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
@@ -0,0 +1,50 @@
|
||||
import { Prisma } from '@prisma/client';
|
||||
import { OrdersService } from './orders.service';
|
||||
|
||||
/**
|
||||
* Owner ruling 2026-10-08: an order is credited to the customer's expert AT
|
||||
* THE MOMENT IT IS PLACED (legacy `orders.reagent_id`), and a later change of
|
||||
* the customer's expert never moves it.
|
||||
*/
|
||||
describe('OrdersService.createOrder — sales expert credit', () => {
|
||||
function build(referredByAgentId: string | null) {
|
||||
const created: Record<string, unknown>[] = [];
|
||||
const tx = {
|
||||
order: {
|
||||
create: jest.fn(async ({ data }: { data: Record<string, unknown> }) => {
|
||||
created.push(data);
|
||||
return { id: 'o1', ...data };
|
||||
}),
|
||||
},
|
||||
};
|
||||
const prisma = {
|
||||
customer: {
|
||||
findUnique: jest.fn(async () => ({
|
||||
id: 'c1',
|
||||
referredByAgentId,
|
||||
goldDebtGrams: new Prisma.Decimal(0),
|
||||
goldCreditLimitGrams: new Prisma.Decimal(1000),
|
||||
})),
|
||||
},
|
||||
$transaction: jest.fn(async (fn: (t: typeof tx) => unknown) => fn(tx)),
|
||||
};
|
||||
const catalog = { getVariantOrThrow: jest.fn(async () => ({ id: 'v1', rashWeightGrams: '10' })) };
|
||||
const accounting = { orderStatusReached: jest.fn() };
|
||||
const service = new OrdersService(prisma as never, catalog as never, {} as never, accounting as never);
|
||||
return { service, created };
|
||||
}
|
||||
|
||||
const dto = { items: [{ productVariantId: 'v1', quantity: 1, wagePercent: 3 }] } as never;
|
||||
|
||||
it("records the customer's current expert on the order", async () => {
|
||||
const { service, created } = build('agent-A');
|
||||
await service.createOrder(dto, 'c1');
|
||||
expect(created[0].salesAgentId).toBe('agent-A');
|
||||
});
|
||||
|
||||
it('records no expert for a customer without one', async () => {
|
||||
const { service, created } = build(null);
|
||||
await service.createOrder(dto, 'c1');
|
||||
expect(created[0].salesAgentId).toBeNull();
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user