5643d89236
- 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.
9 lines
3.0 KiB
JavaScript
9 lines
3.0 KiB
JavaScript
const {z}=require("zod");const wrap=body=>z.object({body:body.strict(),params:z.object({}).passthrough(),query:z.object({}).passthrough()});const id=z.string().min(1).max(160),money=z.string().regex(/^\d+(\.\d{1,2})?$/),date=z.coerce.date();
|
|
exports.adjustment=wrap(z.object({warehouseId:id,variantId:id,quantityDelta:z.number().int().refine(v=>v!==0),reason:z.string().min(1).max(500)}));
|
|
exports.transfer=wrap(z.object({sourceWarehouseId:id,destinationWarehouseId:id,variantId:id,quantity:z.number().int().positive()}));
|
|
exports.warehouse=wrap(z.object({code:z.string().trim().min(1).max(50),name:z.string().min(1).max(150),status:z.enum(["ACTIVE","INACTIVE"]).default("ACTIVE"),isDefault:z.boolean().default(false),timezone:z.string().max(80).optional(),city:z.string().max(100).optional(),countryCode:z.string().length(2).optional()}));
|
|
exports.businessPrice=wrap(z.object({variantId:id,businessTierId:id.optional(),businessCustomerId:id.optional(),currency:z.string().length(3).transform(v=>v.toUpperCase()),price:money,minimumQuantity:z.number().int().positive().default(1),status:z.enum(["ACTIVE","INACTIVE"]).default("ACTIVE"),startsAt:date.optional(),endsAt:date.optional(),tiers:z.array(z.object({minQuantity:z.number().int().positive(),maxQuantity:z.number().int().positive().nullable().optional(),unitPrice:money}).strict()).default([])}).refine(x=>Boolean(x.businessTierId)!==Boolean(x.businessCustomerId),"Exactly one audience required"));
|
|
exports.promotion=wrap(z.object({name:z.string().min(1).max(180),type:z.enum(["PERCENTAGE","FIXED_AMOUNT","FIXED_PRICE"]),status:z.enum(["DRAFT","ACTIVE","INACTIVE","ARCHIVED"]).default("DRAFT"),startsAt:date.optional(),endsAt:date.optional(),priority:z.number().int().default(0),stackable:z.boolean().default(false),discountPercent:money.optional(),discountAmount:money.optional(),fixedPrice:money.optional(),minimumQuantity:z.number().int().positive().optional(),targets:z.array(z.object({type:z.enum(["ALL","PRODUCT","VARIANT","CATEGORY","BRAND","COLLECTION"]),id:id.nullable().optional()}).strict()).default([{type:"ALL"}])}));
|
|
exports.coupon=wrap(z.object({code:z.string().trim().min(1).max(50).regex(/^[A-Za-z0-9_-]+$/).transform(v=>v.toUpperCase()),promotionId:id,status:z.enum(["ACTIVE","INACTIVE","ARCHIVED"]).default("ACTIVE"),startsAt:date.optional(),expiresAt:date.optional()}));
|
|
exports.banner=wrap(z.object({placement:z.string().trim().min(1).max(80),status:z.enum(["DRAFT","ACTIVE","INACTIVE","ARCHIVED"]).default("DRAFT"),startsAt:date.optional(),endsAt:date.optional(),imageUploadId:z.number().int().positive(),mobileImageUploadId:z.number().int().positive().optional(),targetUrl:z.string().url().optional(),audienceType:z.enum(["ALL","CUSTOMER","BUSINESS_CUSTOMER"]).default("ALL"),businessTierId:id.optional(),sortOrder:z.number().int().default(0),translations:z.array(z.object({locale:z.enum(["en","si","ta"]),headline:z.string().max(180).optional(),subheadline:z.string().max(500).optional(),ctaText:z.string().max(80).optional(),altText:z.string().max(255).optional()}).strict()).min(1)}));
|