feat: implement business pricing service and money utilities
- Added `businessPricing.service.js` to handle business customer pricing logic. - Introduced `money.js` for money parsing, formatting, and calculations. - Created `pricing.service.js` to manage variant quoting and promotion application. - Updated validation schemas in `catalogue.schemas.js` and `inventoryMerchandising.schemas.js` for new pricing and inventory features. - Implemented cron job for inventory reservation expiry in `inventoryReservationExpiry.cron.js`. - Created database migrations for catalogue and inventory structures. - Added unit tests for catalogue localization, validation, and inventory merchandising functionalities.
This commit is contained in:
@@ -0,0 +1,42 @@
|
||||
# Inventory and Merchandising API
|
||||
|
||||
All routes use the `/api/v1` prefix. Admin routes require authentication and the named Phase 5 permission.
|
||||
|
||||
## Inventory and warehouses
|
||||
|
||||
- `GET /admin/inventory` (`inventory.read`)
|
||||
- `GET /admin/inventory/:variantId` (`inventory.read`)
|
||||
- `GET /admin/inventory/ledger` (`inventory.read`)
|
||||
- `GET /admin/inventory/low-stock` (`inventory.read`)
|
||||
- `POST /admin/inventory/adjustments` (`inventory.adjust`); send `Idempotency-Key`
|
||||
- `POST /admin/inventory/transfers` (`inventory.transfer`); send `Idempotency-Key`
|
||||
- `GET /admin/warehouses` (`inventory.read`)
|
||||
- `POST /admin/warehouses`, `PATCH /admin/warehouses/:id` (`inventory.warehouses.manage`)
|
||||
- `GET /availability/:variantId` returns only `IN_STOCK`, `LOW_STOCK`, or `OUT_OF_STOCK` and `availableForSale`; it never exposes warehouse quantities.
|
||||
|
||||
Inventory mutations are internal service operations: `reserveStock`, `releaseReservation`, and `consumeReservation`. Reservations default to `INVENTORY_RESERVATION_TTL_MINUTES=15`. The minute reconciliation job expires bounded batches of 100; the database remains authoritative.
|
||||
|
||||
## Business pricing
|
||||
|
||||
- `GET /admin/business-pricing` (`pricing.business.read`)
|
||||
- `POST /admin/business-pricing` (`pricing.business.manage`)
|
||||
|
||||
Rules support exactly one tier or customer audience, effective dates, MOQ, and non-overlapping volume ranges. Precedence is customer override, business tier, then retail. Money is stored as DECIMAL and calculated using integer-scaled helpers.
|
||||
|
||||
## Promotions and coupons
|
||||
|
||||
- `GET|POST /admin/promotions` (`promotions.read` / `promotions.manage`)
|
||||
- `GET|POST /admin/coupons` (`promotions.read` / `promotions.manage`)
|
||||
|
||||
The quote boundary resolves retail/business base price, then the highest-priority eligible automatic promotion, then a coupon only when stacking permits. Discounts floor at zero. Coupon codes are canonical uppercase. Usage redemption is intentionally deferred until orders exist.
|
||||
|
||||
## Banners
|
||||
|
||||
- `GET /banners?placement=&locale=` returns active, scheduled, audience-eligible localized banners.
|
||||
- `GET|POST /admin/banners` requires `merchandising.banners.manage`.
|
||||
|
||||
Banner media reuses Upload records and only returns safe upload identifiers, never bucket/object keys.
|
||||
|
||||
## Not implemented
|
||||
|
||||
Cart, checkout, orders, coupon redemption, shipping, tax, payment, and delivery remain outside Phase 5.
|
||||
Reference in New Issue
Block a user