Files
Sathira Sri Sathara f920ca8920
CI / test (push) Successful in 10m22s
CI / test (pull_request) Successful in 10m53s
feat: Implement Phase 10 support and recommendations features
- Added models for support messages, SLA policies, tickets, ticket events, and ticket links.
- Created routes for help, help admin, newsletter, recommendations, and support for both customer and admin.
- Developed services for help, marketing (newsletter), and recommendations.
- Introduced support service for ticket management, including creation, replies, transitions, and attachments.
- Added validation schemas for support recommendations and ticket management.
- Implemented a cron job for support reconciliation and recommendation cleanup.
- Created migration for new support and recommendation database tables.
- Added unit tests for validation and policy checks related to Phase 10 features.
2026-09-09 16:07:31 +05:30

2 lines
2.0 KiB
JavaScript

const db=require("../../models"),support=require("../../services/support/support.service");const page=req=>({page:Math.max(Number(req.query.page)||1,1),limit:Math.min(Math.max(Number(req.query.limit)||20,1),100)});exports.create=async(req,res,next)=>{try{res.status(201).json({success:true,data:await support.createTicket(req.user,req.body)});}catch(e){next(e);}};exports.list=async(req,res,next)=>{try{const p=page(req),where={customer_user_id:req.user.id,...(req.query.status&&{status:req.query.status}),...(req.query.category&&{category_id:req.query.category})},x=await db.SupportTicket.findAndCountAll({where,order:[["createdAt","DESC"]],limit:p.limit,offset:(p.page-1)*p.limit});res.json({success:true,data:x.rows,pagination:{...p,total:x.count}});}catch(e){next(e);}};exports.detail=async(req,res,next)=>{try{const ticket=await support.ownTicket(req.params.id,req.user.id),[messages,attachments,links,events]=await Promise.all([db.SupportMessage.findAll({where:{ticket_id:ticket.id,visibility:"CUSTOMER_VISIBLE"},order:[["createdAt","ASC"]]}),db.SupportAttachment.findAll({where:{ticket_id:ticket.id,visibility:"CUSTOMER_VISIBLE"}}),db.SupportTicketLink.findAll({where:{ticket_id:ticket.id}}),db.SupportTicketEvent.findAll({where:{ticket_id:ticket.id,type:["TICKET_CREATED","TICKET_ASSIGNED","TICKET_RESOLVED","TICKET_CLOSED","TICKET_REOPENED"]},attributes:{exclude:["metadata"]},order:[["occurred_at","ASC"]]})]);res.json({success:true,data:{ticket,messages,attachments,links,events}});}catch(e){next(e);}};exports.reply=async(req,res,next)=>{try{res.status(201).json({success:true,data:await support.customerReply(req.user,req.params.id,req.body)});}catch(e){next(e);}};exports.close=async(req,res,next)=>{try{await support.ownTicket(req.params.id,req.user.id);res.json({success:true,data:await support.transition(req.params.id,"CLOSED",req.user)});}catch(e){next(e);}};exports.attachment=async(req,res,next)=>{try{res.json({success:true,data:{url:await support.attachmentUrl(req.params.id,req.params.attachmentId,req.user,false)}});}catch(e){next(e);}};