This commit is contained in:
s.esmaeili
2026-09-19 13:12:58 +03:30
parent cb07e7c969
commit 7227e9c61b
7 changed files with 124 additions and 8 deletions
+121 -4
View File
@@ -84977,8 +84977,7 @@ var require_acl_constants = __commonJS({
"config.wallet",
"custom.config.statics.slider",
"custom.config.statics.tags.banner.ids",
"dashboard.omde",
"dashboard.tak",
"dashboard.view",
"document.create",
"document.list",
"document.list.confirm",
@@ -92609,6 +92608,112 @@ var require_admin_dashboard_service = __commonJS({
static SOLD = {
status: { in: [client_1.OrderStatus.DELIVERED_TO_AGENT, client_1.OrderStatus.DELIVERED_TO_CUSTOMER] }
};
/** The single merged dashboard endpoint (`GET admin/dashboard/overview`). */
async overview() {
const since30 = this.daysAgo(30);
const since7 = this.daysAgo(7);
const [omde, tak, ordersLast30, statusGroups, channelGroups, topProductRows, latestGoldQuote, debtAgg] = await Promise.all([
this.omdeAnalytics(),
this.takAnalytics(),
// روند سفارش‌ها در ۳۰ روز گذشته — one row per order, bucketed by day below.
this.prisma.order.findMany({
where: { createdAt: { gte: since30 } },
select: { createdAt: true, channel: true }
}),
// دونات وضعیت سفارشات (۳۰ روز گذشته)
this.prisma.order.groupBy({
by: ["status"],
where: { createdAt: { gte: since30 } },
_count: true
}),
// تفکیک عمده/تک (۳۰ روز گذشته)
this.prisma.order.groupBy({
by: ["channel"],
where: { createdAt: { gte: since30 } },
_count: true,
_sum: { totalGoldWeightGrams: true }
}),
// محصولات پرفروش (۳۰ روز گذشته) — by shipped weight, top 6.
this.prisma.orderItem.findMany({
where: { order: { createdAt: { gte: since30 } } },
select: {
quantity: true,
computedWeightGrams: true,
productVariant: { select: { product: { select: { id: true, title: true } } } }
}
}),
// نرخ فعلی طلا — legacy's goldPrice widget (18 عیار / 750‰).
this.prisma.goldPriceQuote.findFirst({
where: { karatPerMille: 750 },
orderBy: { quotedAt: "desc" }
}),
// مجموع بدهی مشتریان (گرم طلا) — cached balance, see Customer.goldDebtGrams.
this.prisma.customer.aggregate({ _sum: { goldDebtGrams: true } })
]);
const trendByDay = /* @__PURE__ */ new Map();
for (let i = 29; i >= 0; i--) {
trendByDay.set(this.dayKey(this.daysAgo(i)), { total: 0, retail: 0, wholesale: 0 });
}
for (const o of ordersLast30) {
const key = this.dayKey(o.createdAt);
const bucket = trendByDay.get(key);
if (!bucket)
continue;
bucket.total += 1;
if (o.channel === "WHOLESALE")
bucket.wholesale += 1;
else
bucket.retail += 1;
}
const ordersTrend = [...trendByDay.entries()].map(([date, v]) => ({ date, ...v }));
const statusLabels = {
SUSPENDED: "\u0645\u0639\u0644\u0642 (\u0633\u0642\u0641 \u0627\u0639\u062A\u0628\u0627\u0631)",
PLACED: "\u062B\u0628\u062A \u0634\u062F\u0647",
ADMIN_APPROVED: "\u062A\u0627\u06CC\u06CC\u062F \u0645\u062F\u06CC\u0631",
SOURCING: "\u062F\u0631 \u062D\u0627\u0644 \u062A\u0627\u0645\u06CC\u0646",
PREPARING: "\u062F\u0631 \u062D\u0627\u0644 \u0622\u0645\u0627\u062F\u0647\u200C\u0633\u0627\u0632\u06CC",
DELIVERED_TO_AGENT: "\u062A\u062D\u0648\u06CC\u0644 \u0628\u0647 \u0646\u0645\u0627\u06CC\u0646\u062F\u0647",
DELIVERED_TO_CUSTOMER: "\u062A\u062D\u0648\u06CC\u0644 \u0628\u0647 \u0645\u0634\u062A\u0631\u06CC",
CANCELLED: "\u0644\u063A\u0648 \u0634\u062F\u0647"
};
const statusBreakdown = statusGroups.map((g) => ({
status: g.status,
label: statusLabels[g.status],
count: g._count
}));
const channelLabels = { RETAIL: "\u062A\u06A9 \u0641\u0631\u0648\u0634\u06CC", WHOLESALE: "\u0639\u0645\u062F\u0647 \u0641\u0631\u0648\u0634\u06CC" };
const channelBreakdown = channelGroups.map((g) => ({
channel: g.channel,
label: channelLabels[g.channel] ?? g.channel,
count: g._count,
grams: g._sum.totalGoldWeightGrams ?? new client_1.Prisma.Decimal(0)
}));
const productTotals = /* @__PURE__ */ new Map();
for (const it of topProductRows) {
const p = it.productVariant.product;
const row = productTotals.get(p.id) ?? { title: p.title, weight: new client_1.Prisma.Decimal(0), qty: 0 };
row.weight = row.weight.add(it.computedWeightGrams.mul(it.quantity));
row.qty += it.quantity;
productTotals.set(p.id, row);
}
const topProducts = [...productTotals.values()].sort((a, b) => Number(b.weight) - Number(a.weight)).slice(0, 6);
return {
// ── everything the two legacy dashboards returned, unchanged ──────
...omde,
takLastOrder: tak.lastOrder,
// ── new chart data ─────────────────────────────────────────────
ordersTrend,
statusBreakdown,
channelBreakdown,
topProducts,
goldPricePerGram: latestGoldQuote?.pricePerGramRial ?? null,
goldPriceQuotedAt: latestGoldQuote?.quotedAt ?? null,
totalCustomerDebtGrams: debtAgg._sum.goldDebtGrams ?? new client_1.Prisma.Decimal(0)
};
}
dayKey(d) {
return d.toISOString().slice(0, 10);
}
/** Legacy `GET get-analytics` — the wholesale dashboard. */
async omdeAnalytics() {
const since30 = this.daysAgo(30);
@@ -92837,9 +92942,14 @@ var require_admin_dashboard_controller = __commonJS({
constructor(dashboard) {
this.dashboard = dashboard;
}
overview() {
return this.dashboard.overview();
}
/** @deprecated superseded by GET overview; kept as an alias. */
omde() {
return this.dashboard.omdeAnalytics();
}
/** @deprecated superseded by GET overview; kept as an alias. */
tak() {
return this.dashboard.takAnalytics();
}
@@ -92853,16 +92963,23 @@ var require_admin_dashboard_controller = __commonJS({
}
};
exports2.AdminDashboardController = AdminDashboardController;
__decorate4([
(0, common_12.Get)("overview"),
(0, guards_1.RequirePermission)("dashboard.view"),
__metadata3("design:type", Function),
__metadata3("design:paramtypes", []),
__metadata3("design:returntype", void 0)
], AdminDashboardController.prototype, "overview", null);
__decorate4([
(0, common_12.Get)("omde"),
(0, guards_1.RequirePermission)("dashboard.omde"),
(0, guards_1.RequirePermission)("dashboard.view"),
__metadata3("design:type", Function),
__metadata3("design:paramtypes", []),
__metadata3("design:returntype", void 0)
], AdminDashboardController.prototype, "omde", null);
__decorate4([
(0, common_12.Get)("tak"),
(0, guards_1.RequirePermission)("dashboard.tak"),
(0, guards_1.RequirePermission)("dashboard.view"),
__metadata3("design:type", Function),
__metadata3("design:paramtypes", []),
__metadata3("design:returntype", void 0)
+3 -4
View File
@@ -1620,8 +1620,7 @@ var ALL_RIDS = [
"config.wallet",
"custom.config.statics.slider",
"custom.config.statics.tags.banner.ids",
"dashboard.omde",
"dashboard.tak",
"dashboard.view",
"document.create",
"document.list",
"document.list.confirm",
@@ -1782,7 +1781,7 @@ async function main() {
"persons.list.client.single.view",
"persons.create",
"product.list",
"dashboard.tak",
"dashboard.view",
"comment"
]
},
@@ -1800,7 +1799,7 @@ async function main() {
"report.order.item",
"report.product",
"config.report",
"dashboard.omde"
"dashboard.view"
]
},
{