From babd6e950e8e66964aa7fa1301879e7b1d824103 Mon Sep 17 00:00:00 2001 From: HotelSync Date: Fri, 20 Mar 2026 17:47:12 +0300 Subject: [PATCH] Fix: add passport_issued_by/issue_date to guests table for full autocomplete - Migration 014: add passport_issued_by, passport_issue_date to guests table - guests.ts: include new fields in SELECT, INSERT, PATCH + encrypt/decrypt - booking-guests.ts: sync issued_by/issue_date back to guests on update - GuestApiType: add passportIssuedBy, passportIssueDate fields - selectAcGuest: fill passport_issued_by and passport_issue_date from guest profile Co-Authored-By: Claude Sonnet 4.6 --- .../014_guests_passport_details.sql | 6 ++++ backend/src/routes/booking-guests.ts | 8 ++++-- backend/src/routes/guests.ts | 28 +++++++++++++------ .../bookings/BookingDetailPanel.tsx | 12 ++++---- src/lib/api.ts | 2 ++ 5 files changed, 39 insertions(+), 17 deletions(-) create mode 100644 backend/migrations/014_guests_passport_details.sql diff --git a/backend/migrations/014_guests_passport_details.sql b/backend/migrations/014_guests_passport_details.sql new file mode 100644 index 0000000..e32d9bf --- /dev/null +++ b/backend/migrations/014_guests_passport_details.sql @@ -0,0 +1,6 @@ +-- Migration 014: добавляем поля выдачи паспорта в таблицу guests +-- чтобы при автозаполнении по серии+номеру подтягивались все паспортные данные + +ALTER TABLE guests + ADD COLUMN IF NOT EXISTS passport_issued_by TEXT, + ADD COLUMN IF NOT EXISTS passport_issue_date TEXT; diff --git a/backend/src/routes/booking-guests.ts b/backend/src/routes/booking-guests.ts index 012fced..5b18c50 100644 --- a/backend/src/routes/booking-guests.ts +++ b/backend/src/routes/booking-guests.ts @@ -239,9 +239,11 @@ const bookingGuests: FastifyPluginAsync = async (fastify) => { } addG('first_name', b.first_name) addG('last_name', b.last_name) - if (b.passport_series !== undefined) addG('passport_series', encryptField(b.passport_series)) - if (b.passport_number !== undefined) addG('passport_number', encryptField(b.passport_number)) - if (b.birth_date !== undefined) addG('birth_date', encryptField(b.birth_date || null)) + if (b.passport_series !== undefined) addG('passport_series', encryptField(b.passport_series)) + if (b.passport_number !== undefined) addG('passport_number', encryptField(b.passport_number)) + if (b.passport_issued_by !== undefined) addG('passport_issued_by', encryptField(b.passport_issued_by)) + if (b.passport_issue_date !== undefined) addG('passport_issue_date', encryptField(b.passport_issue_date || null)) + if (b.birth_date !== undefined) addG('birth_date', encryptField(b.birth_date || null)) addG('nationality', b.nationality) // Обновляем токен в профиле гостя if (b.passport_series !== undefined || b.passport_number !== undefined) { diff --git a/backend/src/routes/guests.ts b/backend/src/routes/guests.ts index 167b1a5..884ac43 100644 --- a/backend/src/routes/guests.ts +++ b/backend/src/routes/guests.ts @@ -8,6 +8,7 @@ type SlugIdParam = { Params: { slug: string; id: string } } const GUEST_FIELDS = ` g.id, g.hotel_id, g.first_name, g.last_name, g.middle_name, g.email, g.phone, g.passport, g.passport_series, g.passport_number, + g.passport_issued_by, g.passport_issue_date, g.birth_date, g.nationality, g.gender, g.city, g.notes, g.tags, g.loyalty_tier, g.loyalty_points, g.rating, g.created_at, g.updated_at` @@ -28,10 +29,12 @@ const STATS_JOIN = ` function decryptGuest(row: Record) { return { ...row, - passport: decryptField(row.passport as string | null), - passport_series: decryptField(row.passport_series as string | null), - passport_number: decryptField(row.passport_number as string | null), - birth_date: decryptField(row.birth_date as string | null), + passport: decryptField(row.passport as string | null), + passport_series: decryptField(row.passport_series as string | null), + passport_number: decryptField(row.passport_number as string | null), + passport_issued_by: decryptField(row.passport_issued_by as string | null), + passport_issue_date: decryptField(row.passport_issue_date as string | null), + birth_date: decryptField(row.birth_date as string | null), } } @@ -129,6 +132,7 @@ const guests: FastifyPluginAsync = async (fastify) => { first_name: string; last_name: string; middle_name?: string email?: string; phone?: string passport?: string; passport_series?: string; passport_number?: string + passport_issued_by?: string; passport_issue_date?: string birth_date?: string; nationality?: string; gender?: string; city?: string notes?: string; tags?: string[]; rating?: number } }>( @@ -179,8 +183,9 @@ const guests: FastifyPluginAsync = async (fastify) => { `INSERT INTO guests (hotel_id, first_name, last_name, middle_name, email, phone, passport, passport_series, passport_number, passport_search_token, + passport_issued_by, passport_issue_date, birth_date, nationality, gender, city, notes, tags, rating) - VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15,$16,$17) + VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15,$16,$17,$18,$19) RETURNING *`, [ hotelId, b.first_name, b.last_name, b.middle_name ?? null, @@ -189,6 +194,8 @@ const guests: FastifyPluginAsync = async (fastify) => { encryptField(b.passport_series ?? null), encryptField(b.passport_number ?? null), token, + encryptField(b.passport_issued_by ?? null), + encryptField(b.passport_issue_date ?? null), encryptField(b.birth_date ?? null), b.nationality ?? null, b.gender ?? null, b.city ?? null, b.notes ?? '', b.tags ?? [], b.rating ?? 3, @@ -203,6 +210,7 @@ const guests: FastifyPluginAsync = async (fastify) => { first_name: string; last_name: string; middle_name: string email: string; phone: string passport: string; passport_series: string; passport_number: string + passport_issued_by: string; passport_issue_date: string birth_date: string; nationality: string; gender: string; city: string notes: string; tags: string[]; rating: number }> }>( @@ -237,10 +245,12 @@ const guests: FastifyPluginAsync = async (fastify) => { add('tags', b.tags) add('rating', b.rating) // Шифруем чувствительные поля - if (b.passport !== undefined) add('passport', encryptField(b.passport)) - if (b.passport_series !== undefined) add('passport_series', encryptField(b.passport_series)) - if (b.passport_number !== undefined) add('passport_number', encryptField(b.passport_number)) - if (b.birth_date !== undefined) add('birth_date', encryptField(b.birth_date || null)) + if (b.passport !== undefined) add('passport', encryptField(b.passport)) + if (b.passport_series !== undefined) add('passport_series', encryptField(b.passport_series)) + if (b.passport_number !== undefined) add('passport_number', encryptField(b.passport_number)) + if (b.passport_issued_by !== undefined) add('passport_issued_by', encryptField(b.passport_issued_by)) + if (b.passport_issue_date !== undefined) add('passport_issue_date', encryptField(b.passport_issue_date || null)) + if (b.birth_date !== undefined) add('birth_date', encryptField(b.birth_date || null)) // Обновляем токен если поменялся паспорт if (b.passport_series !== undefined || b.passport_number !== undefined) { // Читаем текущие значения если нужно diff --git a/src/components/bookings/BookingDetailPanel.tsx b/src/components/bookings/BookingDetailPanel.tsx index e8552c0..dd5b132 100644 --- a/src/components/bookings/BookingDetailPanel.tsx +++ b/src/components/bookings/BookingDetailPanel.tsx @@ -141,11 +141,13 @@ export function BookingDetailPanel({ booking, room, rooms, allBookings, slug, on ...f, first_name: g.firstName, last_name: g.lastName, - middle_name: g.middleName ?? undefined, - birth_date: g.birthDate ?? undefined, - passport_series: g.passportSeries ?? undefined, - passport_number: g.passportNumber ?? undefined, - nationality: g.nationality ?? undefined, + middle_name: g.middleName ?? undefined, + birth_date: g.birthDate ?? undefined, + passport_series: g.passportSeries ?? undefined, + passport_number: g.passportNumber ?? undefined, + passport_issued_by: g.passportIssuedBy ?? undefined, + passport_issue_date: g.passportIssueDate ?? undefined, + nationality: g.nationality ?? undefined, })) setAcQuery(g.lastName) setAcResults([]) diff --git a/src/lib/api.ts b/src/lib/api.ts index 52dc69c..fe439c9 100644 --- a/src/lib/api.ts +++ b/src/lib/api.ts @@ -469,6 +469,8 @@ export interface GuestApiType { passport: string | null passportSeries: string | null passportNumber: string | null + passportIssuedBy: string | null + passportIssueDate: string | null birthDate: string | null nationality: string | null gender: string | null