import { createPartner, getPartnerById, getPartnerByQuery, getPartnersByQuery, getAllPartners, updatePartner, aggregatePartner, } from "../models/Partner/operations"; import { aggregateAccess } from "../models/Access/operations"; import { createApproval, updateApproval, aggregateApproval, } from "../models/Approval/operations"; import dayjs from "dayjs"; import { ObjectId } from "mongodb"; export const createPartnerController = async (req, res) => { try { const { user } = res.locals; const accessRole = await aggregateAccess([ { $match: { user: ObjectId.createFromHexString(user.id), }, }, { $lookup: { from: "roles", localField: "role", foreignField: "_id", as: "role", }, }, { $unwind: { path: "$role", preserveNullAndEmptyArrays: true, }, }, ]); console.log("ACCESS ROLE", accessRole[0]?.role?.modules); const isAutoApproved = accessRole[0]?.role?.modules?.some( ({ module, permission }) => { return module === "partner" && permission === "authorize"; }, ); const partnerPayload = { ...req.body, createdBy: user.id, createdOn: dayjs().toISOString(), temp: true, isApproved: isAutoApproved, }; const approvalPayload = { entity: partner.id, type: "partner", createdBy: user.id, createdOn: dayjs().toISOString(), }; if (isAutoApproved) { approvalPayload.approvedBy = user.id; approvalPayload.approvedOn = dayjs().toISOString(); approvalPayload.isAutoApproved = true; approvalPayload.isApproved = true; } const partner = await createPartner(partnerPayload); const approval = await createApproval(approvalPayload); res.status(200).json({ result: partner }); } catch (error) { console.log("createPartnerController Error", error); next(error); } }; export const getPartnerController = async (req, res, next) => { try { const { id } = req.params; const pipeline = [ // 1. Match the specific partner (Satisfies Req #1) { $match: { _id: ObjectId.createFromHexString(id), }, }, // 2. Fetch all invoices for this partner { $lookup: { from: "orders", // Ensure this matches your actual collection name localField: "_id", foreignField: "partner", as: "partnerOrders", }, }, // 3. Calculate Invoice Metrics without unwinding (Satisfies Reqs #3, #4, #5) { $addFields: { totalOrdersCount: { $size: "$partnerOrders" }, pendingOrPartialOrdersCount: { $size: { $filter: { input: "$partnerOrders", as: "order", cond: { $in: ["$$order.status", ["INPROGRESS", "COMPLETED"]], }, }, }, }, // Note: Your schema uses "PAID", assuming that correlates to "COMPLETED" totalOrdersAmount: { $sum: "$partnerOrders.total" }, }, }, // 4. Remove the heavy invoices array from memory before doing more lookups { $project: { partnerOrders: 0, }, }, // 5. Lookup Venues and nested Users/Profiles (Satisfies Reqs #2 & #6) { $lookup: { from: "venues", let: { partnerId: "$_id" }, pipeline: [ // Match venues to the partner (Assuming 'entity' field links to Partner _id) { $match: { $expr: { $eq: ["$entity", "$$partnerId"] }, }, }, // Lookup Assignments for this specific venue { $lookup: { from: "assignments", let: { venueId: "$_id" }, pipeline: [ { $match: { $expr: { $eq: ["$venue", "$$venueId"] }, isActive: true, // Optional: ensuring we only get active assignments }, }, // Lookup the User for the assignment { $lookup: { from: "users", localField: "user", foreignField: "_id", as: "userDetails", }, }, { $unwind: { path: "$userDetails", preserveNullAndEmptyArrays: true, }, }, // Lookup the Profile for the assigned User { $lookup: { from: "profiles", localField: "user", foreignField: "user", as: "userProfile", }, }, { $unwind: { path: "$userProfile", preserveNullAndEmptyArrays: true, }, }, // Clean up the assignment shape { $project: { _id: 1, targetedVisits: 1, user: "$userDetails", profile: "$userProfile", }, }, ], as: "assignedUsers", }, }, ], as: "venues", }, }, ]; const partner = await aggregatePartner(pipeline); if (!partner?.length) { throw new Error("Partner not found"); } res.status(200).json({ result: partner[0] || {} }); } catch (error) { console.log("getPartnerController Error", error); next(error); } }; export const getAllPartnersController = async (req, res) => { try { const partners = await getPartnersByQuery({ isApproved: true }); res.status(200).json({ result: partners }); } catch (error) { console.log("getAllPartnersController Error", error); next(error); } }; export const updatePartnerController = async (req, res) => { try { const { id } = req.params; const partner = await updatePartner(id, req.body); res.status(200).json({ result: partner }); } catch (error) { console.log("updatePartnerController Error", error); next(error); } }; export const deletePartnerController = async (req, res, next) => { try { const { id } = req.params; const partner = await updatePartner(id, { isActive: false }); res.status(200).json({ result: partner }); } catch (error) { console.log("deletePartnerController Error", error); next(error); } }; export const approvePartnerController = async (req, res, next) => { try { const { user } = res.locals; const { id } = req.params; const approval = await updateApproval(id, { isApproved: true, isAutoApproved: false, approvedBy: user.id, approvedOn: dayjs().toISOString(), }); const partner = await updatePartner(approval.entity, { isApproved: true, temp: true, }); res.status(200).json({ result: partner }); } catch (error) { console.log("approvePartnerController Error", error); next(error); } }; export const getUnapprovedPartnersController = async (req, res, next) => { try { const pipeline = [ { $match: { isApproved: false, }, }, { $lookup: { from: "partners", localField: "entity", foreignField: "_id", as: "partner", }, }, { $unwind: { path: "$partner", }, }, ]; const unapprovedPartners = await aggregateApproval(pipeline); res.status(200).json({ result: unapprovedPartners }); } catch (error) { console.log("getUnapprovedPartnersController Error", error); next(error); } };