Files
Sathira Sri Sathara ad9287b804
CI / test (push) Has been cancelled
CI / test (pull_request) Has been cancelled
feat: Implement Phase 6 Shopping and Checkout
- Introduced authenticated shopping state and atomic checkout process without creating orders or payments.
- Reused existing components from previous phases including identities, addresses, catalogues, pricing, and inventory.
- Developed cart architecture to support one active cart per user with unique items per variant.
- Implemented dynamic cart pricing with various precedence rules for promotions and coupons.
- Created a wishlist feature that exposes only visible active products without reserving inventory.
- Integrated inventory validation to ensure availability of items before adding to cart.
- Developed a checkout architecture that locks the cart, revalidates pricing and shipping, and reserves inventory.
- Added shipping zones, methods, and rates with configurable options for international shipping and duty/tax boundaries.
- Implemented checkout snapshots to capture immutable checkout details.
- Introduced idempotency for checkout requests to prevent duplicate processing.
- Added functionality for coupon integration and business checkout validation.
- Established permissions for managing shipping zones, methods, and rates.
- Created comprehensive unit tests covering various aspects of the shopping and checkout processes.
- Added cron job for handling checkout expiry reconciliation.
- Created migration script to set up new database tables and constraints for carts, checkout sessions, and shipping.
2026-09-03 23:45:01 +05:30

2 lines
1.9 KiB
JavaScript

const{z}=require("zod"),wrap=body=>z.object({body:body.strict(),params:z.object({}).passthrough(),query:z.object({}).passthrough()}),id=z.string().min(1).max(160),money=z.string().regex(/^\d+(\.\d{1,2})?$/),date=z.coerce.date();exports.cartItem=wrap(z.object({variantId:id,quantity:z.number().int().positive().max(Number(process.env.CART_MAX_ITEM_QUANTITY||100))}));exports.cartQuantity=wrap(z.object({quantity:z.number().int().min(0).max(Number(process.env.CART_MAX_ITEM_QUANTITY||100))}));exports.coupon=wrap(z.object({code:z.string().trim().min(1).max(50).regex(/^[A-Za-z0-9_-]+$/).transform(x=>x.toUpperCase())}));exports.wishlist=wrap(z.object({productId:id}));exports.checkout=wrap(z.object({shippingAddressId:id,billingAddressId:id,shippingMethodId:id,couponCode:z.string().trim().max(50).optional()}));exports.shippingQuote=wrap(z.object({addressId:id}));exports.zone=wrap(z.object({code:z.string().min(1).max(60),name:z.string().min(1).max(150),status:z.enum(["ACTIVE","INACTIVE"]).default("ACTIVE"),dutyMode:z.enum(["NONE","ESTIMATED","PAYABLE_ON_DELIVERY","INCLUDED","UNKNOWN"]).default("UNKNOWN"),regions:z.array(z.object({countryCode:z.string().length(2),province:z.string().max(100).optional(),district:z.string().max(100).optional()}).strict()).min(1)}));exports.method=wrap(z.object({code:z.string().min(1).max(60),name:z.string().min(1).max(150),description:z.string().optional(),status:z.enum(["ACTIVE","INACTIVE"]).default("ACTIVE"),estimatedMinDays:z.number().int().nonnegative(),estimatedMaxDays:z.number().int().nonnegative(),trackingSupported:z.boolean().default(false)}));exports.rate=wrap(z.object({shippingZoneId:id,shippingMethodId:id,currency:z.string().length(3),baseAmount:money,freeShippingThreshold:money.optional(),minimumSubtotal:money.optional(),maximumSubtotal:money.optional(),status:z.enum(["ACTIVE","INACTIVE"]).default("ACTIVE"),startsAt:date.optional(),endsAt:date.optional()}));