feat: Implement loyalty and wholesale services with models, routes, and validation
CI / test (push) Successful in 10m23s
CI / test (push) Successful in 10m23s
- Added models for loyalty points allocation, redemption, rewards, tiers, tier history, and referrals. - Created business credit ledger entries, settlements, and settlement items models. - Developed services for loyalty operations including account management, point allocation, redemption, and referral handling. - Implemented wholesale credit management services for transactions and settlements. - Established routes for loyalty and wholesale admin and customer operations with appropriate middleware for authentication and permission checks. - Introduced validation schemas for loyalty and wholesale operations. - Set up cron jobs for loyalty reconciliation tasks such as birthday rewards and point expirations. - Created migration scripts to set up the database schema for loyalty and wholesale features. - Added unit tests for validation and policy enforcement in loyalty and wholesale services.
This commit is contained in:
@@ -0,0 +1 @@
|
||||
const crypto=require("crypto"),db=require("../../models"),loyalty=require("../../services/loyalty/loyalty.service"),{logActivity}=require("../../services/activity.service");const list=model=>async(req,res,next)=>{try{res.json({success:true,data:await model.findAll({order:[["createdAt","DESC"]]})});}catch(e){next(e);}};exports.accounts=list(db.LoyaltyAccount);exports.tiers=list(db.LoyaltyTier);exports.rules=list(db.LoyaltyEarnRule);exports.rewards=list(db.LoyaltyReward);exports.referrals=list(db.Referral);exports.adjust=async(req,res,next)=>{try{const result=await loyalty.post({userId:req.body.userId,eventId:`LOYALTY:ADMIN:${req.get("Idempotency-Key")}`,type:"ADJUSTMENT",sourceType:"ADMIN_ADJUSTMENT",points:req.body.pointsDelta,descriptionCode:req.body.reasonCode,metadata:{note:req.body.note,actorUserId:req.user.id}});await logActivity({user:req.user,type:"LOYALTY_POINTS_ADJUSTED",module:"Loyalty",targetId:result.entry.id,requestId:req.id});res.status(result.idempotent?200:201).json({success:true,data:result.entry});}catch(e){next(e);}};exports.createTier=async(req,res,next)=>{try{const b=req.body,row=await db.LoyaltyTier.create({id:crypto.randomUUID(),code:b.code.toUpperCase(),name:b.name,status:b.status,rank:b.rank,qualification_threshold:b.qualificationThreshold,qualification_metric:"LIFETIME_POINTS",benefits_json:b.benefits,sort_order:b.sortOrder});res.status(201).json({success:true,data:row});}catch(e){next(e);}};exports.createRule=async(req,res,next)=>{try{const b=req.body,row=await db.LoyaltyEarnRule.create({id:crypto.randomUUID(),source_type:b.sourceType,status:b.status,points_per_amount:b.pointsPerAmount,amount_unit:b.amountUnit,fixed_points:b.fixedPoints,minimum_amount:b.minimumAmount,maximum_points:b.maximumPoints,expiry_days:b.expiryDays,effective_from:b.effectiveFrom,effective_to:b.effectiveTo});res.status(201).json({success:true,data:row});}catch(e){next(e);}};exports.createReward=async(req,res,next)=>{try{const b=req.body,row=await db.LoyaltyReward.create({id:crypto.randomUUID(),code:b.code.toUpperCase(),name:b.name,description:b.description,type:b.type,points_cost:b.pointsCost,status:b.status,starts_at:b.startsAt,ends_at:b.endsAt,stock_limit:b.stockLimit,per_user_limit:b.perUserLimit,configuration:b.configuration});res.status(201).json({success:true,data:row});}catch(e){next(e);}};
|
||||
Reference in New Issue
Block a user