import { Prisma } from '@prisma/client'; import { AdminUsersService } from './admin-users.service'; /** * Editing a sales expert in the panel must reach the app: the app shows the * expert their own account through the linked trading Customer row, which is * only seeded once at first sign-in. */ describe('AdminUsersService — expert edit reaches the trading account', () => { const expertRow = { id: 'exp1', role: 'SALES_EXPERT', fullName: 'سعید اسماعیلی', firstName: 'سعید', lastName: 'اسماعیلی', mobile: '09902560722', wagePercent: new Prisma.Decimal(12), isActive: true, salesExpertProfile: { tradingCustomerId: 'cust1', gramLevel: new Prisma.Decimal(0) }, }; function build(customerHolder: { id: string } | null = null) { const customerUpdate = jest.fn(async () => ({})); const tx = { adminUser: { update: jest.fn(async ({ data }: { data: Record }) => ({ ...expertRow, ...(data.firstName !== undefined ? { firstName: data.firstName, fullName: `${data.firstName} ${data.lastName}` } : {}), ...(data.lastName !== undefined ? { lastName: data.lastName } : {}), ...(data.mobile !== undefined ? { mobile: data.mobile } : {}), ...(data.wagePercent !== undefined ? { wagePercent: data.wagePercent } : {}), salesExpertProfile: { ...expertRow.salesExpertProfile, ...((data.salesExpertProfile as { upsert?: { update?: { gramLevel?: Prisma.Decimal } } } | undefined) ?.upsert?.update?.gramLevel !== undefined ? { gramLevel: (data.salesExpertProfile as { upsert: { update: { gramLevel: Prisma.Decimal } } }).upsert.update.gramLevel } : {}), }, })), }, customer: { update: customerUpdate, findUnique: jest.fn(async () => customerHolder), // the cross-table check: does a customer (not the expert's own account) hold the number findFirst: jest.fn(async () => customerHolder), }, }; const prisma = { ...tx, admin: { findUnique: jest.fn(async () => null) }, adminUser: { ...tx.adminUser, findFirst: jest.fn(async () => expertRow), // the expert-table mobile clash check: no other expert holds the number findUnique: jest.fn(async () => null), }, $transaction: jest.fn(async (fn: (t: typeof tx) => unknown) => fn(tx)), }; const service = new AdminUsersService(prisma as never, {} as never, {} as never); return { service, customerUpdate }; } it('copies a name change to the trading account', async () => { const { service, customerUpdate } = build(); await service.update('exp1', { fname: 'سعید1', lname: 'اسماعیلی1' }); expect(customerUpdate).toHaveBeenCalledWith({ where: { id: 'cust1' }, data: { firstName: 'سعید1', lastName: 'اسماعیلی1' }, }); }); it('copies the credit limit and wage percent the operator changed', async () => { const { service, customerUpdate } = build(); await service.update('exp1', { gram_level: '50', percent: '3' }); const data = (customerUpdate.mock.calls[0] as unknown as [{ data: Record }])[0].data; expect(data.goldCreditLimitGrams.toString()).toBe('50'); expect(data.makingChargeOffsetPercent.toString()).toBe('3'); expect(data).not.toHaveProperty('firstName'); }); it('copies a new mobile only when no other customer holds it', async () => { const free = build(null); await free.service.update('exp1', { mobile: '09120001111' }); expect(free.customerUpdate).toHaveBeenCalledWith({ where: { id: 'cust1' }, data: { mobile: '09120001111' } }); }); it('refuses a new mobile a customer already holds, and writes nothing', async () => { const taken = build({ id: 'someone-else' }); await expect(taken.service.update('exp1', { mobile: '09120001111' })).rejects.toThrow( 'این شماره موبایل قبلاً برای یک مشتری ثبت شده است', ); expect(taken.customerUpdate).not.toHaveBeenCalled(); }); it('does not ask about a mobile that is not changing, so an existing duplicate stays editable', async () => { const { service, customerUpdate } = build({ id: 'someone-else' }); await expect(service.update('exp1', { mobile: '09902560722', fname: 'سعید1', lname: 'اسماعیلی1' })).resolves.toBeDefined(); expect(customerUpdate).toHaveBeenCalledWith({ where: { id: 'cust1' }, data: { firstName: 'سعید1', lastName: 'اسماعیلی1' }, }); }); it('refuses to create an expert on a number a customer holds', async () => { const { service } = build({ id: 'someone-else' }); await expect( service.create({ fname: 'علی', lname: 'رضایی', mobile: '09125550000', password: 'secret1', role: 'SALES_EXPERT' }), ).rejects.toThrow('این شماره موبایل قبلاً برای یک مشتری ثبت شده است'); }); it('writes nothing to the trading account when nothing it mirrors changed', async () => { const { service, customerUpdate } = build(); await service.update('exp1', { address: 'تهران' }); expect(customerUpdate).not.toHaveBeenCalled(); }); });