import { afterAll, beforeEach, describe, expect, it } from 'vitest'; import { createT } from '@barev/i18n'; import { createOrder, DomainError, giveConsent, grantSubscription, loadTextOverrides, quoteForClient, startClient } from '../src/index.ts'; import { db, fixtures, makeCtx, NOW, slotAt, tgUser } from './helpers.ts'; let fx: Awaited>; beforeEach(async () => { fx = await fixtures(); }); afterAll(async () => { await db.textOverride.deleteMany({}); await loadTextOverrides(db); await db.$disconnect(); }); const code = (p: Promise) => p.then(() => 'OK', (e) => (e instanceof DomainError ? e.code : String(e))); const params = { cleaningType: 'regular', rooms: 2 }; async function client(ctx: ReturnType['ctx'], tg: number) { const s = await startClient(ctx, tgUser(tg)); await giveConsent(ctx, s.clientId); return s.clientId; } describe('промокоды', () => { it('скидка по коду; один раз на клиента; не складывается с подпиской — берётся большая', async () => { const { ctx } = makeCtx(NOW); await db.promoCode.create({ data: { code: 'AUTUMN20', kind: 'DISCOUNT', discountPct: 20 } }); await db.promoCode.create({ data: { code: 'SMALL5', kind: 'DISCOUNT', discountPct: 5 } }); const c = await client(ctx, 901); const q = await quoteForClient(ctx, c, 'cleaning', params, 'autumn20'); expect(q.quote).toMatchObject({ basePrice: 19000, discountPct: 20, totalPrice: 15200 }); expect(q.promo?.code).toBe('AUTUMN20'); const o = await createOrder(ctx, { clientId: c, serviceCode: 'cleaning', params, scheduledAt: slotAt(2, 11), addressText: 'Pushkin 10', districtId: fx.kentron.id, promoCode: 'AUTUMN20' }); expect(o.totalPrice).toBe(15200); expect((await db.promoCode.findUniqueOrThrow({ where: { code: 'AUTUMN20' } })).usedCount).toBe(1); expect(await code(quoteForClient(ctx, c, 'cleaning', params, 'AUTUMN20'))).toBe('PROMO_USED'); // подписчик со скидкой 10%: код на 5% не нужен — остаётся скидка подписки, код не тратится const member = await client(ctx, 902); await grantSubscription(ctx, { clientId: member, plan: 'BAREV_PLUS', days: 30 }); const m = await quoteForClient(ctx, member, 'cleaning', params, 'SMALL5'); expect(m.quote.discountPct).toBe(10); expect(m.promo).toBeNull(); }); it('выключен, истёк, исчерпан или не для этого направления — понятная ошибка', async () => { const { ctx } = makeCtx(NOW); const c = await client(ctx, 903); await db.promoCode.create({ data: { code: 'OFF', kind: 'DISCOUNT', discountPct: 10, active: false } }); await db.promoCode.create({ data: { code: 'OLD', kind: 'DISCOUNT', discountPct: 10, validUntil: new Date(NOW.getTime() - 1000) } }); await db.promoCode.create({ data: { code: 'FULL', kind: 'DISCOUNT', discountPct: 10, maxUses: 1, usedCount: 1 } }); await db.promoCode.create({ data: { code: 'DOCSONLY', kind: 'DISCOUNT', discountPct: 10, categories: ['DOCS'] } }); expect(await code(quoteForClient(ctx, c, 'cleaning', params, 'NOPE'))).toBe('PROMO_INVALID'); expect(await code(quoteForClient(ctx, c, 'cleaning', params, 'OFF'))).toBe('PROMO_INVALID'); expect(await code(quoteForClient(ctx, c, 'cleaning', params, 'OLD'))).toBe('PROMO_EXPIRED'); expect(await code(quoteForClient(ctx, c, 'cleaning', params, 'FULL'))).toBe('PROMO_EXPIRED'); expect(await code(quoteForClient(ctx, c, 'cleaning', params, 'DOCSONLY'))).toBe('PROMO_NOT_FOR_SERVICE'); }); }); describe('тексты из админки', () => { it('правка подменяет стандартный текст, свой перевод языка важнее русской правки', async () => { const before = createT('ru')('services.cleaning.name'); await db.textOverride.create({ data: { key: 'services.cleaning.name', locale: 'ru', value: 'Уборка квартиры' } }); await db.textOverride.create({ data: { key: 'services.cleaning.name', locale: 'hy', value: 'Բնակարանի մաքրում' } }); await loadTextOverrides(db); expect(createT('ru')('services.cleaning.name')).toBe('Уборка квартиры'); expect(createT('hy')('services.cleaning.name')).toBe('Բնակարանի մաքրում'); // у английского свой перевод — русская правка его не трогает expect(createT('en')('services.cleaning.name')).not.toBe('Уборка квартиры'); await db.textOverride.deleteMany({}); await loadTextOverrides(db); expect(createT('ru')('services.cleaning.name')).toBe(before); }); });