132 lines
5.2 KiB
TypeScript
132 lines
5.2 KiB
TypeScript
import bcrypt from 'bcryptjs'
|
|
import { db } from './db'
|
|
|
|
const HOTELS = [
|
|
{ name: 'Grand Palace Hotel', slug: 'grand-palace', plan: 'pro' },
|
|
{ name: 'Marina Bay Resort', slug: 'marina-bay', plan: 'enterprise' },
|
|
{ name: 'City Center Inn', slug: 'city-inn', plan: 'starter' },
|
|
]
|
|
|
|
const ROOMS_TEMPLATE = [
|
|
{ number: '101', type: 'Standard', floor: 1, capacity: 2, price: 3500 },
|
|
{ number: '102', type: 'Standard', floor: 1, capacity: 2, price: 3500 },
|
|
{ number: '103', type: 'Deluxe', floor: 1, capacity: 3, price: 5200 },
|
|
{ number: '201', type: 'Deluxe', floor: 2, capacity: 3, price: 5200 },
|
|
{ number: '202', type: 'Suite', floor: 2, capacity: 4, price: 8900 },
|
|
{ number: '301', type: 'Suite', floor: 3, capacity: 4, price: 8900 },
|
|
{ number: '302', type: 'Junior Suite', floor: 3, capacity: 4, price: 6800 },
|
|
{ number: '401', type: 'Penthouse', floor: 4, capacity: 6, price: 18000 },
|
|
]
|
|
|
|
export async function seedIfEmpty() {
|
|
const { rows } = await db.query('SELECT count(*)::int AS c FROM hotels')
|
|
if (rows[0].c > 0) {
|
|
console.log('[seed] Data already exists, skipping')
|
|
return
|
|
}
|
|
|
|
console.log('[seed] Seeding demo data...')
|
|
const passwordHash = await bcrypt.hash('demo', 12)
|
|
|
|
for (const hotel of HOTELS) {
|
|
// Insert hotel
|
|
const { rows: [h] } = await db.query(
|
|
`INSERT INTO hotels (name, slug, plan) VALUES ($1, $2, $3) RETURNING id`,
|
|
[hotel.name, hotel.slug, hotel.plan],
|
|
)
|
|
const hotelId = h.id
|
|
|
|
// Insert rooms
|
|
for (const r of ROOMS_TEMPLATE) {
|
|
await db.query(
|
|
`INSERT INTO rooms (hotel_id, number, type, floor, capacity, price_per_night, amenities)
|
|
VALUES ($1, $2, $3, $4, $5, $6, $7)`,
|
|
[hotelId, r.number, r.type, r.floor, r.capacity, r.price,
|
|
['Wi-Fi', 'TV', 'Mini-bar']],
|
|
)
|
|
}
|
|
|
|
// Insert channels (disabled by default)
|
|
for (const name of ['booking_com', 'yandex_travel', 'ostrovok', 'sutochno', 'avito', 'bronevik', 'hotels101', 'onetwotrip']) {
|
|
await db.query(
|
|
`INSERT INTO channels (hotel_id, name) VALUES ($1, $2)`,
|
|
[hotelId, name],
|
|
)
|
|
}
|
|
}
|
|
|
|
// Super admin (no hotel)
|
|
await db.query(
|
|
`INSERT INTO users (email, password_hash, name, role, hotel_id)
|
|
VALUES ($1, $2, 'Super Admin', 'super_admin', NULL)`,
|
|
['admin@hotelsync.io', passwordHash],
|
|
)
|
|
|
|
// Grand Palace users
|
|
const { rows: [gp] } = await db.query(
|
|
`SELECT id FROM hotels WHERE slug = 'grand-palace'`,
|
|
)
|
|
await db.query(
|
|
`INSERT INTO users (email, password_hash, name, role, hotel_id) VALUES
|
|
($1, $2, 'Артём Голомазов', 'hotel_admin', $3),
|
|
($4, $2, 'Клавдия Иванова', 'housekeeper', $3)`,
|
|
['manager@grand-palace.ru', passwordHash, gp.id,
|
|
'cleaner@grand-palace.ru'],
|
|
)
|
|
|
|
// Seed a few bookings for grand-palace
|
|
const { rows: rooms } = await db.query(
|
|
`SELECT id FROM rooms WHERE hotel_id = $1 LIMIT 4`,
|
|
[gp.id],
|
|
)
|
|
const today = new Date()
|
|
const d = (offset: number) => {
|
|
const dt = new Date(today)
|
|
dt.setDate(dt.getDate() + offset)
|
|
return dt.toISOString().slice(0, 10)
|
|
}
|
|
|
|
const bookingData = [
|
|
{ room: 0, guest: 'Иван Петров', email: 'ivan@example.com', ci: d(-2), co: d(1), status: 'checked_in', src: 'direct' },
|
|
{ room: 1, guest: 'Maria Schmidt', email: 'maria@example.com', ci: d(1), co: d(4), status: 'confirmed', src: 'booking_com' },
|
|
{ room: 2, guest: 'John Smith', email: 'john@example.com', ci: d(3), co: d(7), status: 'confirmed', src: 'airbnb' },
|
|
{ room: 3, guest: 'Анна Сидорова', email: 'anna@example.com', ci: d(-5), co: d(-1), status: 'checked_out', src: 'direct' },
|
|
]
|
|
|
|
for (const b of bookingData) {
|
|
if (!rooms[b.room]) continue
|
|
const nights = (new Date(b.co).getTime() - new Date(b.ci).getTime()) / 86400000
|
|
await db.query(
|
|
`INSERT INTO bookings
|
|
(hotel_id, room_id, guest_name, guest_email, check_in, check_out, status, source, total_amount)
|
|
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)`,
|
|
[gp.id, rooms[b.room].id, b.guest, b.email, b.ci, b.co, b.status, b.src, nights * 3500],
|
|
)
|
|
}
|
|
|
|
// Seed housekeeping tasks
|
|
const taskRooms = rooms.slice(0, 3)
|
|
const { rows: [cleaner] } = await db.query(
|
|
`SELECT id FROM users WHERE email = 'cleaner@grand-palace.ru'`,
|
|
)
|
|
const taskData = [
|
|
{ r: 0, type: 'cleaning', status: 'pending', priority: 'high', notes: 'Стандартная уборка' },
|
|
{ r: 1, type: 'turnover', status: 'in_progress', priority: 'urgent', notes: 'Заезд через 2 часа' },
|
|
{ r: 2, type: 'inspection', status: 'pending', priority: 'medium', notes: 'Плановая проверка' },
|
|
]
|
|
for (const t of taskData) {
|
|
if (!taskRooms[t.r]) continue
|
|
await db.query(
|
|
`INSERT INTO housekeeping_tasks
|
|
(hotel_id, room_id, type, status, priority, assignee_id, notes, due_date)
|
|
VALUES ($1, $2, $3, $4, $5, $6, $7, $8)`,
|
|
[gp.id, taskRooms[t.r].id, t.type, t.status, t.priority, cleaner.id, t.notes, d(0)],
|
|
)
|
|
}
|
|
|
|
console.log('[seed] ✅ Demo data seeded')
|
|
console.log('[seed] admin@hotelsync.io / demo (super_admin)')
|
|
console.log('[seed] manager@grand-palace.ru / demo (hotel_admin)')
|
|
console.log('[seed] cleaner@grand-palace.ru / demo (housekeeper)')
|
|
}
|