Files
2026-10-25 22:55:29 +04:00

104 lines
8.5 KiB
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* Локальная разработка: демо-данные для двух сценариев клиентского приложения.
* pnpm --filter @barev/api dev:demo
* Анна — переезжает (план «под ключ» с шагами, документы, переписка с консьержем),
* John — живёт в Армении с Barev+, 李明 — с Elite, Ольга — живёт без подписки; партнёры клуба.
* Повторный запуск пересоздаёт демо-состояние этих клиентов.
*/
import { getDb } from '@barev/db';
import { acceptPartnerInvite, createAppLead, createOwnerInvite, createStaffInvite, grantSubscription, savePartnerOffer, startClient, giveConsent, type Ctx } from '@barev/services';
import { env } from '../src/env.ts';
if (env.isProd) throw new Error('Только для разработки');
const db = getDb();
const ctx: Ctx = { db, notify: { emit: () => {} }, now: () => new Date() };
const DAY = 24 * 3600_000;
async function client(id: number, firstName: string, lang: string, username?: string) {
const res = await startClient(ctx, { id, first_name: firstName, language_code: lang, username });
const c = await db.client.findUniqueOrThrow({ where: { id: res.clientId } });
if (!c.consentAt) await giveConsent(ctx, c.id);
// чистое демо-состояние
await db.lead.deleteMany({ where: { clientId: c.id } });
await db.clientRequest.deleteMany({ where: { clientId: c.id } });
await db.conciergeMessage.deleteMany({ where: { clientId: c.id } });
await db.subscription.deleteMany({ where: { clientId: c.id, source: 'MANUAL' } });
return c.id;
}
const anna = await client(100000001, 'Анна', 'ru', 'anna_moves');
await db.client.update({ where: { id: anna }, data: { segment: 'MOVING' } });
const moveDate = new Date(Date.now() + 40 * DAY).toISOString().slice(0, 10);
const lead = await createAppLead(ctx, anna, { moveWhen: 'date', moveDate: new Date(`${moveDate}T00:00:00Z`), package: 'TURNKEY', comment: 'Двое взрослых и кот' });
const notes: Record<string, { status: 'DONE' | 'IN_PROGRESS'; note?: string }> = {
airport: { status: 'DONE', note: 'Водитель Арам встретит с табличкой, +374 91 000 000' },
stay: { status: 'DONE', note: 'Отель Republica, 5 ночей, завтрак включён' },
flat: { status: 'IN_PROGRESS', note: 'Подобрали 3 варианта в Кентроне, просмотры в среду с 15:00' },
};
for (const s of lead.steps) if (notes[s.code]) await db.leadStep.update({ where: { id: s.id }, data: notes[s.code]! });
await db.lead.update({ where: { id: lead.id }, data: { status: 'IN_WORK' } });
await db.leadDoc.updateMany({ where: { leadId: lead.id, code: { in: ['passport', 'passportCopies', 'photos'] } }, data: { checked: true } });
const admin = await db.adminUser.findFirst();
const msgs: [string, 'CLIENT' | 'OPERATOR', number][] = [
['Здравствуйте! Можно ли взять кота в отель?', 'CLIENT', 50],
['Добрый день! Да, в Republica можно с животными, предупредили отель 🐈', 'OPERATOR', 45],
['Спасибо! А что с апостилем на дипломе — делать до переезда?', 'CLIENT', 5],
];
for (const [text, author, minAgo] of msgs) {
await db.conciergeMessage.create({
data: { clientId: anna, author, text, adminUserId: author === 'OPERATOR' ? admin?.id : undefined, readAt: minAgo > 10 ? new Date() : null, createdAt: new Date(Date.now() - minAgo * 60_000) },
});
}
const john = await client(100000002, 'John', 'en', 'john_yerevan');
await db.client.update({ where: { id: john }, data: { segment: 'LIVING' } });
await grantSubscription(ctx, { clientId: john, plan: 'BAREV_PLUS', days: 30 });
await db.clientRequest.create({ data: { clientId: john, kind: 'SERVICE', serviceCode: 'repair', comment: 'Kitchen tap is leaking, after 6 pm please' } });
await db.conciergeMessage.create({ data: { clientId: john, author: 'CLIENT', text: 'Hi! Can you recommend an English-speaking dentist?' } });
const li = await client(100000003, '李明', 'zh', 'li_ming');
await db.client.update({ where: { id: li }, data: { segment: 'LIVING' } });
await grantSubscription(ctx, { clientId: li, plan: 'ELITE', days: 30 });
const olga = await client(100000004, 'Ольга', 'ru', 'olga_local');
await db.client.update({ where: { id: olga }, data: { segment: 'LIVING' } });
await db.clientRequest.create({ data: { clientId: olga, kind: 'SUBSCRIPTION', plan: 'ELITE' } });
// новый клиент — увидит выбор сценария при первом входе
await db.client.updateMany({ where: { user: { telegramId: 100000099n } }, data: { segment: null } });
if ((await db.partner.count()) === 0) {
const offer = (ru: string, en: string, zh: string, hy: string, es: string) => ({ ru, en, zh, hy, es });
await db.partner.createMany({
data: [
{ category: 'cafe', name: 'Lumen Coffee', address: 'Ереван, ул. Абовяна 18', offer: offer('−15% на кофе и завтраки', '−15% on coffee and breakfast', '咖啡和早餐 −15%', '−15% սուրճի և նախաճաշի համար', '−15% en café y desayunos') },
{ category: 'restaurant', name: 'Dolmama', address: 'Ереван, ул. Пушкина 10', offer: offer('Десерт в подарок к ужину', 'Free dessert with dinner', '晚餐赠送甜点', 'Աղանդեր նվեր ընթրիքին', 'Postre de regalo con la cena') },
{ category: 'restaurant', name: 'Lavash', address: 'Ереван, ул. Туманяна 21', offer: offer('−10% на всё меню', '−10% on the whole menu', '全部菜单 −10%', '−10% ամբողջ մենյուի համար', '−10% en toda la carta') },
{ category: 'shop', name: 'Gum Market', address: 'Ереван, ул. Московяна 35', offer: offer('Подарочный набор специй', 'Free spice gift set', '赠送香料礼盒', 'Համեմունքների նվեր հավաքածու', 'Set de especias de regalo') },
{ category: 'beauty', name: 'Barber Yerevan', address: 'Ереван, пр. Маштоца 7', offer: offer('−20% на первую стрижку', '−20% on the first haircut', '首次理发 −20%', '−20% առաջին սանրվածքի համար', '−20% en el primer corte') },
],
});
}
// предложения партнёров по уровням и лимитам; Арам — собственник Lumen Coffee, Гаяне — сотрудник
const lumen =
(await db.partner.findFirst({ where: { name: 'Lumen Coffee' } })) ??
(await db.partner.create({ data: { category: 'cafe', name: 'Lumen Coffee', address: 'Ереван, ул. Абовяна 18', offer: { ru: 'Кофейня у Каскада', en: 'Café near the Cascade', zh: '', hy: '', es: '' } } }));
if (lumen && (await db.partnerOffer.count({ where: { partnerId: lumen.id } })) === 0) {
const L = (ru: string, en: string) => ({ ru, en, zh: '', hy: '', es: '' });
await savePartnerOffer(ctx, { partnerId: lumen.id, title: L('−10% на кофе и завтраки', '−10% on coffee and breakfast'), minLevel: null, limit: 'NONE', limitCount: 1, active: true });
await savePartnerOffer(ctx, { partnerId: lumen.id, title: L('Десерт на первый визит', 'Dessert on the first visit'), minLevel: null, limit: 'ONCE', limitCount: 1, active: true });
await savePartnerOffer(ctx, { partnerId: lumen.id, title: L('Кофе в подарок', 'Free coffee'), minLevel: 'BAREV_PLUS', limit: 'WEEK', limitCount: 1, active: true });
await savePartnerOffer(ctx, { partnerId: lumen.id, title: L('Завтрак для двоих', 'Breakfast for two'), minLevel: 'ELITE', limit: 'MONTH', limitCount: 2, active: true });
}
if (lumen && (await db.partnerMember.count({ where: { partnerId: lumen.id } })) === 0) {
const { url } = await createOwnerInvite(ctx, lumen.id);
await acceptPartnerInvite(ctx, { id: 300000010, first_name: 'Арам', language_code: 'ru' }, url.split('start=')[1]!);
const staff = await createStaffInvite(ctx, 300000010n, lumen.id);
await acceptPartnerInvite(ctx, { id: 300000011, first_name: 'Гаяне', language_code: 'ru' }, staff.url.split('start=')[1]!);
}
console.log('Демо готово: Анна — переезд, John — Barev+, 李明 — Elite, Ольга — без подписки, «Новый клиент» — выбор сценария.');
await db.$disconnect();