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,6 @@
|
||||
const {z}=require("zod");const req=(body)=>z.object({body:z.object(body).strict(),params:z.object({}).passthrough(),query:z.object({}).passthrough()});const id=z.string().min(1).max(100);const slug=z.string().trim().toLowerCase().regex(/^[a-z0-9]+(?:-[a-z0-9]+)*$/).max(200);const money=z.string().regex(/^\d{1,13}(?:\.\d{1,2})?$/);const locale=z.enum(["en","si","ta"]);const translation=z.object({locale,name:z.string().trim().min(1).max(220),shortDescription:z.string().trim().max(500).optional(),description:z.string().trim().max(20000).optional(),careInstructions:z.string().trim().max(5000).optional(),materials:z.string().trim().max(2000).optional(),origin:z.string().trim().max(120).optional(),metaTitle:z.string().trim().max(180).optional(),metaDescription:z.string().trim().max(320).optional()}).strict();
|
||||
const variant=z.object({sku:z.string().trim().regex(/^[A-Za-z0-9._-]+$/).max(100),barcode:z.string().trim().max(100).optional(),basePrice:money,compareAtPrice:money.optional().nullable(),currency:z.string().length(3).transform(v=>v.toUpperCase()).default("LKR"),weight:z.string().regex(/^\d+(?:\.\d{1,3})?$/).optional(),sortOrder:z.number().int().min(0).default(0)}).strict();
|
||||
module.exports={slug,money,locale,productCreate:req({brandId:id,defaultCategoryId:id.optional(),slug,productCode:z.string().trim().min(1).max(100),productType:z.string().trim().max(80).default("STANDARD"),featured:z.boolean().default(false),newArrivalUntil:z.coerce.date().optional().nullable(),translations:z.array(translation).min(1),categoryIds:z.array(id).min(1),variants:z.array(variant).min(1),mediaUploadIds:z.array(z.number().int().positive()).default([])}),productUpdate:req({brandId:id.optional(),defaultCategoryId:id.optional().nullable(),slug:slug.optional(),productType:z.string().trim().max(80).optional(),featured:z.boolean().optional(),newArrivalUntil:z.coerce.date().optional().nullable(),status:z.enum(["DRAFT","ACTIVE","INACTIVE","ARCHIVED"]).optional(),visibility:z.enum(["PUBLIC","HIDDEN"]).optional()}),variantCreate:req(variant.shape),variantUpdate:req({status:z.enum(["ACTIVE","INACTIVE"]).optional(),basePrice:money.optional(),compareAtPrice:money.optional().nullable(),currency:z.string().length(3).transform(v=>v.toUpperCase()).optional(),weight:z.string().regex(/^\d+(?:\.\d{1,3})?$/).optional(),sortOrder:z.number().int().min(0).optional(),optionValueIds:z.array(id).optional()}),brand:req({name:z.string().trim().min(1).max(160),slug,description:z.string().trim().max(5000).optional(),logoUploadId:z.number().int().positive().optional().nullable(),website:z.string().url().optional().nullable(),status:z.enum(["ACTIVE","INACTIVE"]).default("INACTIVE"),sortOrder:z.number().int().min(0).default(0)}),category:req({parentId:id.optional().nullable(),code:z.string().trim().regex(/^[A-Za-z0-9_-]+$/).max(80),slug,status:z.enum(["ACTIVE","INACTIVE"]).default("INACTIVE"),sortOrder:z.number().int().min(0).default(0),imageUploadId:z.number().int().positive().optional().nullable(),translations:z.array(translation.pick({locale:true,name:true,description:true,metaTitle:true,metaDescription:true})).min(1)}),collection:req({slug,type:z.string().trim().min(1).max(80),status:z.enum(["DRAFT","ACTIVE","INACTIVE"]).default("DRAFT"),startsAt:z.coerce.date().optional().nullable(),endsAt:z.coerce.date().optional().nullable(),heroUploadId:z.number().int().positive().optional().nullable(),sortOrder:z.number().int().min(0).default(0),translations:z.array(z.object({locale,name:z.string().trim().min(1).max(180),description:z.string().max(10000).optional(),headline:z.string().max(250).optional(),subheadline:z.string().max(300).optional()}).strict()).min(1),productIds:z.array(id).default([])}),review:req({rating:z.number().int().min(1).max(5),title:z.string().trim().min(1).max(160),body:z.string().trim().min(3).max(5000)}),reviewStatus:req({status:z.enum(["APPROVED","REJECTED"])}),sizeGuide:req({code:z.string().trim().regex(/^[A-Za-z0-9_-]+$/).max(80),name:z.string().trim().min(1).max(160),locale,data:z.object({columns:z.array(z.string().max(80)).min(1).max(20),rows:z.array(z.array(z.string().max(100)).max(20)).max(100)}).strict(),categoryId:id.optional().nullable(),status:z.enum(["ACTIVE","INACTIVE"]).default("ACTIVE")})};
|
||||
module.exports.option=req({name:z.string().trim().min(1).max(100),values:z.array(z.string().trim().min(1).max(100)).min(1),sortOrder:z.number().int().min(0).default(0)});
|
||||
module.exports.media=req({uploadId:z.number().int().positive(),variantId:id.optional().nullable(),altText:z.string().trim().max(250).optional(),isPrimary:z.boolean().default(false),sortOrder:z.number().int().min(0).default(0)});
|
||||
module.exports.relation=req({targetProductId:id,relationType:z.enum(["RELATED","SIMILAR","COMPLETE_THE_LOOK"]),sortOrder:z.number().int().min(0).default(0)});
|
||||
Reference in New Issue
Block a user