import { afterAll, beforeEach, describe, expect, it } from 'vitest'; import { createOrder, editOrderComposition, giveConsent, markPaid, previewOrderEdit, staffChecklistItem, startClient, transitionOrder } from '../src/index.ts'; import { db, fixtures, makeCtx, NOW, slotAt, tgUser } from './helpers.ts'; let fx: Awaited>; beforeEach(async () => { fx = await fixtures(); }); afterAll(() => db.$disconnect()); async function order(ctx: ReturnType['ctx'], tg: number) { const s = await startClient(ctx, tgUser(tg)); await giveConsent(ctx, s.clientId); return createOrder(ctx, { clientId: s.clientId, serviceCode: 'cleaning', params: { cleaningType: 'regular', rooms: 2, bathrooms: 1 }, scheduledAt: slotAt(2, 11), addressText: 'Pushkin 10', districtId: fx.kentron.id }); } const admin = () => db.adminUser.create({ data: { name: 'Op', roles: ['SUPPORT'] } }); describe('команда меняет заказ', () => { it('состав: пересчёт цены и длительности, история, уведомление по галочке', async () => { const { ctx, events } = makeCtx(NOW); const o = await order(ctx, 1501); const op = await admin(); const p = await previewOrderEdit(ctx, { orderId: o.id, params: { cleaningType: 'regular', rooms: 3, bathrooms: 1, extras: { windows: 2 } } }); expect(p.totalPrice).toBeGreaterThan(o.totalPrice); expect(p.durationMinutes).toBeGreaterThan(o.durationMinutes); await editOrderComposition(ctx, { orderId: o.id, adminId: op.id, params: p.params, notify: true }); const after = await db.order.findUniqueOrThrow({ where: { id: o.id } }); expect(after).toMatchObject({ totalPrice: p.totalPrice, durationMinutes: p.durationMinutes }); expect((after.params as Record).rooms).toBe(3); expect(events).toContainEqual({ type: 'order.edited', orderId: o.id }); expect(await db.orderStatusHistory.count({ where: { orderId: o.id, event: 'editedByStaff' } })).toBe(1); }); it('своя цена — только с причиной', async () => { const { ctx } = makeCtx(NOW); const o = await order(ctx, 1502); const op = await admin(); await expect(editOrderComposition(ctx, { orderId: o.id, adminId: op.id, params: { cleaningType: 'regular', rooms: 2, bathrooms: 1 }, totalPrice: 12_345 })).rejects.toMatchObject({ code: 'REASON_REQUIRED' }); await editOrderComposition(ctx, { orderId: o.id, adminId: op.id, params: { cleaningType: 'regular', rooms: 2, bathrooms: 1 }, totalPrice: 12_345, reason: 'договорились' }); expect((await db.order.findUniqueOrThrow({ where: { id: o.id } })).totalPrice).toBe(12_345); }); it('после оплаты: кэшбек пересчитывается по новой цене', async () => { const { ctx } = makeCtx(NOW); const o = await order(ctx, 1503); const op = await admin(); await db.order.update({ where: { id: o.id }, data: { status: 'CLEANING', providerId: fx.maria.id } }); await db.orderChecklistItem.updateMany({ where: { orderId: o.id }, data: { checkedAt: NOW, requiresPhoto: false } }); await transitionOrder(ctx, { orderId: o.id, to: 'DONE', actor: 'ADMIN' }); await markPaid(ctx, { orderId: o.id, by: { type: 'ADMIN', id: op.id } }); const before = await db.pointsAccrual.findFirstOrThrow({ where: { orderId: o.id, status: { not: 'REVERSED' } } }); await editOrderComposition(ctx, { orderId: o.id, adminId: op.id, params: { cleaningType: 'regular', rooms: 4, bathrooms: 2 } }); const now = await db.pointsAccrual.findFirstOrThrow({ where: { orderId: o.id, status: { not: 'REVERSED' } } }); expect(now.id).not.toBe(before.id); expect(now.amount).toBeGreaterThan(before.amount); }); it('чек-лист за клинера: пункт с фото — без фото только с причиной; потом заказ можно закрыть', async () => { const { ctx } = makeCtx(NOW); const o = await order(ctx, 1504); const op = await admin(); await db.order.update({ where: { id: o.id }, data: { status: 'CLEANING', providerId: fx.maria.id } }); const items = await db.orderChecklistItem.findMany({ where: { orderId: o.id } }); const photo = items.find((i) => i.requiresPhoto)!; await expect(staffChecklistItem(ctx, { orderId: o.id, adminId: op.id, code: photo.code, checked: true })).rejects.toMatchObject({ code: 'PHOTO_REQUIRED' }); for (const i of items) await staffChecklistItem(ctx, { orderId: o.id, adminId: op.id, code: i.code, checked: true, reason: i.requiresPhoto ? 'фото в чате' : null }); await transitionOrder(ctx, { orderId: o.id, to: 'DONE', actor: 'ADMIN' }); expect((await db.order.findUniqueOrThrow({ where: { id: o.id } })).status).toBe('DONE'); }); });