# Sales Module Plan ## Summary This sales module is split into two phases: - **Phase 1**: basic, standard sales features that fit the current ERP architecture - **Phase 2**: enterprise extensions that can be added after the core flow is stable The design stays aligned with the existing backend patterns: - controller thinness - service-based business rules - repository + unit of work - ETag concurrency - audit logging - stock FIFO and ledger posting Returns, credit notes, and sales returns are **out of scope for Phase 1**. --- ## Phase 1 - Basic Standard Sales Module ### Goal Implement the minimum sales flow needed for both B2B and B2C: - maintain customers - create sales invoices - create sales slips - support fixed sale price fallback and GRN-based cost fallback - support discounts by percentage and value - support free issue lines - post stock movement and ledger entries - generate basic sales reports ### In Scope - Customer master - Sales invoice - Sales invoice lines - Sales slip - Sales slip lines - Pricing resolver - Discount calculation - Free issue handling - Stock posting - Basic sales reports ### Not in Scope for Phase 1 - customer groups - price lists - promotions - reservations - sales payments allocation - approval workflow - returns and credit notes - advanced customer segmentation ### Phase 1 Entity Design #### `Customer` Basic customer master used for both B2B and B2C. Fields: - `CustomerId` - `CustomerCode` - `CustomerType` (`B2B`, `B2C`, `WalkIn`) - `Name` - `DisplayName` - `Phone` - `Email` - `AddressLine1` - `AddressLine2` - `City` - `Country` - `TaxRegistrationNo` - `CreditLimit` - `CreditDays` - `DefaultWarehouseId` - `Status` - `CreatedAt` - `UpdatedAt` - `RowVersion` #### `SalesInvoice` Primary posted sales document. Fields: - `SalesInvoiceId` - `InvoiceNo` - `InvoiceDate` - `CustomerId` - `CustomerSnapshotName` - `CustomerSnapshotTaxNo` - `WarehouseId` - `InvoiceType` (`B2B`, `B2C`, `Cash`, `Credit`) - `Status` (`Draft`, `Posted`, `Cancelled`) - `Subtotal` - `DiscountTotal` - `TaxTotal` - `GrandTotal` - `RoundOff` - `NetPayable` - `PaidAmount` - `BalanceAmount` - `CreatedBy` - `CreatedAt` - `UpdatedAt` - `RowVersion` #### `SalesInvoiceLine` Invoice line with pricing, discount, and free issue support. Fields: - `SalesInvoiceLineId` - `SalesInvoiceId` - `ItemId` - `Description` - `Qty` - `FreeQty` - `UomId` - `WarehouseId` - `UnitPrice` - `BaseCost` - `PriceSource` - `DiscountPct` - `DiscountAmount` - `NetUnitPrice` - `LineTotal` - `TaxPct` - `TaxAmount` - `IsFreeIssue` - `ParentLineId` - `RowVersion` #### `SalesSlip` Fast retail or counter-sale document. Fields: - `SalesSlipId` - `SlipNo` - `SlipDate` - `CustomerId` - `CustomerSnapshotName` - `WarehouseId` - `CashierUserId` - `Status` - `Subtotal` - `DiscountTotal` - `TaxTotal` - `GrandTotal` - `PaidAmount` - `BalanceAmount` - `CreatedAt` - `UpdatedAt` - `RowVersion` #### `SalesSlipLine` Slip line with the same sales calculation rules as invoices. Fields: - `SalesSlipLineId` - `SalesSlipId` - `ItemId` - `Description` - `Qty` - `FreeQty` - `UomId` - `WarehouseId` - `UnitPrice` - `BaseCost` - `PriceSource` - `DiscountPct` - `DiscountAmount` - `NetUnitPrice` - `LineTotal` - `TaxPct` - `TaxAmount` - `IsFreeIssue` - `ParentLineId` - `RowVersion` ### Phase 1 Pricing Rule Use the following order: 1. fixed `Item.SalePrice` 2. GRN-derived stock cost fallback 3. FIFO valuation fallback Important: - use a weighted average when deriving from multiple GRNs - keep the resolved source in `PriceSource` - allow manual override only if permitted by business rule ### Phase 1 Discount Rule Support: - percentage discount - fixed value discount Discount must be computed server-side and stored in line and document totals. ### Phase 1 Free Issue Rule Support free issue lines in the same invoice/slip document. Rules: - free quantity must be separate from paid quantity - free issue still reduces stock - free issue must be visible in reports - free issue should not be merged into discount ### Phase 1 Stock Posting Rule When an invoice or slip is posted: - reduce stock from the selected warehouse - consume FIFO layers - write `StockLedger` rows - maintain source document traceability - update totals in the same transaction ### Phase 1 API Route List - `GET /api/v1/customers` - `GET /api/v1/customers/{id}` - `POST /api/v1/customers` - `PUT /api/v1/customers/{id}` - `PATCH /api/v1/customers/{id}/status` - `GET /api/v1/sales-invoices` - `GET /api/v1/sales-invoices/{id}` - `POST /api/v1/sales-invoices` - `PUT /api/v1/sales-invoices/{id}` - `POST /api/v1/sales-invoices/{id}/post` - `POST /api/v1/sales-invoices/{id}/cancel` - `GET /api/v1/sales-invoices/{id}/print-preview` - `GET /api/v1/sales-slips` - `GET /api/v1/sales-slips/{id}` - `POST /api/v1/sales-slips` - `POST /api/v1/sales-slips/{id}/post` - `POST /api/v1/sales-slips/{id}/cancel` - `GET /api/v1/free-issues` - `GET /api/v1/free-issues/{id}` - `POST /api/v1/free-issues` - `PUT /api/v1/free-issues/{id}` - `POST /api/v1/free-issues/{id}/post` - `POST /api/v1/free-issues/{id}/cancel` - `GET /api/v1/reports/sales` - `GET /api/v1/reports/sales/{reportId}` - `POST /api/v1/reports/sales/query` ### Phase 1 Folder / Module Plan - `Domain/Entities` - add `Customer`, `SalesInvoice`, `SalesInvoiceLine`, `SalesSlip`, `SalesSlipLine` - `Domain/Enums` - add sales status enums and invoice/slip type enums - `Dtos/Sales` - add request and response DTOs for customer, invoice, slip, and reports - `Services/Interfaces` - add `ICustomerService`, `ISalesInvoiceService`, `ISalesSlipService`, `ISalesPricingService`, `ISalesReportService` - `Services` - implement the sales services with transaction-safe logic - `Controllers` - add `CustomersController`, `SalesInvoicesController`, `SalesSlipsController`, `SalesReportsController` - `Infra/Persistence/Configurations` - add EF Core mappings for all sales entities - `Infra/Persistence/ErpDbContext.cs` - register sales `DbSet`s - `Infra/Persistence/Migrations` - add the sales schema migration after the model is defined ### Phase 1 Implementation Order 1. Customer master 2. Sales invoice entity and DTOs 3. Sales slip entity and DTOs 4. Pricing resolver 5. Discount computation 6. Free issue handling 7. Stock posting 8. Basic sales reports 9. Controllers and swagger wiring --- ## Phase 2 - Enterprise Extensions ### Goal Add richer commercial features after Phase 1 is stable and tested. ### In Scope - customer groups - price lists - promotions - free issue schemes - reservations - payment allocation - approval flow - advanced reporting dimensions ### Phase 2 Entity Additions #### `CustomerGroup` Used only if group-level pricing or segmentation is needed. #### `PriceList` Customer, group, warehouse, or global price policies. #### `PriceListItem` Per-item pricing rows inside a price list. #### `Promotion` Promotional header. #### `PromotionRule` Buy-X-get-Y, discount, or reward rules. #### `FreeIssueScheme` Separate free issue header. #### `FreeIssueSchemeLine` Rule lines for free issue behavior. #### `SalesReservation` Stock reservation header for B2B order fulfillment. #### `SalesReservationLine` Reserved item quantities. #### `SalesPayment` Payment header for cash or credit settlement. #### `SalesPaymentAllocation` Allocation of a payment across invoices. ### Phase 2 API Routes - `GET /api/v1/customer-groups` - `POST /api/v1/customer-groups` - `PUT /api/v1/customer-groups/{id}` - `PATCH /api/v1/customer-groups/{id}/status` - `GET /api/v1/price-lists` - `POST /api/v1/price-lists` - `PUT /api/v1/price-lists/{id}` - `PATCH /api/v1/price-lists/{id}/status` - `GET /api/v1/price-lists/{id}/items` - `PUT /api/v1/price-lists/{id}/items` - `GET /api/v1/pricing/resolve` - `GET /api/v1/promotions` - `POST /api/v1/promotions` - `PUT /api/v1/promotions/{id}` - `PATCH /api/v1/promotions/{id}/status` - `GET /api/v1/free-issue-schemes` - `POST /api/v1/free-issue-schemes` - `PUT /api/v1/free-issue-schemes/{id}` - `PATCH /api/v1/free-issue-schemes/{id}/status` - `POST /api/v1/sales-orders` - `POST /api/v1/sales-orders/{id}/reserve` - `POST /api/v1/sales-orders/{id}/confirm` - `POST /api/v1/sales-payments` - `POST /api/v1/sales-payments/{id}/allocate` - extended reporting routes for channel, cashier, tax, and credit views ### Phase 2 Folder / Module Plan - extend the same sales folders rather than creating a separate module - add new entities and DTOs under the same sales namespace - add new service interfaces and service implementations next to Phase 1 sales services - add new controllers only for the advanced routes - add migrations incrementally so Phase 1 tables remain stable ### Phase 2 Implementation Order 1. customer groups 2. price lists 3. promotions and free issue schemes 4. sales orders and reservations 5. payments and allocations 6. advanced reports 7. permissions and approval workflow --- ## Test Plan - Verify customer CRUD with ETag concurrency and status changes. - Verify invoice and slip create/update/post flows. - Verify fixed sale price fallback works. - Verify GRN-derived fallback uses weighted average. - Verify discounts calculate correctly by percentage and fixed value. - Verify free issue lines post stock and appear in reports. - Verify stock ledger entries are created once per posted document. - Verify Phase 1 routes remain stable before Phase 2 is added. ## Assumptions - Phase 1 is intentionally minimal and should not include customer groups or price lists. - `SalesInvoice` is the primary posted sales document. - `SalesSlip` is a simplified retail document. - Returns are deferred to a later step. - Existing ERP patterns must be preserved: repository, unit of work, audit, ETag, and FIFO stock posting.