feat(orders): credit each order to the expert who placed it, as legacy did
Legacy fixed `orders.reagent_id` once, when the order was placed, and its «میزان فروش» summed `customer_id = X OR reagent_id = X`. The app credited orders to the customer's CURRENT referrer and left out an expert's own orders, so 9 of 49 imported experts showed a different figure. - Order.salesAgentId (+ referrerCustomerId for 17 legacy orders whose referrer was not an expert); additive migration, recent app orders backfilled from the customer's referrer - createOrder records the expert at placement time - one shared filter (agent-orders.ts) for the experts list, expert detail, dashboard and the expert app; child orders follow salesAgentId - customer page gets its «میزان فروش» back - import carries orders.reagent_id as is; ex-experts kept as admins keep their profile so their own orders stay linked - reconcile-sales: 1,557 of 1,558 match legacy's own formula; balances unchanged Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
8c5d971d1f
commit
29084904e9
@@ -2,6 +2,7 @@ import { ForbiddenException, Injectable, NotFoundException } from '@nestjs/commo
|
||||
import { Prisma } from '@prisma/client';
|
||||
import { PrismaService } from '../../prisma/prisma.service';
|
||||
import type { AuthenticatedAdmin } from '../auth/jwt.strategy';
|
||||
import { agentSalesWhere } from './agent-orders';
|
||||
|
||||
/**
|
||||
* Backs the sales expert's ("کارشناس فروش") own screens in the customer apps.
|
||||
@@ -45,12 +46,12 @@ export class SalesAgentService {
|
||||
* Legacy kept this denormalised in `customers.grams_sell`, recomputed by
|
||||
* `CustomerController::updateGramSell` as
|
||||
* SUM(orders.input) WHERE customer_id = X OR reagent_id = X
|
||||
* with NO order-status filter. Computed live here instead of denormalised.
|
||||
* with NO order-status filter. Computed live here instead of denormalised;
|
||||
* both arms are kept — see agent-orders.ts.
|
||||
*
|
||||
* Two deliberate fidelity notes:
|
||||
* - The `OR customer_id = X` arm is structurally empty now: an agent is an
|
||||
* AdminUser and cannot own an Order, so only the referred-customer arm can
|
||||
* ever contribute. Kept as a comment rather than silently dropped.
|
||||
* - The `OR customer_id = X` arm is the expert's trading account (D21): an
|
||||
* AdminUser cannot own an Order, so their own orders sit on that Customer.
|
||||
* - No status filter, matching legacy. The admin panel disagrees with itself
|
||||
* here — `AdminCustomersService.listReagents` aggregates unfiltered while
|
||||
* `reagentDetail` filters on the SOLD statuses — so this matches
|
||||
@@ -59,7 +60,7 @@ export class SalesAgentService {
|
||||
*/
|
||||
private async gramsSoldFor(agentId: string) {
|
||||
const agg = await this.prisma.order.aggregate({
|
||||
where: { customer: { referredByAgentId: agentId } },
|
||||
where: agentSalesWhere(agentId),
|
||||
_sum: { totalGoldWeightGrams: true },
|
||||
});
|
||||
return agg._sum.totalGoldWeightGrams ?? new Prisma.Decimal(0);
|
||||
|
||||
Reference in New Issue
Block a user