From d0b4052c5da7feb23d885ccd892d7e0875504ee2 Mon Sep 17 00:00:00 2001 From: Maurice Date: Thu, 25 Jun 2026 23:56:21 +0200 Subject: [PATCH] fix(import): create linked costs and accommodations from reviewed bookings Reviewing an imported booking saves it through the normal reservation form, which dropped the parsed price (so no linked cost was created) and only created the accommodation when both nights matched a trip day. Carry the parsed price into a linked cost on save, and create the accommodation from whichever day the check-in/out dates resolve to. --- .../src/components/Planner/ReservationModal.tsx | 17 ++++++++++++++--- .../src/components/Planner/TransportModal.tsx | 9 +++++++++ 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/client/src/components/Planner/ReservationModal.tsx b/client/src/components/Planner/ReservationModal.tsx index 4d320f832..50e39e123 100644 --- a/client/src/components/Planner/ReservationModal.tsx +++ b/client/src/components/Planner/ReservationModal.tsx @@ -257,7 +257,7 @@ export function ReservationModal({ isOpen, onClose, onSave, reservation, days, p endpoints: [], needs_review: false, } - if (form.type === 'hotel' && form.hotel_start_day && form.hotel_end_day) { + if (form.type === 'hotel' && (form.hotel_start_day || form.hotel_end_day)) { saveData.create_accommodation = { place_id: form.hotel_place_id || null, // No existing place picked but we have an address/name (e.g. a reviewed @@ -265,14 +265,25 @@ export function ReservationModal({ isOpen, onClose, onSave, reservation, days, p venue: (!form.hotel_place_id && (form.hotel_address || form.title)) ? { name: form.title, address: form.hotel_address || null } : null, - start_day_id: form.hotel_start_day, - end_day_id: form.hotel_end_day, + // Tolerate a single resolved end of the range (a one-night stay or a date + // that only matched one trip day) so the accommodation is still created. + start_day_id: form.hotel_start_day || form.hotel_end_day, + end_day_id: form.hotel_end_day || form.hotel_start_day, check_in: form.meta_check_in_time || null, check_in_end: form.meta_check_in_end_time || null, check_out: form.meta_check_out_time || null, confirmation: form.confirmation_number || null, } } + // Imported booking → auto-create the linked cost from the parsed price (what the + // old direct import did). Only on create (not edit) and only when there's a price. + if (!reservation && prefill && isBudgetEnabled) { + const pmeta = prefill.metadata && typeof prefill.metadata === 'object' ? (prefill.metadata as Record) : {} + const price = Number(pmeta.price) + if (Number.isFinite(price) && price > 0) { + saveData.create_budget_entry = { total_price: price, category: typeToCostCategory(form.type) } + } + } const saved = await onSave(saveData) if (!reservation?.id && saved?.id && pendingFiles.length > 0) { for (const file of pendingFiles) { diff --git a/client/src/components/Planner/TransportModal.tsx b/client/src/components/Planner/TransportModal.tsx index bcf6682c2..953719813 100644 --- a/client/src/components/Planner/TransportModal.tsx +++ b/client/src/components/Planner/TransportModal.tsx @@ -336,6 +336,15 @@ export function TransportModal({ isOpen, onClose, onSave, reservation, days, sel endpoints, needs_review: false, } + // Imported booking → auto-create the linked cost from the parsed price (what the + // old direct import did). Only on create (not edit) and only when there's a price. + if (!reservation && prefill && isBudgetEnabled) { + const pmeta = prefill.metadata && typeof prefill.metadata === 'object' ? (prefill.metadata as Record) : {} + const price = Number(pmeta.price) + if (Number.isFinite(price) && price > 0) { + ;(payload as Record).create_budget_entry = { total_price: price, category: typeToCostCategory(form.type) } + } + } const saved = await onSave(payload) if (!reservation?.id && saved?.id && pendingFiles.length > 0 && onFileUpload) { for (const file of pendingFiles) {