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[] = []; const tx = { order: { create: jest.fn(async ({ data }: { data: Record }) => { 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 wage = { quote: jest.fn() }; const service = new OrdersService(prisma as never, catalog as never, {} as never, accounting as never, wage 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(); }); }); /** A server quote of 10% for every variant. */ const wageStub = { quote: jest.fn(async (_c: string, ids: string[]) => new Map(ids.map((id) => [id, { wagePercentSnapshot: '10', discountPercentSnapshot: '0' }]))), }; /** MON-05 (owner ruling 2026-10-08): «عدم سفارش» stops app orders only. */ describe('OrdersService.createOrder — order ban', () => { function build(canPlaceOrders: boolean) { const tx = { order: { create: jest.fn(async ({ data }: { data: object }) => ({ id: 'o1', ...data })) } }; const prisma = { customer: { findUnique: jest.fn(async () => ({ id: 'c1', canPlaceOrders, referredByAgentId: null, 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' })) }; return new OrdersService(prisma as never, catalog as never, {} as never, { orderStatusReached: jest.fn() } as never, wageStub as never); } const dto = { items: [{ productVariantId: 'v1', quantity: 1, wagePercent: 3 }] } as never; it('refuses a suspended customer ordering from the app', async () => { await expect(build(false).createOrder(dto, 'c1', { placedBy: 'customer' })).rejects.toThrow('غیرفعال'); }); it('lets an operator place an order for a suspended customer', async () => { await expect(build(false).createOrder(dto, 'c1', { placedBy: 'operator' })).resolves.toMatchObject({ id: 'o1' }); }); it('lets an allowed customer order from the app', async () => { await expect(build(true).createOrder(dto, 'c1', { placedBy: 'customer' })).resolves.toMatchObject({ id: 'o1' }); }); }); /** MON-08 (owner ruling 2026-10-08): an app order is priced by the server, never by the app. */ describe('OrdersService.createOrder — server-side making charge', () => { function build() { const created: Record[] = []; const tx = { order: { create: jest.fn(async ({ data }: { data: Record }) => { created.push(data); return { id: 'o1', ...data }; }) } }; const prisma = { customer: { findUnique: jest.fn(async () => ({ id: 'c1', canPlaceOrders: true, referredByAgentId: null, 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 service = new OrdersService(prisma as never, catalog as never, {} as never, { orderStatusReached: jest.fn() } as never, wageStub as never); return { service, created }; } // A tampered request: zero making charge, a 50% discount and a rial charge. const tampered = { items: [{ productVariantId: 'v1', quantity: 1, wagePercent: 0, discountPercent: 50, flatRialCharge: 999 }] } as never; it('ignores what the app sends and uses the server quote', async () => { const { service, created } = build(); await service.createOrder(tampered, 'c1', { placedBy: 'customer' }); expect(created[0].totalGoldWeightGrams.toString()).toBe('11'); expect(created[0].flatRialCharge.toString()).toBe('0'); }); it('keeps the numbers an operator entered in the panel', async () => { const { service, created } = build(); await service.createOrder(tampered, 'c1', { placedBy: 'operator' }); expect(created[0].totalGoldWeightGrams.toString()).toBe('5'); expect(created[0].flatRialCharge.toString()).toBe('999'); }); });