import { Types } from "mongoose"; import { IOrder } from "./models/Abstraction/IOrder"; import { IOrderItem } from "./models/Abstraction/IOrderItem"; import { OrderModel } from "./models/order.model"; import { OrderItemModel } from "./models/orderItem.model"; import { BaseRepository } from "../../common/base/repository"; import { OrderItemsStatus, OrdersStatus } from "../../common/enums/order.enum"; import { OrderStatusQuery, SellerOrdersQueries } from "../../common/types/query.type"; import { TimeService } from "../../utils/time.service"; export type Gran = "daily" | "weekly" | "monthly"; class OrderRepository extends BaseRepository { constructor() { super(OrderModel); } async getUserOrderCount(userId: string) { const pipeline = [ { $match: { user: new Types.ObjectId(userId), }, }, { $lookup: { from: "orderitems", localField: "_id", foreignField: "order", as: "orderItems", }, }, { $unwind: "$orderItems", }, { $group: { _id: { orderId: "$_id", orderStatus: "$orderStatus", itemStatus: "$orderItems.status", }, }, }, { $group: { _id: null, processing: { $sum: { $cond: [ { $or: [ { $eq: ["$_id.orderStatus", OrdersStatus.process_by_seller] }, { $eq: ["$_id.orderStatus", OrdersStatus.wait_payment] }, ], }, { $cond: [ { $or: [ { $eq: ["$_id.itemStatus", OrderItemsStatus.Processing] }, { $eq: ["$_id.itemStatus", OrderItemsStatus.Shipped] }, ], }, 1, 0, ], }, 0, ], }, }, delivered: { $sum: { $cond: [ { $and: [ { $eq: ["$_id.orderStatus", OrdersStatus.process_by_seller] }, { $eq: ["$_id.itemStatus", OrderItemsStatus.Delivered] }, ], }, 1, 0, ], }, }, cancelled: { $sum: { $cond: [ { $and: [ { $eq: ["$_id.orderStatus", OrdersStatus.cancelled_system] }, { $eq: ["$_id.itemStatus", OrderItemsStatus.cancelled_system] }, ], }, 1, 0, ], }, }, }, }, { $project: { _id: 0, processing: 1, delivered: 1, cancelled: 1, }, }, ]; const result = await this.model.aggregate(pipeline); return result[0] || { processing: 0, delivered: 0, cancelled: 0 }; } async getUserOrders(userId: string, statusQuery: OrderStatusQuery) { const matchQuery: { [k: string]: unknown } = { user: new Types.ObjectId(userId), $or: [], }; const orderItemsMatchQuery: { [k: string]: unknown } = {}; switch (statusQuery) { case "Cancelled": matchQuery.$or = [{ orderStatus: OrdersStatus.cancelled_system }, { orderStatus: OrdersStatus.Cancelled }]; orderItemsMatchQuery.$or = [ { "orderItems.status": OrderItemsStatus.cancelled_system }, { "orderItems.status": OrderItemsStatus.cancelled_shop }, { "orderItems.status": OrderItemsStatus.cancelled_user }, ]; break; case "Processing": matchQuery.$or = [{ orderStatus: OrdersStatus.process_by_seller }, { orderStatus: OrdersStatus.wait_payment }]; orderItemsMatchQuery.$or = [ { "orderItems.status": OrderItemsStatus.Processing }, { "orderItems.status": OrderItemsStatus.Shipped }, ]; break; case "Delivered": matchQuery.orderStatus = OrdersStatus.process_by_seller; orderItemsMatchQuery["orderItems.status"] = OrderItemsStatus.Delivered; break; case "Returned": matchQuery.orderStatus = OrdersStatus.process_by_seller; orderItemsMatchQuery["orderItems.status"] = OrderItemsStatus.Returned; break; default: break; } return this.model.aggregate([ { $match: matchQuery, }, { $lookup: { from: "cartpayments", localField: "payment", foreignField: "_id", as: "payment", }, }, { $unwind: "$payment", }, { $lookup: { from: "paymentmethods", localField: "payment.payment_method", foreignField: "_id", as: "payment.payment_method", }, }, { $unwind: "$payment.payment_method", }, { $lookup: { from: "orderitems", localField: "_id", foreignField: "order", as: "orderItems", }, }, { $unwind: "$orderItems", }, { $match: orderItemsMatchQuery, }, { $lookup: { from: "shipments", localField: "orderItems.shipper", foreignField: "_id", as: "orderItems.shipper", }, }, { $unwind: "$orderItems.shipper", }, { $lookup: { from: "shops", localField: "orderItems.shop", foreignField: "_id", as: "orderItems.shop", }, }, { $unwind: "$orderItems.shop", }, { $unwind: "$orderItems.shipmentItems", }, { $lookup: { from: "products", localField: "orderItems.shipmentItems.product", foreignField: "_id", as: "shipmentItemProduct", }, }, { $unwind: "$shipmentItemProduct", }, { $lookup: { from: "productvariants", localField: "orderItems.shipmentItems.variant", foreignField: "_id", as: "shipmentItemVariant", }, }, { $unwind: "$shipmentItemVariant", }, { $group: { _id: "$orderItems._id", shop: { $first: "$orderItems.shop" }, shipper: { $first: "$orderItems.shipper" }, totalSellingPrice: { $first: "$orderItems.totalSellingPrice" }, totalRetailPrice: { $first: "$orderItems.totalRetailPrice" }, totalShipmentCost: { $first: "$orderItems.totalShipmentCost" }, totalPaymentPrice: { $first: "$orderItems.totalPaymentPrice" }, itemsCount: { $first: "$orderItems.itemsCount" }, trackCode: { $first: "$orderItems.trackCode" }, postingDate: { $first: "$orderItems.postingDate" }, postingReceipt: { $first: "$orderItems.postingReceipt" }, status: { $first: "$orderItems.status" }, shipmentItems: { $push: { product: "$shipmentItemProduct", variant: "$shipmentItemVariant", quantity: "$orderItems.shipmentItems.quantity", cancelled_quantity: "$orderItems.shipmentItems.cancelled_quantity", returned_quantity: "$orderItems.shipmentItems.returned_quantity", selling_price: "$orderItems.shipmentItems.selling_price", retail_price: "$orderItems.shipmentItems.retail_price", discount_percent: "$orderItems.shipmentItems.discount_percent", shipmentCost: "$orderItems.shipmentItems.shipmentCost", }, }, orderId: { $first: "$_id" }, payment: { $first: "$payment" }, shipmentAddress: { $first: "$shipmentAddress" }, orderStatus: { $first: "$orderStatus" }, createdAt: { $first: "$createdAt" }, }, }, { $group: { _id: "$orderId", payment: { $first: "$payment" }, shipmentAddress: { $first: "$shipmentAddress" }, orderStatus: { $first: "$orderStatus" }, createdAt: { $first: "$createdAt" }, orderItems: { $push: { _id: "$_id", // orderItem `_id` shop: "$shop", shipper: "$shipper", totalSellingPrice: "$totalSellingPrice", totalRetailPrice: "$totalRetailPrice", totalShipmentCost: "$totalShipmentCost", totalPaymentPrice: "$totalPaymentPrice", itemsCount: "$itemsCount", trackCode: "$trackCode", postingDate: "$postingDate", postingReceipt: "$postingReceipt", status: "$status", shipmentItems: "$shipmentItems", }, }, }, }, { $sort: { createdAt: -1, }, }, ]); } async getUserOrderDetail(orderId: number, userId: string) { return this.model.aggregate([ { $match: { _id: orderId, user: new Types.ObjectId(userId), }, }, { $lookup: { from: "cartpayments", localField: "payment", foreignField: "_id", as: "payment", }, }, { $unwind: "$payment", }, { $lookup: { from: "paymentmethods", localField: "payment.payment_method", foreignField: "_id", as: "payment.payment_method", }, }, { $unwind: "$payment.payment_method", }, { $lookup: { from: "users", localField: "user", foreignField: "_id", as: "user", }, }, { $unwind: "$user", }, { $lookup: { from: "orderitems", localField: "_id", foreignField: "order", as: "orderItems", }, }, { $unwind: "$orderItems", }, { $lookup: { from: "shipments", localField: "orderItems.shipper", foreignField: "_id", as: "orderItems.shipper", }, }, { $unwind: "$orderItems.shipper", }, { $lookup: { from: "shops", localField: "orderItems.shop", foreignField: "_id", as: "orderItems.shop", }, }, { $unwind: "$orderItems.shop", }, { $unwind: "$orderItems.shipmentItems", }, { $lookup: { from: "products", localField: "orderItems.shipmentItems.product", foreignField: "_id", as: "orderItems.shipmentItems.product", }, }, { $unwind: "$orderItems.shipmentItems.product", }, { $lookup: { from: "productvariants", localField: "orderItems.shipmentItems.variant", foreignField: "_id", as: "orderItems.shipmentItems.variant", }, }, { $unwind: "$orderItems.shipmentItems.variant", }, { $lookup: { from: "warranties", localField: "orderItems.shipmentItems.variant.warranty", foreignField: "_id", as: "orderItems.shipmentItems.variant.warranty", }, }, { $unwind: { path: "$orderItems.shipmentItems.variant.warranty", preserveNullAndEmptyArrays: true, }, }, { $lookup: { from: "colors", localField: "orderItems.shipmentItems.variant.color", foreignField: "_id", as: "orderItems.shipmentItems.variant.color", }, }, { $unwind: { path: "$orderItems.shipmentItems.variant.color", preserveNullAndEmptyArrays: true, }, }, { $lookup: { from: "sizes", localField: "orderItems.shipmentItems.variant.size", foreignField: "_id", as: "orderItems.shipmentItems.variant.size", }, }, { $unwind: { path: "$orderItems.shipmentItems.variant.size", preserveNullAndEmptyArrays: true, }, }, { $lookup: { from: "meterages", localField: "orderItems.shipmentItems.variant.meterage", foreignField: "_id", as: "orderItems.shipmentItems.variant.meterage", }, }, { $unwind: { path: "$orderItems.shipmentItems.variant.meterage", preserveNullAndEmptyArrays: true, }, }, { $group: { _id: "$orderItems._id", shop: { $first: "$orderItems.shop" }, shipper: { $first: "$orderItems.shipper" }, status: { $first: "$orderItems.status" }, totalSellingPrice: { $first: "$orderItems.totalSellingPrice" }, totalRetailPrice: { $first: "$orderItems.totalRetailPrice" }, totalShipmentCost: { $first: "$orderItems.totalShipmentCost" }, totalPaymentPrice: { $first: "$orderItems.totalPaymentPrice" }, itemsCount: { $first: "$orderItems.itemsCount" }, trackCode: { $first: "$orderItems.trackCode" }, postingDate: { $first: "$orderItems.postingDate" }, postingReceipt: { $first: "$orderItems.postingReceipt" }, shipmentItems: { $push: "$orderItems.shipmentItems" }, orderId: { $first: "$_id" }, user: { $first: "$user" }, payment: { $first: "$payment" }, shipmentAddress: { $first: "$shipmentAddress" }, orderStatus: { $first: "$orderStatus" }, createdAt: { $first: "$createdAt" }, }, }, { $group: { _id: "$orderId", user: { $first: "$user" }, payment: { $first: "$payment" }, shipmentAddress: { $first: "$shipmentAddress" }, orderStatus: { $first: "$orderStatus" }, createdAt: { $first: "$createdAt" }, orderItems: { $push: { _id: "$_id", order_id: "$orderId", shop: "$shop", shipper: "$shipper", totalSellingPrice: "$totalSellingPrice", totalRetailPrice: "$totalRetailPrice", totalShipmentCost: "$totalShipmentCost", totalPaymentPrice: "$totalPaymentPrice", itemsCount: "$itemsCount", trackCode: "$trackCode", postingDate: "$postingDate", postingReceipt: "$postingReceipt", status: "$status", shipmentItems: "$shipmentItems", }, }, }, }, ]); } } class OrderItemRepo extends BaseRepository { constructor() { super(OrderItemModel); } async getOrderTrackingDetails(orderId: number) { return this.model.find({ order: orderId, trackCode: { $exists: true } }).populate([{ path: "shipper" }]); } async getUserOrderItemsDetail(orderId: number, orderItemId: string) { return this.model.aggregate([ { $match: { _id: new Types.ObjectId(orderItemId), order: orderId, }, }, { $lookup: { from: "orders", localField: "order", foreignField: "_id", as: "order", }, }, { $unwind: "$order", }, { $lookup: { from: "users", localField: "order.user", foreignField: "_id", as: "order.user", }, }, { $unwind: "$order.user", }, { $unwind: "$shipmentItems", }, { $lookup: { from: "products", localField: "shipmentItems.product", foreignField: "_id", as: "shipmentItems.product", }, }, { $unwind: "$shipmentItems.product", }, { $lookup: { from: "productvariants", localField: "shipmentItems.variant", foreignField: "_id", as: "shipmentItems.variant", }, }, { $unwind: "$shipmentItems.variant", }, { $lookup: { from: "warranties", localField: "shipmentItems.variant.warranty", foreignField: "_id", as: "shipmentItems.variant.warranty", }, }, { $unwind: { path: "$shipmentItems.variant.warranty", preserveNullAndEmptyArrays: true, }, }, { $lookup: { from: "colors", localField: "shipmentItems.variant.color", foreignField: "_id", as: "shipmentItems.variant.color", }, }, { $unwind: { path: "$shipmentItems.variant.color", preserveNullAndEmptyArrays: true, }, }, { $lookup: { from: "sizes", localField: "shipmentItems.variant.size", foreignField: "_id", as: "shipmentItems.variant.size", }, }, { $unwind: { path: "$shipmentItems.variant.size", preserveNullAndEmptyArrays: true, }, }, { $lookup: { from: "meterages", localField: "shipmentItems.variant.meterage", foreignField: "_id", as: "shipmentItems.variant.meterage", }, }, { $unwind: { path: "$shipmentItems.variant.meterage", preserveNullAndEmptyArrays: true, }, }, { $lookup: { from: "shipments", localField: "shipper", foreignField: "_id", as: "shipper", }, }, { $unwind: "$shipper", }, { $group: { _id: "$order._id", user: { $first: "$order.user" }, // payment: { $first: "$order.payment" }, shipmentAddress: { $first: "$order.shipmentAddress" }, orderStatus: { $first: "$order.orderStatus" }, createdAt: { $first: "$order.createdAt" }, orderItems: { $first: { _id: "$_id", order_id: "$order._id", shop: "$shop", shipper: "$shipper", totalSellingPrice: "$totalSellingPrice", totalRetailPrice: "$totalRetailPrice", totalShipmentCost: "$totalShipmentCost", totalPaymentPrice: "$totalPaymentPrice", itemsCount: "$itemsCount", trackCode: "$trackCode", postingDate: "$postingDate", postingReceipt: "$postingReceipt", status: "$status", }, }, shipmentItems: { $push: { _id: "$shipmentItems._id", product: "$shipmentItems.product", variant: "$shipmentItems.variant", quantity: "$shipmentItems.quantity", cancelled_quantity: "$shipmentItems.cancelled_quantity", returned_quantity: "$shipmentItems.returned_quantity", selling_price: "$shipmentItems.selling_price", retail_price: "$shipmentItems.retail_price", discount_percent: "$shipmentItems.discount_percent", shipmentCost: "$shipmentItems.shipmentCost", }, }, // totalSellingPrice: { $sum: { $multiply: ["$shipmentItems.selling_price", "$shipmentItems.quantity"] } }, // totalRetailPrice: { $sum: { $multiply: ["$shipmentItems.retail_price", "$shipmentItems.quantity"] } }, // totalShipmentCost: { $sum: "$shipmentItems.shipmentCost" }, // itemsCount: { $sum: "$shipmentItems.quantity" }, }, }, { $addFields: { "orderItems.shipmentItems": "$shipmentItems", // totalPaymentPrice: { $add: ["$totalSellingPrice", "$totalShipmentCost"] }, }, }, ]); } async getOrdersForSellerPanel(shopId: string, queries: SellerOrdersQueries, orderIds?: string[] | string) { const page = queries.page || 1; const limit = queries.limit || 10; const skip = (page - 1) * limit; const priceQuery: { [k: string]: { [op: string]: number } } = {}; const orderMatchQuery: any = {}; if (queries.minPrice) { priceQuery.totalPaymentPrice = { $gte: queries.minPrice }; } if (queries.maxPrice) { if (priceQuery.totalPaymentPrice) { priceQuery.totalPaymentPrice.$lte = queries.maxPrice; } else { priceQuery.totalPaymentPrice = { $lte: queries.maxPrice }; } } if (typeof orderIds === "string") { orderMatchQuery.order = +orderIds; } else if (orderIds && orderIds.length > 0) { orderMatchQuery.order = { $in: orderIds.map((id) => +id) }; } const docs = await this.model.aggregate([ { $match: { shop: new Types.ObjectId(shopId), ...orderMatchQuery, }, }, { $lookup: { from: "orders", localField: "order", foreignField: "_id", as: "order", }, }, { $unwind: "$order", }, { $lookup: { from: "cartpayments", localField: "order.payment", foreignField: "_id", as: "order.payment", }, }, { $unwind: "$order.payment", }, { $lookup: { from: "paymentmethods", localField: "order.payment.payment_method", foreignField: "_id", as: "order.payment.payment_method", }, }, { $unwind: "$order.payment.payment_method", }, { $match: { ...(queries.status && { "order.payment.paymentStatus": queries.status, }), ...(queries.shipperId && { shipper: +queries.shipperId, }), ...(queries.since && { "order.createdAt": { $gte: new Date(queries.since) }, }), }, }, { $lookup: { from: "users", localField: "order.user", foreignField: "_id", as: "order.user", }, }, { $unwind: "$order.user", }, { $unwind: "$shipmentItems", }, { $lookup: { from: "products", localField: "shipmentItems.product", foreignField: "_id", as: "shipmentItems.product", }, }, { $unwind: "$shipmentItems.product", }, { $lookup: { from: "productvariants", localField: "shipmentItems.variant", foreignField: "_id", as: "shipmentItems.variant", }, }, { $unwind: "$shipmentItems.variant", }, { $lookup: { from: "shipments", localField: "shipper", foreignField: "_id", as: "shipper", }, }, { $unwind: "$shipper", }, { $group: { _id: "$order._id", user: { $first: "$order.user" }, payment: { $first: "$order.payment" }, shipmentAddress: { $first: "$order.shipmentAddress" }, orderStatus: { $first: "$order.orderStatus" }, createdAt: { $first: "$order.createdAt" }, orderItems: { $first: { _id: "$_id", order_id: "$order._id", shop: "$shop", shipper: "$shipper", totalSellingPrice: "$totalSellingPrice", totalRetailPrice: "$totalRetailPrice", totalShipmentCost: "$totalShipmentCost", totalPaymentPrice: "$totalPaymentPrice", itemsCount: "$itemsCount", trackCode: "$trackCode", postingDate: "$postingDate", postingReceipt: "$postingReceipt", status: "$status", }, }, shipmentItems: { $push: { _id: "$shipmentItems._id", product: "$shipmentItems.product", variant: "$shipmentItems.variant", quantity: "$shipmentItems.quantity", cancelled_quantity: "$shipmentItems.cancelled_quantity", returned_quantity: "$shipmentItems.returned_quantity", selling_price: "$shipmentItems.selling_price", retail_price: "$shipmentItems.retail_price", discount_percent: "$shipmentItems.discount_percent", shipmentCost: "$shipmentItems.shipmentCost", }, }, // totalSellingPrice: { $sum: { $multiply: ["$shipmentItems.selling_price", "$shipmentItems.quantity"] } }, // totalRetailPrice: { $sum: { $multiply: ["$shipmentItems.retail_price", "$shipmentItems.quantity"] } }, // totalShipmentCost: { $sum: "$shipmentItems.shipmentCost" }, // itemsCount: { $sum: "$shipmentItems.quantity" }, }, }, { $addFields: { "orderItems.shipmentItems": "$shipmentItems", // totalPaymentPrice: { $add: ["$totalSellingPrice", "$totalShipmentCost"] }, }, }, { $match: priceQuery, }, { $sort: { "order.createdAt": -1, }, }, { $facet: { data: [{ $skip: skip }, { $limit: limit }], totalCount: [{ $count: "count" }], }, }, { $addFields: { totalCount: { $arrayElemAt: ["$totalCount.count", 0] }, }, }, { $project: { shipmentItems: 0, }, }, ]); return { count: (docs[0]?.totalCount as number) || 0, docs: docs[0]?.data || [], }; } async getOrdersForAdminPanel(queries: SellerOrdersQueries) { const page = queries.page || 1; const limit = queries.limit || 10; const skip = (page - 1) * limit; const priceQuery: { [k: string]: { [op: string]: number } } = {}; if (queries.minPrice) { priceQuery.totalPaymentPrice = { $gte: queries.minPrice }; } if (queries.maxPrice) { if (priceQuery.totalPaymentPrice) { priceQuery.totalPaymentPrice.$lte = queries.maxPrice; } else { priceQuery.totalPaymentPrice = { $lte: queries.maxPrice }; } } const docs = await this.model.aggregate([ { $lookup: { from: "orders", localField: "order", foreignField: "_id", as: "order", }, }, { $unwind: "$order", }, { $lookup: { from: "cartpayments", localField: "order.payment", foreignField: "_id", as: "order.payment", }, }, { $unwind: "$order.payment", }, { $lookup: { from: "paymentmethods", localField: "order.payment.payment_method", foreignField: "_id", as: "order.payment.payment_method", }, }, { $unwind: "$order.payment.payment_method", }, { $match: { ...(queries.status && { "order.payment.paymentStatus": queries.status, }), ...(queries.shipperId && { shipper: +queries.shipperId, }), ...(queries.since && { "order.createdAt": { $gte: new Date(queries.since) }, }), }, }, { $lookup: { from: "users", localField: "order.user", foreignField: "_id", as: "order.user", }, }, { $unwind: "$order.user", }, { $unwind: "$shipmentItems", }, { $lookup: { from: "products", localField: "shipmentItems.product", foreignField: "_id", as: "shipmentItems.product", }, }, { $unwind: "$shipmentItems.product", }, { $lookup: { from: "productvariants", localField: "shipmentItems.variant", foreignField: "_id", as: "shipmentItems.variant", }, }, { $unwind: "$shipmentItems.variant", }, { $lookup: { from: "shipments", localField: "shipper", foreignField: "_id", as: "shipper", }, }, { $unwind: "$shipper", }, { $group: { _id: "$order._id", user: { $first: "$order.user" }, payment: { $first: "$order.payment" }, shipmentAddress: { $first: "$order.shipmentAddress" }, orderStatus: { $first: "$order.orderStatus" }, createdAt: { $first: "$order.createdAt" }, orderItems: { $first: { _id: "$_id", order_id: "$order._id", shop: "$shop", shipper: "$shipper", totalSellingPrice: "$totalSellingPrice", totalRetailPrice: "$totalRetailPrice", totalShipmentCost: "$totalShipmentCost", totalPaymentPrice: "$totalPaymentPrice", itemsCount: "$itemsCount", trackCode: "$trackCode", postingDate: "$postingDate", postingReceipt: "$postingReceipt", status: "$status", }, }, shipmentItems: { $push: { product: "$shipmentItems.product", variant: "$shipmentItems.variant", quantity: "$shipmentItems.quantity", cancelled_quantity: "$shipmentItems.cancelled_quantity", returned_quantity: "$shipmentItems.returned_quantity", selling_price: "$shipmentItems.selling_price", retail_price: "$shipmentItems.retail_price", discount_percent: "$shipmentItems.discount_percent", shipmentCost: "$shipmentItems.shipmentCost", }, }, }, }, { $addFields: { "orderItems.shipmentItems": "$shipmentItems", // totalPaymentPrice: { $add: ["$totalSellingPrice", "$totalShipmentCost"] }, }, }, { $match: priceQuery, }, { $sort: { "order.createdAt": -1, }, }, { $facet: { data: [{ $skip: skip }, { $limit: limit }], totalCount: [{ $count: "count" }], }, }, { $addFields: { totalCount: { $arrayElemAt: ["$totalCount.count", 0] }, }, }, { $project: { shipmentItems: 0, }, }, ]); return { count: (docs[0]?.totalCount as number) || 0, docs: docs[0]?.data || [], }; } async getSellerOrdersForAdminPanel(shopIds: Types.ObjectId[], queries: SellerOrdersQueries) { const page = queries.page || 1; const limit = queries.limit || 10; const skip = (page - 1) * limit; const priceQuery: { [k: string]: { [op: string]: number } } = {}; if (queries.minPrice) { priceQuery.totalPaymentPrice = { $gte: queries.minPrice }; } if (queries.maxPrice) { if (priceQuery.totalPaymentPrice) { priceQuery.totalPaymentPrice.$lte = queries.maxPrice; } else { priceQuery.totalPaymentPrice = { $lte: queries.maxPrice }; } } const docs = await this.model.aggregate([ { $match: { shop: { $in: shopIds }, }, }, { $lookup: { from: "shops", foreignField: "_id", localField: "shop", as: "shop", }, }, { $unwind: "$shop", }, { $lookup: { from: "orders", localField: "order", foreignField: "_id", as: "order", }, }, { $unwind: "$order", }, { $lookup: { from: "cartpayments", localField: "order.payment", foreignField: "_id", as: "order.payment", }, }, { $unwind: "$order.payment", }, { $lookup: { from: "paymentmethods", localField: "order.payment.payment_method", foreignField: "_id", as: "order.payment.payment_method", }, }, { $unwind: "$order.payment.payment_method", }, { $match: { ...(queries.status && { "order.payment.paymentStatus": queries.status, }), ...(queries.shipperId && { shipper: +queries.shipperId, }), ...(queries.since && { "order.createdAt": { $gte: new Date(queries.since) }, }), }, }, { $lookup: { from: "users", localField: "order.user", foreignField: "_id", as: "order.user", }, }, { $unwind: "$order.user", }, { $unwind: "$shipmentItems", }, { $lookup: { from: "products", localField: "shipmentItems.product", foreignField: "_id", as: "shipmentItems.product", }, }, { $unwind: "$shipmentItems.product", }, { $lookup: { from: "productvariants", localField: "shipmentItems.variant", foreignField: "_id", as: "shipmentItems.variant", }, }, { $unwind: "$shipmentItems.variant", }, { $lookup: { from: "shipments", localField: "shipper", foreignField: "_id", as: "shipper", }, }, { $unwind: "$shipper", }, { $group: { _id: "$order._id", user: { $first: "$order.user" }, payment: { $first: "$order.payment" }, shipmentAddress: { $first: "$order.shipmentAddress" }, orderStatus: { $first: "$order.orderStatus" }, createdAt: { $first: "$order.createdAt" }, orderItems: { $first: { _id: "$_id", order_id: "$order._id", shop: "$shop", shipper: "$shipper", totalSellingPrice: "$totalSellingPrice", totalRetailPrice: "$totalRetailPrice", totalShipmentCost: "$totalShipmentCost", totalPaymentPrice: "$totalPaymentPrice", itemsCount: "$itemsCount", trackCode: "$trackCode", postingDate: "$postingDate", postingReceipt: "$postingReceipt", status: "$status", }, }, shipmentItems: { $push: { product: "$shipmentItems.product", variant: "$shipmentItems.variant", quantity: "$shipmentItems.quantity", cancelled_quantity: "$shipmentItems.cancelled_quantity", returned_quantity: "$shipmentItems.returned_quantity", selling_price: "$shipmentItems.selling_price", retail_price: "$shipmentItems.retail_price", discount_percent: "$shipmentItems.discount_percent", shipmentCost: "$shipmentItems.shipmentCost", }, }, // totalSellingPrice: { $sum: { $multiply: ["$shipmentItems.selling_price", "$shipmentItems.quantity"] } }, // totalRetailPrice: { $sum: { $multiply: ["$shipmentItems.retail_price", "$shipmentItems.quantity"] } }, // totalShipmentCost: { $sum: "$shipmentItems.shipmentCost" }, // itemsCount: { $sum: "$shipmentItems.quantity" }, }, }, { $addFields: { "orderItems.shipmentItems": "$shipmentItems", // totalPaymentPrice: { $add: ["$totalSellingPrice", "$totalShipmentCost"] }, }, }, { $match: priceQuery, }, { $sort: { "order.createdAt": -1, }, }, { $facet: { data: [{ $skip: skip }, { $limit: limit }], totalCount: [{ $count: "count" }], }, }, { $addFields: { totalCount: { $arrayElemAt: ["$totalCount.count", 0] }, }, }, { $project: { shipmentItems: 0, }, }, ]); return { count: (docs[0]?.totalCount as number) || 0, docs: docs[0]?.data || [], }; } async getOrderPriceRangeForAdminPanel() { const docs = await this.model.aggregate([ { $lookup: { from: "orders", localField: "order", foreignField: "_id", as: "order", }, }, { $unwind: "$order", }, { $unwind: "$shipmentItems", }, { $group: { _id: "$order._id", totalSellingPrice: { $sum: { $multiply: ["$shipmentItems.selling_price", "$shipmentItems.quantity"] } }, }, }, { $group: { _id: null, minPrice: { $min: "$totalSellingPrice" }, maxPrice: { $max: "$totalSellingPrice" }, }, }, { $project: { _id: 0, minPrice: 1, maxPrice: 1, }, }, ]); return docs[0]; } async getOrderPriceRange(shopId: string) { const docs = await this.model.aggregate([ { $match: { shop: new Types.ObjectId(shopId), }, }, { $lookup: { from: "orders", localField: "order", foreignField: "_id", as: "order", }, }, { $unwind: "$order", }, { $unwind: "$shipmentItems", }, { $group: { _id: "$order._id", totalSellingPrice: { $sum: { $multiply: ["$shipmentItems.selling_price", "$shipmentItems.quantity"] } }, }, }, { $group: { _id: null, minPrice: { $min: "$totalSellingPrice" }, maxPrice: { $max: "$totalSellingPrice" }, }, }, { $project: { _id: 0, minPrice: 1, maxPrice: 1, }, }, ]); return docs[0]; } async getSellerOrderPriceRange(shopIds: Types.ObjectId[]) { const docs = await this.model.aggregate([ { $match: { shop: { $in: shopIds }, }, }, { $lookup: { from: "shops", foreignField: "_id", localField: "shop", as: "shop", }, }, { $unwind: "$shop", }, { $lookup: { from: "orders", localField: "order", foreignField: "_id", as: "order", }, }, { $unwind: "$order", }, { $unwind: "$shipmentItems", }, { $group: { _id: "$order._id", totalSellingPrice: { $sum: { $multiply: ["$shipmentItems.selling_price", "$shipmentItems.quantity"] } }, }, }, { $group: { _id: null, minPrice: { $min: "$totalSellingPrice" }, maxPrice: { $max: "$totalSellingPrice" }, }, }, { $project: { _id: 0, minPrice: 1, maxPrice: 1, }, }, ]); return docs[0]; } async getSellerOrderDetail(orderId: number, shopId: string) { return this.model.aggregate([ { $match: { order: orderId, shop: new Types.ObjectId(shopId), }, }, { $lookup: { from: "orders", localField: "order", foreignField: "_id", as: "order", }, }, { $unwind: "$order", }, { $lookup: { from: "cartpayments", localField: "order.payment", foreignField: "_id", as: "order.payment", }, }, { $unwind: "$order.payment", }, { $lookup: { from: "paymentmethods", localField: "order.payment.payment_method", foreignField: "_id", as: "order.payment.payment_method", }, }, { $unwind: "$order.payment.payment_method", }, { $lookup: { from: "users", localField: "order.user", foreignField: "_id", as: "order.user", }, }, { $unwind: "$order.user", }, { $unwind: "$shipmentItems", }, { $lookup: { from: "products", localField: "shipmentItems.product", foreignField: "_id", as: "shipmentItems.product", }, }, { $unwind: "$shipmentItems.product", }, { $lookup: { from: "productvariants", localField: "shipmentItems.variant", foreignField: "_id", as: "shipmentItems.variant", }, }, { $unwind: "$shipmentItems.variant", }, { $lookup: { from: "warranties", localField: "shipmentItems.variant.warranty", foreignField: "_id", as: "shipmentItems.variant.warranty", }, }, { $unwind: { path: "$shipmentItems.variant.warranty", preserveNullAndEmptyArrays: true, }, }, { $lookup: { from: "colors", localField: "shipmentItems.variant.color", foreignField: "_id", as: "shipmentItems.variant.color", }, }, { $unwind: { path: "$shipmentItems.variant.color", preserveNullAndEmptyArrays: true, }, }, { $lookup: { from: "sizes", localField: "shipmentItems.variant.size", foreignField: "_id", as: "shipmentItems.variant.size", }, }, { $unwind: { path: "$shipmentItems.variant.size", preserveNullAndEmptyArrays: true, }, }, { $lookup: { from: "meterages", localField: "shipmentItems.variant.meterage", foreignField: "_id", as: "shipmentItems.variant.meterage", }, }, { $unwind: { path: "$shipmentItems.variant.meterage", preserveNullAndEmptyArrays: true, }, }, { $lookup: { from: "shipments", localField: "shipper", foreignField: "_id", as: "shipper", }, }, { $unwind: "$shipper", }, { $group: { _id: "$order._id", user: { $first: "$order.user" }, payment: { $first: "$order.payment" }, shipmentAddress: { $first: "$order.shipmentAddress" }, orderStatus: { $first: "$order.orderStatus" }, createdAt: { $first: "$order.createdAt" }, orderItems: { $first: { _id: "$_id", order_id: "$order._id", shop: "$shop", shipper: "$shipper", totalSellingPrice: "$totalSellingPrice", totalRetailPrice: "$totalRetailPrice", totalShipmentCost: "$totalShipmentCost", totalPaymentPrice: "$totalPaymentPrice", itemsCount: "$itemsCount", trackCode: "$trackCode", postingDate: "$postingDate", postingReceipt: "$postingReceipt", status: "$status", }, }, shipmentItems: { $push: { _id: "$shipmentItems._id", product: "$shipmentItems.product", variant: "$shipmentItems.variant", quantity: "$shipmentItems.quantity", cancelled_quantity: "$shipmentItems.cancelled_quantity", returned_quantity: "$shipmentItems.returned_quantity", selling_price: "$shipmentItems.selling_price", retail_price: "$shipmentItems.retail_price", discount_percent: "$shipmentItems.discount_percent", shipmentCost: "$shipmentItems.shipmentCost", }, }, // totalSellingPrice: { $sum: { $multiply: ["$shipmentItems.selling_price", "$shipmentItems.quantity"] } }, // totalRetailPrice: { $sum: { $multiply: ["$shipmentItems.retail_price", "$shipmentItems.quantity"] } }, // totalShipmentCost: { $sum: "$shipmentItems.shipmentCost" }, // itemsCount: { $sum: "$shipmentItems.quantity" }, }, }, { $addFields: { "orderItems.shipmentItems": "$shipmentItems", // totalPaymentPrice: { $add: ["$totalSellingPrice", "$totalShipmentCost"] }, }, }, ]); } async getSellerOrderDetailForAdminPanel(orderId: number, shopIds: Types.ObjectId[]) { return this.model.aggregate([ { $match: { order: orderId, shop: { $in: shopIds }, }, }, { $lookup: { from: "shops", localField: "shop", foreignField: "_id", as: "shop", }, }, { $unwind: "$shop", }, { $lookup: { from: "orders", localField: "order", foreignField: "_id", as: "order", }, }, { $unwind: "$order", }, { $lookup: { from: "cartpayments", localField: "order.payment", foreignField: "_id", as: "order.payment", }, }, { $unwind: "$order.payment", }, { $lookup: { from: "paymentmethods", localField: "order.payment.payment_method", foreignField: "_id", as: "order.payment.payment_method", }, }, { $unwind: "$order.payment.payment_method", }, { $lookup: { from: "users", localField: "order.user", foreignField: "_id", as: "order.user", }, }, { $unwind: "$order.user", }, { $unwind: "$shipmentItems", }, { $lookup: { from: "products", localField: "shipmentItems.product", foreignField: "_id", as: "shipmentItems.product", }, }, { $unwind: "$shipmentItems.product", }, { $lookup: { from: "productvariants", localField: "shipmentItems.variant", foreignField: "_id", as: "shipmentItems.variant", }, }, { $unwind: "$shipmentItems.variant", }, { $lookup: { from: "warranties", localField: "shipmentItems.variant.warranty", foreignField: "_id", as: "shipmentItems.variant.warranty", }, }, { $unwind: { path: "$shipmentItems.variant.warranty", preserveNullAndEmptyArrays: true, }, }, { $lookup: { from: "colors", localField: "shipmentItems.variant.color", foreignField: "_id", as: "shipmentItems.variant.color", }, }, { $unwind: { path: "$shipmentItems.variant.color", preserveNullAndEmptyArrays: true, }, }, { $lookup: { from: "sizes", localField: "shipmentItems.variant.size", foreignField: "_id", as: "shipmentItems.variant.size", }, }, { $unwind: { path: "$shipmentItems.variant.size", preserveNullAndEmptyArrays: true, }, }, { $lookup: { from: "meterages", localField: "shipmentItems.variant.meterage", foreignField: "_id", as: "shipmentItems.variant.meterage", }, }, { $unwind: { path: "$shipmentItems.variant.meterage", preserveNullAndEmptyArrays: true, }, }, { $lookup: { from: "shipments", localField: "shipper", foreignField: "_id", as: "shipper", }, }, { $unwind: "$shipper", }, { $group: { _id: "$order._id", user: { $first: "$order.user" }, payment: { $first: "$order.payment" }, shipmentAddress: { $first: "$order.shipmentAddress" }, orderStatus: { $first: "$order.orderStatus" }, createdAt: { $first: "$order.createdAt" }, orderItems: { $first: { _id: "$_id", order_id: "$order._id", shop: "$shop", shipper: "$shipper", totalSellingPrice: "$totalSellingPrice", totalRetailPrice: "$totalRetailPrice", totalShipmentCost: "$totalShipmentCost", totalPaymentPrice: "$totalPaymentPrice", itemsCount: "$itemsCount", trackCode: "$trackCode", postingDate: "$postingDate", postingReceipt: "$postingReceipt", status: "$status", }, }, shipmentItems: { $push: { _id: "$shipmentItems._id", product: "$shipmentItems.product", variant: "$shipmentItems.variant", quantity: "$shipmentItems.quantity", cancelled_quantity: "$shipmentItems.cancelled_quantity", returned_quantity: "$shipmentItems.returned_quantity", selling_price: "$shipmentItems.selling_price", retail_price: "$shipmentItems.retail_price", discount_percent: "$shipmentItems.discount_percent", shipmentCost: "$shipmentItems.shipmentCost", }, }, // totalSellingPrice: { $sum: { $multiply: ["$shipmentItems.selling_price", "$shipmentItems.quantity"] } }, // totalRetailPrice: { $sum: { $multiply: ["$shipmentItems.retail_price", "$shipmentItems.quantity"] } }, // totalShipmentCost: { $sum: "$shipmentItems.shipmentCost" }, // itemsCount: { $sum: "$shipmentItems.quantity" }, }, }, { $addFields: { "orderItems.shipmentItems": "$shipmentItems", // totalPaymentPrice: { $add: ["$totalSellingPrice", "$totalShipmentCost"] }, }, }, ]); } async getSellerSalesStats(shopId: string, queries: { start?: string; end?: string }) { // Parse the date range from queries, converting from Persian to Gregorian if necessary const startDate = queries.start ? new Date(TimeService.convertPersianToGregorian(queries.start)) : null; const endDate = queries.end ? new Date(TimeService.convertPersianToGregorian(queries.end)) : new Date(); // Build the match query to filter data within the date range and for the specific shop const matchQuery: any = { shop: new Types.ObjectId(shopId), createdAt: { ...(startDate ? { $gte: startDate } : {}), $lte: endDate, }, }; const salesData = await this.model.aggregate([ { $match: matchQuery }, { $lookup: { from: "orders", localField: "order", foreignField: "_id", as: "order", }, }, { $unwind: "$order" }, { $group: { _id: { year: { $year: "$createdAt" }, month: { $month: "$createdAt" }, }, totalSales: { $sum: "$totalSellingPrice" }, totalNetSales: { $sum: "$totalRetailPrice" }, itemsSold: { $sum: "$itemsCount" }, totalOrders: { $sum: 1 }, }, }, { $sort: { "_id.year": 1, "_id.month": 1 } }, ]); // Format the aggregated sales data const formattedSalesData = salesData.map((item) => { const monthString = `${item._id.year}-${String(item._id.month).padStart(2, "0")}`; return { month: TimeService.PersianMonthName(monthString), totalSales: item.totalSales, totalNetSales: item.totalNetSales, itemsSold: item.itemsSold, averageSales: item.totalSales / (item.totalOrders || 1), totalOrders: item.totalOrders, }; }); // Calculate overall stats const totalSales = formattedSalesData.reduce((acc, curr) => acc + curr.totalSales, 0); const totalNetSales = formattedSalesData.reduce((acc, curr) => acc + curr.totalNetSales, 0); const totalOrders = formattedSalesData.reduce((acc, curr) => acc + curr.totalOrders, 0); const itemsSold = formattedSalesData.reduce((acc, curr) => acc + curr.itemsSold, 0); return { averageDailySales: totalSales / (formattedSalesData.length * 30 || 1), totalSales, totalNetSales, totalOrders, itemsSold, startDate: startDate ? TimeService.convertGregorianToPersian(startDate) : null, endDate: TimeService.convertGregorianToPersian(endDate), totalMonths: formattedSalesData.length, statsByMonth: formattedSalesData, }; } async getAllProcessingOrders() { return await this.model.find({ status: "Processing" }).countDocuments(); } async getDailyShipmentSalesReport() { const today = new Date(); today.setHours(0, 0, 0, 0); const startOfDay = new Date(today.getFullYear(), today.getMonth(), today.getDate()); const endOfDay = new Date(today.getFullYear(), today.getMonth(), today.getDate(), 23, 59, 59, 999); const salesData = await this.model.aggregate([ { $match: { createdAt: { $gte: startOfDay, $lte: endOfDay, }, status: { $nin: ["cancelled_shop", "cancelled_system", "Returned", OrdersStatus.wait_payment], }, }, }, { $group: { _id: null, // Since we only want today's stats, grouping by date isn't necessary totalShipmentCost: { $sum: "$totalShipmentCost" }, itemsSold: { $sum: "$itemsCount" }, totalOrders: { $sum: 1 }, }, }, ]); const defaultData = { _id: null, totalShipmentCost: 0, itemsSold: 0, totalOrders: 0, }; return salesData.length > 0 ? salesData[0] : defaultData; } async getWeeklyShipmentSalesReport() { const today = new Date(); today.setHours(0, 0, 0, 0); const startOfWeek = new Date(today); startOfWeek.setDate(today.getDate() - 6); // 7 days ago const endOfWeek = new Date(today.getFullYear(), today.getMonth(), today.getDate(), 23, 59, 59, 999); const salesData = await this.model.aggregate([ { $match: { createdAt: { $gte: startOfWeek, $lte: endOfWeek, }, status: { $nin: ["cancelled_shop", "cancelled_system", "Returned", OrdersStatus.wait_payment], }, }, }, { $group: { _id: null, // Since we only want today's stats, grouping by date isn't necessary totalShipmentCost: { $sum: "$totalShipmentCost" }, itemsSold: { $sum: "$itemsCount" }, totalOrders: { $sum: 1 }, }, }, ]); const defaultData = { _id: null, totalShipmentCost: 0, itemsSold: 0, totalOrders: 0, }; return salesData.length > 0 ? salesData[0] : defaultData; } async getMonthlyShipmentSalesReport() { const today = new Date(); const startOfMonth = new Date(today.getFullYear(), today.getMonth(), 1); const endOfMonth = new Date(today.getFullYear(), today.getMonth() + 1, 1); const salesData = await this.model.aggregate([ { $match: { createdAt: { $gte: startOfMonth, $lte: endOfMonth, }, status: { $nin: ["cancelled_shop", "cancelled_system", "Returned", OrdersStatus.wait_payment], }, }, }, { $group: { _id: null, // Since we only want today's stats, grouping by date isn't necessary totalShipmentCost: { $sum: "$totalShipmentCost" }, itemsSold: { $sum: "$itemsCount" }, totalOrders: { $sum: 1 }, }, }, ]); const defaultData = { _id: null, totalShipmentCost: 0, itemsSold: 0, totalOrders: 0, }; return salesData.length > 0 ? salesData[0] : defaultData; } async getAnnualShipmentSalesReport() { const today = new Date(); const startOfYear = new Date(today.getFullYear(), 0, 1); const endOfYear = new Date(today.getFullYear() + 1, 0, 1); const salesData = await this.model.aggregate([ { $match: { createdAt: { $gte: startOfYear, $lte: endOfYear, }, status: { $nin: ["cancelled_shop", "cancelled_system", "Returned", OrdersStatus.wait_payment], }, }, }, { $group: { _id: null, // Since we only want today's stats, grouping by date isn't necessary totalShipmentCost: { $sum: "$totalShipmentCost" }, itemsSold: { $sum: "$itemsCount" }, totalOrders: { $sum: 1 }, }, }, ]); const defaultData = { _id: null, totalShipmentCost: 0, itemsSold: 0, totalOrders: 0, }; return salesData.length > 0 ? salesData[0] : defaultData; } async getDailySalesReport() { const today = new Date(); today.setHours(0, 0, 0, 0); const startOfDay = new Date(today.getFullYear(), today.getMonth(), today.getDate()); const endOfDay = new Date(today.getFullYear(), today.getMonth(), today.getDate(), 23, 59, 59, 999); const salesData = await this.model.aggregate([ { $match: { createdAt: { $gte: startOfDay, $lte: endOfDay, }, status: { $nin: ["cancelled_shop", "cancelled_system", OrderItemsStatus.cancelled_user, "Returned"], }, }, }, { $group: { _id: null, // Since we only want today's stats, grouping by date isn't necessary totalSales: { $sum: "$totalSellingPrice" }, totalNetSales: { $sum: "$totalRetailPrice" }, itemsSold: { $sum: "$itemsCount" }, totalOrders: { $sum: 1 }, }, }, ]); const defaultData = { _id: null, totalSales: 0, totalNetSales: 0, itemsSold: 0, totalOrders: 0, }; return salesData.length > 0 ? salesData[0] : defaultData; } async getWeeklySalesReport() { const today = new Date(); today.setHours(0, 0, 0, 0); const startOfWeek = new Date(today); startOfWeek.setDate(today.getDate() - 6); // 7 days ago const endOfWeek = new Date(today.getFullYear(), today.getMonth(), today.getDate(), 23, 59, 59, 999); const salesData = await this.model.aggregate([ { $match: { createdAt: { $gte: startOfWeek, $lte: endOfWeek, }, status: { $nin: ["cancelled_shop", "cancelled_system", "Returned"], }, }, }, { $group: { _id: null, // Grouping by week totalSales: { $sum: "$totalSellingPrice" }, totalNetSales: { $sum: "$totalRetailPrice" }, itemsSold: { $sum: "$itemsCount" }, totalOrders: { $sum: 1 }, }, }, ]); const defaultData = { _id: null, totalSales: 0, totalNetSales: 0, itemsSold: 0, totalOrders: 0, }; return salesData.length > 0 ? salesData[0] : defaultData; } async getFiveDaysAgoSalesReport() { const today = new Date(); today.setHours(0, 0, 0, 0); // Reset time to the start of the day const fiveDaysAgo = new Date(today); fiveDaysAgo.setDate(today.getDate() - 4); // 5 days ago const salesData = await this.model.aggregate([ { $match: { createdAt: { $gte: fiveDaysAgo, $lt: new Date(today.getTime() + 24 * 60 * 60 * 1000), // Include today }, status: { $nin: [ OrderItemsStatus.cancelled_shop, OrderItemsStatus.cancelled_system, OrderItemsStatus.Returned, OrdersStatus.wait_payment, ], }, }, }, { $group: { _id: { $dateToString: { format: "%Y-%m-%d", date: "$createdAt" }, }, totalSales: { $sum: "$totalSellingPrice" }, }, }, { $sort: { _id: 1 }, // Sort by date in ascending order }, { $project: { _id: 0, date: "$_id", price: "$totalSales", }, }, { $group: { _id: null, dates: { $push: "$date" }, prices: { $push: "$price" }, }, }, { $project: { _id: 0, data: { $map: { input: { $range: [0, 5] }, as: "day", in: { date: { $dateToString: { format: "%Y-%m-%d", date: { $dateSubtract: { startDate: today, unit: "day", amount: "$$day", }, }, }, }, price: { $let: { vars: { index: { $indexOfArray: [ "$dates", { $dateToString: { format: "%Y-%m-%d", date: { $dateSubtract: { startDate: today, unit: "day", amount: "$$day" } }, }, }, ], }, }, in: { $cond: { if: { $gte: ["$$index", 0] }, then: { $arrayElemAt: ["$prices", "$$index"] }, else: 0, }, }, }, }, }, }, }, }, }, { $unwind: "$data", }, { $replaceRoot: { newRoot: "$data" }, }, ]); return salesData; } // Shared constants (place near top of file) async getMonthlySalesReport() { const EXCLUDED_ORDER_ITEM_STATUSES = [ OrderItemsStatus.cancelled_shop, OrderItemsStatus.cancelled_system, OrderItemsStatus.cancelled_user, OrderItemsStatus.Returned, ]; const EXCLUDED_ORDER_STATUSES = [OrdersStatus.wait_payment, OrdersStatus.cancelled_system, OrdersStatus.Cancelled]; const today = new Date(); const startOfMonth = new Date(today.getFullYear(), today.getMonth(), 1); const endOfMonth = new Date(today.getFullYear(), today.getMonth() + 1, 1); const salesData = await this.model.aggregate([ // filter items by month & item status first { $match: { createdAt: { $gte: startOfMonth, $lt: endOfMonth }, status: { $nin: EXCLUDED_ORDER_ITEM_STATUSES }, }, }, // join the parent order { $lookup: { from: "orders", localField: "order", foreignField: "_id", as: "order", }, }, { $unwind: "$order" }, // filter by parent order status { $match: { "order.orderStatus": { $nin: EXCLUDED_ORDER_STATUSES }, }, }, // aggregate totals and collect distinct order ids { $group: { _id: null, totalSales: { $sum: "$totalSellingPrice" }, totalNetSales: { $sum: "$totalRetailPrice" }, itemsSold: { $sum: "$itemsCount" }, orderIds: { $addToSet: "$order._id" }, }, }, // convert orderIds into a number { $addFields: { totalOrders: { $size: "$orderIds" }, }, }, // optionally remove the array from results { $project: { orderIds: 0 }, }, ]); return salesData.length > 0 ? salesData[0] : null; } async getOrderChart(granularity: Gran = "daily", from?: string, to?: string) { const EXCLUDED_ORDER_ITEM_STATUSES = [ OrderItemsStatus.cancelled_shop, OrderItemsStatus.cancelled_system, OrderItemsStatus.cancelled_user, OrderItemsStatus.Returned, ]; const EXCLUDED_ORDER_STATUSES = [OrdersStatus.wait_payment, OrdersStatus.cancelled_system, OrdersStatus.Cancelled]; const DATE_TRUNC_TIMEZONE = "Asia/Tehran"; const MS_PER_DAY = 24 * 60 * 60 * 1000; const today = new Date(); // if user asked for monthly and did not give from/to, use calendar month let startDate: Date; let endDate: Date; if (granularity === "monthly" && !from && !to) { startDate = new Date(today.getFullYear(), today.getMonth(), 1); endDate = new Date(today.getFullYear(), today.getMonth() + 1, 1); } else { endDate = to ? new Date(to) : new Date(); endDate.setHours(23, 59, 59, 999); const defaultStart = new Date(Date.now() - 30 * MS_PER_DAY); startDate = from ? new Date(from) : defaultStart; startDate.setHours(0, 0, 0, 0); } if (isNaN(startDate.getTime()) || isNaN(endDate.getTime())) { throw new Error("Invalid date format. Expected YYYY-MM-DD or ISO date."); } if (startDate > endDate) { const tmp = startDate; startDate = endDate; endDate = tmp; } const allowed: Record = { daily: "day", weekly: "week", monthly: "month", }; const unit = allowed[granularity] ?? "day"; const pipeline: any[] = [ // 1. filter order items by date and item-status { $match: { createdAt: { $gte: startDate, $lte: endDate }, status: { $nin: EXCLUDED_ORDER_ITEM_STATUSES }, }, }, // 2. join parent order and filter by order status { $lookup: { from: "orders", localField: "order", foreignField: "_id", as: "order", }, }, { $unwind: "$order" }, { $match: { "order.orderStatus": { $nin: EXCLUDED_ORDER_STATUSES }, }, }, // 3. group by truncated period (include timezone) { $group: { _id: { period: { $dateTrunc: { date: "$createdAt", unit: unit, binSize: 1, timezone: DATE_TRUNC_TIMEZONE, }, }, }, periodTotal: { $sum: "$totalSellingPrice" }, }, }, { $sort: { "_id.period": 1 } }, ]; const aggResults: Array<{ _id: { period: Date }; periodTotal: number }> = await this.model.aggregate(pipeline).exec(); // build map and x/y arrays (same logic as you had) const map = new Map(); for (const r of aggResults) { const d: Date = r._id.period; const key = unit === "month" ? d.toISOString().slice(0, 7) : d.toISOString().slice(0, 10); map.set(key, r.periodTotal ?? 0); } function formatKey(d: Date) { return unit === "month" ? d.toISOString().slice(0, 7) : d.toISOString().slice(0, 10); } function addPeriod(d: Date) { const nd = new Date(d); if (unit === "day") nd.setDate(nd.getDate() + 1); else if (unit === "week") nd.setDate(nd.getDate() + 7); else nd.setMonth(nd.getMonth() + 1); return nd; } const xAxis: string[] = []; const yAxis: number[] = []; let cursor = new Date(startDate); if (unit === "month") cursor.setDate(1); while (cursor <= endDate) { const key = formatKey(cursor); xAxis.push(key); yAxis.push(map.get(key) ?? 0); cursor = addPeriod(cursor); } const totalSales = yAxis.reduce((s, v) => s + v, 0); return { chartType: "line", title: "نمودار کل فروش", unit: "تومان", granularity, xAxis, yAxis, totalSales, _debug: { aggregatedPeriods: aggResults.length }, }; } async getAnnualSalesReport() { const today = new Date(); const startOfYear = new Date(today.getFullYear(), 0, 1); const endOfYear = new Date(today.getFullYear() + 1, 0, 1); const salesData = await this.model.aggregate([ { $lookup: { from: "orders", localField: "order", foreignField: "_id", as: "order", }, }, { $match: { createdAt: { $gte: startOfYear, $lt: endOfYear, }, status: { $nin: ["cancelled_shop", "cancelled_system", "Returned", OrdersStatus.wait_payment], }, }, }, { $group: { _id: null, totalSales: { $sum: "$totalSellingPrice" }, totalNetSales: { $sum: "$totalRetailPrice" }, itemsSold: { $sum: "$itemsCount" }, totalOrders: { $sum: 1 }, }, }, ]); return salesData.length > 0 ? salesData[0] : null; } async getTopSellingProducts(limit = 5) { const topProducts = await this.model.aggregate([ { $unwind: "$shipmentItems" }, { $group: { _id: "$shipmentItems.product", totalSold: { $sum: "$shipmentItems.quantity" }, }, }, { $sort: { totalSold: -1 } }, { $limit: limit }, { $lookup: { from: "products", localField: "_id", foreignField: "_id", as: "productDetails", }, }, { $unwind: "$productDetails" }, { $lookup: { from: "shops", localField: "productDetails.shop", foreignField: "_id", as: "productDetails.shop", }, }, { $unwind: "$productDetails.shop", }, { $project: { _id: 0, productId: "$_id", totalSold: 1, productDetails: { _id: 1, title_fa: 1, title_en: 1, model: 1, description: 1, shop: { _id: 1, shopName: 1, }, }, }, }, ]); return topProducts; } } //**************************************************** */ //**************************************************** */ function createOrderItemRepo(): OrderItemRepo { return new OrderItemRepo(); } function createOrderRepo(): OrderRepository { return new OrderRepository(); } export { OrderRepository, createOrderRepo, createOrderItemRepo, OrderItemRepo };