Add bundle sales backend implementation
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
# 14 · BACKEND — Sales API Reference
|
||||
|
||||
> **Authoritative for:** sales API contracts for invoices, slips, free issues, and sales reports.
|
||||
> **Authoritative for:** sales API contracts for invoices, slips, bundle sales, free issues, and sales reports.
|
||||
> **Navigation:** start from `00-CORE.md`. Sales business rules live in `docs/SALES_MODULE_PLAN.md` and the sales-related backend progress is tracked in `Backend/PROGRESS.md`.
|
||||
> **Scope:** this document covers the sales endpoints currently implemented in ERPCore. Free issue is modeled as a sales-slip alias, not a separate table.
|
||||
|
||||
@@ -132,9 +132,62 @@ Before posting, the UI calls `GET /api/v1/sales-slips/{salesSlipId}/posting-chec
|
||||
### `POST /api/v1/sales-slips/{salesSlipId}/cancel`
|
||||
Cancels a draft slip.
|
||||
|
||||
---
|
||||
|
||||
## 4. Bundle Sales
|
||||
|
||||
Bundle sales are a separate sales document family for fixed bundle compositions.
|
||||
|
||||
### `GET /api/v1/bundle-sales`
|
||||
Query:
|
||||
- `page`
|
||||
- `pageSize`
|
||||
- `q`
|
||||
- `customerId`
|
||||
- `warehouseId`
|
||||
|
||||
Returns a paged list of `BundleSaleSummaryDto`.
|
||||
|
||||
### `GET /api/v1/bundle-sales/{bundleSaleId}`
|
||||
Returns `BundleSaleDto`.
|
||||
|
||||
### `GET /api/v1/bundle-sales/{bundleSaleId}/posting-check`
|
||||
Validates component stock before posting.
|
||||
|
||||
### `POST /api/v1/bundle-sales`
|
||||
Creates a draft bundle sale from a fixed template.
|
||||
|
||||
Request:
|
||||
```json
|
||||
{
|
||||
"customerId": 2,
|
||||
"warehouseId": 1,
|
||||
"cashierUserId": 1,
|
||||
"bundleSaleTemplateId": 1,
|
||||
"bundleName": "Summer Promo Pack",
|
||||
"bundleCode": "BND-001",
|
||||
"bundlePrice": 2500,
|
||||
"allowPriceOverride": true
|
||||
}
|
||||
```
|
||||
|
||||
### `PUT /api/v1/bundle-sales/{bundleSaleId}`
|
||||
Updates a draft bundle sale. Requires `If-Match`.
|
||||
|
||||
### `POST /api/v1/bundle-sales/{bundleSaleId}/post`
|
||||
Posts the bundle and consumes stock from the included component lines.
|
||||
|
||||
### `POST /api/v1/bundle-sales/{bundleSaleId}/cancel`
|
||||
Cancels a draft bundle sale.
|
||||
|
||||
Business rule:
|
||||
- bundle composition is fixed by template lines
|
||||
- posting consumes component stock, not a synthetic bundle stock item
|
||||
- print pages should show both the bundle summary and the component breakdown
|
||||
|
||||
---
|
||||
|
||||
## 4. Free Issues
|
||||
## 5. Free Issues
|
||||
|
||||
Free issue is a business alias over sales slips.
|
||||
There is no separate free-issue table in the current schema.
|
||||
@@ -165,7 +218,7 @@ Business rule:
|
||||
|
||||
---
|
||||
|
||||
## 5. Sales Reports
|
||||
## 6. Sales Reports
|
||||
|
||||
### `GET /api/v1/reports/sales`
|
||||
Returns the report catalog.
|
||||
@@ -217,8 +270,9 @@ Validation rule:
|
||||
|
||||
---
|
||||
|
||||
## 6. Notes
|
||||
## 7. Notes
|
||||
|
||||
- The sales report service reads both invoices and slips where relevant.
|
||||
- Free issue reporting is derived from the same sales document lines.
|
||||
- Bundle sales are treated as a separate fixed-composition document family.
|
||||
- There is no separate free-issue table in the current schema.
|
||||
|
||||
@@ -0,0 +1,136 @@
|
||||
# 15 · BACKEND — Bundle Sales API
|
||||
|
||||
> **Authoritative for:** fixed-composition bundle sales, templates, posting, and print data.
|
||||
> **Navigation:** start from `00-CORE.md`. This module follows the same repository/UoW/ETag/audit patterns as invoices and slips.
|
||||
|
||||
---
|
||||
|
||||
## 1. Concept
|
||||
|
||||
Bundle sales are a separate sales document family for fixed bundle compositions.
|
||||
|
||||
Rules:
|
||||
- a bundle sale is created from a bundle template
|
||||
- the bundle template defines fixed component stock lines
|
||||
- posting consumes stock from the component items, not from a synthetic bundle SKU
|
||||
- the bundle header carries the commercial sale value
|
||||
- print views show both bundle summary and component breakdown
|
||||
|
||||
---
|
||||
|
||||
## 2. API
|
||||
|
||||
### `GET /api/v1/bundle-sales`
|
||||
Query:
|
||||
- `page`
|
||||
- `pageSize`
|
||||
- `q`
|
||||
- `customerId`
|
||||
- `warehouseId`
|
||||
|
||||
### `GET /api/v1/bundle-sales/{bundleSaleId}`
|
||||
Returns the bundle sale header and all component lines.
|
||||
|
||||
### `GET /api/v1/bundle-sales/{bundleSaleId}/posting-check`
|
||||
Validates component stock before posting.
|
||||
|
||||
### `POST /api/v1/bundle-sales`
|
||||
Creates a draft bundle sale from a fixed bundle template.
|
||||
|
||||
### `PUT /api/v1/bundle-sales/{bundleSaleId}`
|
||||
Updates a draft bundle sale. Requires `If-Match`.
|
||||
|
||||
### `POST /api/v1/bundle-sales/{bundleSaleId}/post`
|
||||
Consumes stock from included component lines and marks the bundle as posted.
|
||||
|
||||
### `POST /api/v1/bundle-sales/{bundleSaleId}/cancel`
|
||||
Cancels a draft bundle sale.
|
||||
|
||||
---
|
||||
|
||||
## 3. Template Rules
|
||||
|
||||
- bundle templates are fixed in composition
|
||||
- each template line maps to one component stock item
|
||||
- component quantities are expanded into the sale draft at creation time
|
||||
- price override is allowed only when the caller is permitted by business rules
|
||||
|
||||
---
|
||||
|
||||
## 4. Data Model
|
||||
|
||||
### `BundleSaleTemplate`
|
||||
- `BundleSaleTemplateId`
|
||||
- `TemplateCode`
|
||||
- `TemplateName`
|
||||
- `Description`
|
||||
- `Status`
|
||||
- `CreatedAt`
|
||||
- `UpdatedAt`
|
||||
- `RowVersion`
|
||||
|
||||
### `BundleSaleTemplateLine`
|
||||
- `BundleSaleTemplateLineId`
|
||||
- `BundleSaleTemplateId`
|
||||
- `ItemId`
|
||||
- `UomId`
|
||||
- `WarehouseId`
|
||||
- `Qty`
|
||||
- `UnitPrice`
|
||||
- `IncludeInBundle`
|
||||
- `SortOrder`
|
||||
|
||||
### `BundleSale`
|
||||
- `BundleSaleId`
|
||||
- `BundleNo`
|
||||
- `BundleDate`
|
||||
- `CustomerId`
|
||||
- `CustomerSnapshotName`
|
||||
- `WarehouseId`
|
||||
- `CashierUserId`
|
||||
- `BundleSaleTemplateId`
|
||||
- `BundleName`
|
||||
- `BundleCode`
|
||||
- `Status`
|
||||
- `ComponentSubtotal`
|
||||
- `BundlePrice`
|
||||
- `MarginAmount`
|
||||
- `DiscountTotal`
|
||||
- `TaxTotal`
|
||||
- `GrandTotal`
|
||||
- `CreatedAt`
|
||||
- `UpdatedAt`
|
||||
- `RowVersion`
|
||||
|
||||
### `BundleSaleLine`
|
||||
- `BundleSaleLineId`
|
||||
- `BundleSaleId`
|
||||
- `ItemId`
|
||||
- `Description`
|
||||
- `Qty`
|
||||
- `UomId`
|
||||
- `WarehouseId`
|
||||
- `UnitPrice`
|
||||
- `LineTotal`
|
||||
- `IncludeInBundle`
|
||||
- `IsComponent`
|
||||
- `ParentLineId`
|
||||
- `RowVersion`
|
||||
|
||||
---
|
||||
|
||||
## 5. Posting
|
||||
|
||||
Posting behavior:
|
||||
- validate each included component line has sufficient stock
|
||||
- consume FIFO layers from the component items
|
||||
- write stock ledger rows for each component
|
||||
- mark the bundle as posted in the same transaction
|
||||
|
||||
---
|
||||
|
||||
## 6. Notes
|
||||
|
||||
- This module is intentionally separate from invoices and slips.
|
||||
- Bundle sales are for fixed compositions only in this phase.
|
||||
- Print views should mirror the existing sales document print behavior without the dashboard shell.
|
||||
@@ -282,6 +282,8 @@ Add richer commercial features after Phase 1 is stable and tested.
|
||||
- price lists
|
||||
- promotions
|
||||
- free issue schemes
|
||||
- bundle sales templates
|
||||
- bundle sales documents
|
||||
- reservations
|
||||
- payment allocation
|
||||
- approval flow
|
||||
@@ -304,6 +306,18 @@ Promotional header.
|
||||
#### `PromotionRule`
|
||||
Buy-X-get-Y, discount, or reward rules.
|
||||
|
||||
#### `BundleSaleTemplate`
|
||||
Fixed bundle composition definition.
|
||||
|
||||
#### `BundleSaleTemplateLine`
|
||||
Component stock items and quantities inside a bundle template.
|
||||
|
||||
#### `BundleSale`
|
||||
Posted or draft bundle sale header.
|
||||
|
||||
#### `BundleSaleLine`
|
||||
Component lines expanded from a bundle template.
|
||||
|
||||
#### `FreeIssueScheme`
|
||||
Separate free issue header.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user