import 'dotenv/config' import { getPayload } from 'payload' import { paidDoctors } from './paid-doctors' import { seedPromotions } from './import-promotions' import { seedReviews } from './import-reviews' import config from '../payload.config' const translations = { ru: { branchMain: 'КДЦ МОНИКИ (основной)', branchReutov: 'Филиал КДЦ МОНИКИ в г. Реутов', addrMain: 'г. Москва, ул. Щепкина, 61/2. Станция метро «Проспект Мира», выход к спорткомплексу «Олимпийский».', addrReutov: 'Московская область, г. Реутов, проспект Мира, д. 53', howMain: 'От метро «Проспект Мира» пешком по улице Щепкина до корпуса института.', howReutov: 'Московская область, г. Реутов, проспект Мира, д. 53. Удобно доехать наземным транспортом от метро «Новокосино» и от станции Реутов.', }, en: { branchMain: 'MONIKI CDC (main)', branchReutov: 'MONIKI CDC branch in Reutov', addrMain: 'Moscow, Shchepkina St., 61/2. Prospect Mira metro station.', addrReutov: 'Moscow Region, Reutov, Prospekt Mira, 53', howMain: 'From Prospect Mira metro walk along Shchepkina Street to the institute campus.', howReutov: 'Moscow Region, Reutov, Prospekt Mira, 53. Convenient by surface transport from Novokosino metro and Reutov station.', }, } async function findOne(payload: Awaited>, collection: 'branches' | 'specialties' | 'services' | 'doctors' | 'users' | 'posts', slugOrEmail: string) { const field = collection === 'users' ? 'email' : 'slug' const res = await payload.find({ collection, where: { [field]: { equals: slugOrEmail } }, limit: 1, }) return res.docs[0] } async function ensureBranchesSchema(payload: Awaited>) { const adapter = payload.db as { drizzle: { execute: (query: unknown) => Promise } } const { sql } = await import('@payloadcms/db-postgres') await adapter.drizzle.execute(sql` ALTER TABLE branches ADD COLUMN IF NOT EXISTS sort_order numeric DEFAULT 100 `) await adapter.drizzle.execute(sql` UPDATE branches SET sort_order = 10, is_main = true, lat = 55.786637, lng = 37.627265 WHERE slug = 'kdc-moniki' `) await adapter.drizzle.execute(sql` UPDATE branches SET sort_order = 20, is_main = false, lat = 55.771049, lng = 37.862507 WHERE slug = 'kdc-reutov' `) await adapter.drizzle.execute(sql` UPDATE branches_locales SET name = 'КДЦ МОНИКИ (основной)', address = 'г. Москва, ул. Щепкина, 61/2. Станция метро «Проспект Мира», выход к спорткомплексу «Олимпийский».', city = 'Москва', metro = 'Проспект Мира', how_to_get = 'От метро «Проспект Мира» пешком по улице Щепкина до корпуса института.' WHERE _locale = 'ru' AND _parent_id IN (SELECT id FROM branches WHERE slug = 'kdc-moniki') `) await adapter.drizzle.execute(sql` UPDATE branches_locales SET name = 'Филиал КДЦ МОНИКИ в г. Реутов', address = 'Московская область, г. Реутов, проспект Мира, д. 53', city = 'Реутов', how_to_get = 'Московская область, г. Реутов, проспект Мира, д. 53. Удобно доехать наземным транспортом от метро «Новокосино» и от станции Реутов.' WHERE _locale = 'ru' AND _parent_id IN (SELECT id FROM branches WHERE slug = 'kdc-reutov') `) await adapter.drizzle.execute(sql` UPDATE branches_locales SET name = 'MONIKI CDC (main)', address = 'Moscow, Shchepkina St., 61/2. Prospect Mira metro station.', city = 'Moscow', metro = 'Prospect Mira', how_to_get = 'From Prospect Mira metro walk along Shchepkina Street to the institute campus.' WHERE _locale = 'en' AND _parent_id IN (SELECT id FROM branches WHERE slug = 'kdc-moniki') `) await adapter.drizzle.execute(sql` UPDATE branches_locales SET name = 'MONIKI CDC branch in Reutov', address = 'Moscow Region, Reutov, Prospekt Mira, 53', city = 'Reutov', how_to_get = 'Moscow Region, Reutov, Prospekt Mira, 53. Convenient by surface transport from Novokosino metro and Reutov station.' WHERE _locale = 'en' AND _parent_id IN (SELECT id FROM branches WHERE slug = 'kdc-reutov') `) } async function seed() { const payload = await getPayload({ config }) await ensureBranchesSchema(payload) console.log('Seeding MONIKI demo data...') const adminEmail = 'admin@moniki.local' const existingAdmin = await payload.find({ collection: 'users', where: { email: { equals: adminEmail } }, limit: 1, }) if (!existingAdmin.docs.length) { await payload.create({ collection: 'users', data: { email: adminEmail, password: 'Admin123!', fullName: 'Администратор МОНИКИ', role: 'admin', phone: '+7 (499) 674-07-09', }, }) } const patientEmail = 'patient@demo.local' const existingPatient = await payload.find({ collection: 'users', where: { email: { equals: patientEmail } }, limit: 1, }) if (!existingPatient.docs.length) { await payload.create({ collection: 'users', data: { email: patientEmail, password: 'Patient123!', fullName: 'Иванова Анна Сергеевна', role: 'patient', phone: '+7 (900) 123-45-67', smsOptIn: true, }, }) } let branchMain = await findOne(payload, 'branches', 'kdc-moniki') if (!branchMain) { branchMain = await payload.create({ collection: 'branches', locale: 'ru', data: { name: translations.ru.branchMain, slug: 'kdc-moniki', address: translations.ru.addrMain, city: 'Москва', phone: '+7 (499) 674-07-09', email: 'mail@monikiweb.ru', metro: 'Проспект Мира', howToGet: translations.ru.howMain, isMain: true, sortOrder: 10, lat: 55.786637, lng: 37.627265, workHours: [ { day: 'Пн–Сб', hours: '08:00–20:00' }, { day: 'Вс', hours: '09:00–16:00' }, ], }, }) } let branchReutov = await findOne(payload, 'branches', 'kdc-reutov') if (!branchReutov) { branchReutov = await payload.create({ collection: 'branches', locale: 'ru', data: { name: translations.ru.branchReutov, slug: 'kdc-reutov', address: translations.ru.addrReutov, city: 'Реутов', phone: '+7 (499) 674-07-09', howToGet: translations.ru.howReutov, isMain: false, sortOrder: 20, lat: 55.771049, lng: 37.862507, workHours: [{ day: 'Пн–Сб', hours: '08:00–20:00' }], }, }) } const specialtyDefs = [ { title: 'Терапия', slug: 'therapy', icon: 'heart' }, { title: 'Кардиология', slug: 'cardiology', icon: 'activity' }, { title: 'Неврология', slug: 'neurology', icon: 'cpu-chip' }, { title: 'Гастроэнтерология', slug: 'gastro', icon: 'beaker' }, { title: 'Эндокринология', slug: 'endo', icon: 'flash' }, { title: 'Диагностика', slug: 'diagnostics', icon: 'scan' }, ] const specialties: Record = {} for (const [i, s] of specialtyDefs.entries()) { let doc = await findOne(payload, 'specialties', s.slug) if (!doc) { doc = await payload.create({ collection: 'specialties', locale: 'ru', data: { title: s.title, slug: s.slug, description: `Платные услуги направления «${s.title}» в МОНИКИ`, icon: s.icon, sortOrder: i, }, }) } specialties[s.slug] = doc.id await payload.update({ collection: 'specialties', id: doc.id, locale: 'en', data: { title: s.slug.charAt(0).toUpperCase() + s.slug.slice(1), description: `Paid ${s.slug} services at MONIKI`, }, }) } const serviceDefs = [ { title: 'Консультация терапевта', slug: 'consult-therapy', price: 3500, durationMinutes: 30, specialty: 'therapy', category: 'consultation' as const, isPopular: true, }, { title: 'Консультация кардиолога', slug: 'consult-cardio', price: 4500, durationMinutes: 40, specialty: 'cardiology', category: 'consultation' as const, isPopular: true, }, { title: 'Консультация невролога', slug: 'consult-neuro', price: 4200, durationMinutes: 40, specialty: 'neurology', category: 'consultation' as const, isPopular: false, }, { title: 'УЗИ органов брюшной полости', slug: 'uzi-abdomen', price: 3200, durationMinutes: 30, specialty: 'diagnostics', category: 'diagnostics' as const, isPopular: true, }, { title: 'ЭКГ с расшифровкой', slug: 'ecg', price: 1800, durationMinutes: 20, specialty: 'cardiology', category: 'diagnostics' as const, isPopular: true, }, { title: 'Комплексное обследование «Чек-ап»', slug: 'checkup', price: 18900, durationMinutes: 120, specialty: 'diagnostics', category: 'package' as const, isPopular: true, }, ] const services: Record = {} for (const s of serviceDefs) { let doc = await findOne(payload, 'services', s.slug) if (!doc) { doc = await payload.create({ collection: 'services', locale: 'ru', data: { title: s.title, slug: s.slug, description: `${s.title} в платных отделениях МОНИКИ. Полная оплата через СБП.`, price: s.price, durationMinutes: s.durationMinutes, specialty: specialties[s.specialty], category: s.category, branches: [branchMain.id, branchReutov.id], isPopular: s.isPopular, isPublished: true, }, }) } services[s.slug] = doc.id } const doctors: Record = {} for (const d of paidDoctors) { let doc = await findOne(payload, 'doctors', d.slug) if (!doc) { doc = await payload.create({ collection: 'doctors', locale: 'ru', data: { fullName: d.fullName, slug: d.slug, position: [d.position, d.specialty] .filter((value, index, arr) => value && arr.indexOf(value) === index) .join(' · '), degree: d.degree || undefined, experienceYears: d.experienceYears, bio: d.bio, photoUrl: d.photo, photoPending: d.photoPending, specialties: d.specialtySlugs.map((s) => specialties[s]).filter(Boolean), branches: [branchMain.id], education: d.education.map((item) => ({ item })), defaultSlotMinutes: d.defaultSlotMinutes, isPublished: true, rating: 0, reviewsCount: 0, }, }) await payload.create({ collection: 'schedules', data: { title: `Расписание: ${d.fullName}`, doctor: doc.id, branch: branchMain.id, slotMinutes: d.defaultSlotMinutes, isActive: true, weekdays: [ { day: '1', startTime: '09:00', endTime: '14:00' }, { day: '2', startTime: '09:00', endTime: '14:00' }, { day: '3', startTime: '14:00', endTime: '19:00' }, { day: '4', startTime: '09:00', endTime: '14:00' }, { day: '5', startTime: '09:00', endTime: '13:00' }, ], }, }) } doctors[d.slug] = doc.id } const existingReviews = await payload.find({ collection: 'reviews', limit: 1 }) if (!existingReviews.docs.length) { await seedReviews(payload) } await seedPromotions(payload) console.log('Seed complete.') console.log('Admin: admin@moniki.local / Admin123!') console.log('Patient: patient@demo.local / Patient123!') process.exit(0) } seed().catch((err) => { console.error(err) process.exit(1) })