Files
shop-api/src/modules/order/order.repository.ts
T
morteza-mortezai e8d7996edd fix : daily report
2025-10-29 13:33:42 +03:30

2585 lines
70 KiB
TypeScript

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<IOrder> {
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<IOrderItem> {
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<Gran, "day" | "week" | "month"> = {
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<string, number>();
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 };