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:
Sathira Sri Sathara
2026-09-03 19:25:13 +05:30
parent fd4e324571
commit 5643d89236
75 changed files with 663 additions and 1 deletions
+64
View File
@@ -0,0 +1,64 @@
# ZUMRI Catalogue API
Catalogue reads use `/api/v1`; `/api` remains compatible. Public endpoints require no authentication. Administrative endpoints require Phase 1 permissions. Examples use placeholders.
## Localization
Locale priority is `?locale=en|si|ta`, `X-Locale`, authenticated profile preference, `Accept-Language`, then English. Missing requested content falls back to English and then the first available translation.
## Public products
- `GET /api/v1/products`
- `GET /api/v1/products/:slug`
- `POST /api/v1/products/:productId/reviews` — authenticated customer
List query parameters: `page`, `limit` (maximum 100), `category`, `brand`, `search`, `minPrice`, `maxPrice`, `featured`, `newArrival`, `locale`, and `sort=newest|price_asc|price_desc|name|featured`. Unsupported sorts return 400. Stock and wholesale availability are intentionally absent.
```json
{"data":[{"id":"<product-id>","slug":"<slug>","name":"<localized-name>","primaryImage":{"url":"<short-lived-url>"},"minPrice":"1000.00","maxPrice":"1200.00","currency":"LKR","featured":false,"newArrival":true}]}
```
Detail returns localized content/SEO, brand, categories, active variants, options, descriptive attributes, signed gallery media, a structured size guide, rating summary, and approved review preview. DRAFT, INACTIVE, ARCHIVED, and HIDDEN products always return 404 publicly.
Review body is `{"rating":5,"title":"<title>","body":"<review>"}`. `status`, `verifiedPurchase`, moderator, and user IDs are rejected. One review per user/product is enforced. Purchase verification defaults false until order integration exists.
## Categories, brands, and collections
- `GET /api/v1/categories` — tree; add `flat=true` for a flat list
- `GET /api/v1/categories/:slug`
- `GET /api/v1/brands`
- `GET /api/v1/brands/:slug`
- `GET /api/v1/collections`
- `GET /api/v1/collections/:slug`
Only active categories/brands and currently scheduled active collections are returned.
## Administrative products
- `GET /api/v1/admin/products` — `catalogue.products.read`
- `POST /api/v1/admin/products` — `catalogue.products.create`
- `GET /api/v1/admin/products/:id` — read permission
- `PATCH /api/v1/admin/products/:id` — `catalogue.products.update`
- `DELETE /api/v1/admin/products/:id` — `catalogue.products.delete`; archives instead of deleting
- `POST /api/v1/admin/products/:productId/variants`
- `PATCH /api/v1/admin/products/:productId/variants/:variantId`
- `POST /api/v1/admin/products/:productId/options`
- `POST /api/v1/admin/products/:productId/media`
- `POST /api/v1/admin/products/:productId/relations`
Product creation atomically persists translations, category joins, variants, and owned Phase 2 uploads. Prices are decimal strings. Publishing requires English content, a brand, an active variant, and primary media. Published slugs are immutable.
## Administrative content
- `POST|PATCH /api/v1/admin/brands[/:id]` — `catalogue.brands.manage`
- `POST|PATCH /api/v1/admin/categories[/:id]` — `catalogue.categories.manage`
- `POST /api/v1/admin/collections` — `catalogue.collections.manage`
- `POST /api/v1/admin/size-guides` — `catalogue.size-guides.manage`
- `GET /api/v1/admin/reviews` — `catalogue.reviews.read`
- `PATCH /api/v1/admin/reviews/:id/status` — `catalogue.reviews.moderate`
Categories cannot parent themselves or form cycles. Referenced categories/brands have no hard-delete API. Collections use deterministic join ordering and publish windows. Size guides accept structured columns/rows, never HTML.
## Media and prices
Media must be an AVAILABLE upload owned by the acting administrator. Linking transfers metadata ownership to the catalogue Product. Public responses contain short-lived signed URLs but never object keys, bucket names, or credentials. `basePrice` and optional `compareAtPrice` are display catalogue prices only; promotions and authoritative shopping pricing are deferred.