Legacy stored customers.sts but no code read it, so the switch never stopped an order, and 313 active customers carry it, mostly as the sign-up default. Owner option 2: enforce it from now on, for orders placed from the app only (an operator can still order for the customer), and import every customer as allowed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
85 lines
3.4 KiB
TypeScript
85 lines
3.4 KiB
TypeScript
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();
|
|
});
|
|
});
|
|
|
|
/** 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);
|
|
}
|
|
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' });
|
|
});
|
|
});
|