# 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.
