378 lines
13 KiB
TypeScript
378 lines
13 KiB
TypeScript
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<ReturnType<typeof getPayload>>, 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<ReturnType<typeof getPayload>>) {
|
||
const adapter = payload.db as {
|
||
drizzle: { execute: (query: unknown) => Promise<unknown> }
|
||
}
|
||
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<string, string | number> = {}
|
||
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<string, string | number> = {}
|
||
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<string, string | number> = {}
|
||
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)
|
||
})
|