feat(bills): capture event name/date when importing historical invoices

The historical-invoice import form had no event field, so imported rows
landed with event_name = NULL even when the admin knew the occasion. Add
free-text Event name + Event date inputs to the import modal, thread them
through billsService.importHistorical and the POST /admin/invoices/import
validator, and store them in the event_name/event_date snapshot columns
(migration 107). event_id stays NULL — no FK, since the event may predate
picpeak. Autocomplete-to-event_id linking deferred as a future bonus.
This commit is contained in:
Luca
2026-06-02 09:50:51 +02:00
parent c2d3f663bc
commit db7d11dc7f
5 changed files with 28 additions and 0 deletions
+7
View File
@@ -427,6 +427,8 @@ router.post(
[
body('customerAccountId').isInt({ min: 1 }),
body('invoiceNumber').isString().isLength({ min: 1, max: 64 }),
body('eventName').optional({ values: 'falsy' }).isString().isLength({ max: 255 }),
body('eventDate').optional({ values: 'falsy' }).isISO8601(),
body('issueDate').isISO8601(),
body('dueDate').optional({ values: 'falsy' }).isISO8601(),
body('totalAmountMinor').isInt({ min: 0 }),
@@ -487,7 +489,12 @@ router.post(
invoice_number: req.body.invoiceNumber,
customer_account_id: customer.id,
source_quote_id: null,
// No FK link on import — the event may predate picpeak. Store the
// free-text snapshot only, mirroring createInvoice's event_name /
// event_date columns (migration 107).
event_id: null,
event_name: req.body.eventName || null,
event_date: req.body.eventDate || null,
language,
currency,
issue_date: issueDate,
+1
View File
@@ -3541,6 +3541,7 @@
"selectTiming": "— Zahlungsablauf wählen —",
"eventName": "Anlass",
"eventDate": "Anlassdatum",
"eventNamePlaceholder": "z.B. Hochzeit Schmidt 2024",
"eventTimeStart": "Startzeit",
"eventTimeEnd": "Endzeit",
"customer": "Kunde",
+1
View File
@@ -3587,6 +3587,7 @@
"selectTiming": "— Select schedule —",
"eventName": "Event",
"eventDate": "Event date",
"eventNamePlaceholder": "e.g. Smith wedding 2024",
"eventTimeStart": "Start time",
"eventTimeEnd": "End time",
"customer": "Customer",
@@ -221,6 +221,8 @@ const ImportHistoricalInvoiceModal: React.FC<ImportModalProps> = ({ onClose }) =
const [customerId, setCustomerId] = useState<number | null>(null);
const [customerLabel, setCustomerLabel] = useState('');
const [invoiceNumber, setInvoiceNumber] = useState('');
const [eventName, setEventName] = useState('');
const [eventDate, setEventDate] = useState('');
const [issueDate, setIssueDate] = useState(new Date().toISOString().slice(0, 10));
const [dueDate, setDueDate] = useState('');
const [totalMajor, setTotalMajor] = useState('');
@@ -245,6 +247,8 @@ const ImportHistoricalInvoiceModal: React.FC<ImportModalProps> = ({ onClose }) =
await billsService.importHistorical({
customerAccountId: customerId,
invoiceNumber,
eventName: eventName.trim() || undefined,
eventDate: eventDate || undefined,
issueDate,
dueDate: dueDate || undefined,
totalAmountMinor: Math.round(Number(totalMajor) * 100),
@@ -327,6 +331,17 @@ const ImportHistoricalInvoiceModal: React.FC<ImportModalProps> = ({ onClose }) =
</div>
<div className="grid grid-cols-1 md:grid-cols-2 gap-3">
<div className="md:col-span-2">
<Input label={t('bills.field.eventName', 'Event / occasion (optional)') as string}
value={eventName}
placeholder={t('bills.field.eventNamePlaceholder', 'e.g. Smith wedding 2024') as string}
onChange={(e) => setEventName(e.target.value)} />
</div>
<LocalizedDateInput
label={t('bills.field.eventDate', 'Event date (optional)') as string}
value={eventDate}
onChange={setEventDate}
/>
<Input label={t('bills.field.invoiceNumber', 'Invoice number') as string}
value={invoiceNumber}
placeholder="R-2024-0001"
+4
View File
@@ -330,6 +330,8 @@ export const billsService = {
async importHistorical(payload: {
customerAccountId: number;
invoiceNumber: string;
eventName?: string;
eventDate?: string;
issueDate: string;
dueDate?: string;
totalAmountMinor: number;
@@ -343,6 +345,8 @@ export const billsService = {
form.append('pdf', payload.file);
form.append('customerAccountId', String(payload.customerAccountId));
form.append('invoiceNumber', payload.invoiceNumber);
if (payload.eventName) form.append('eventName', payload.eventName);
if (payload.eventDate) form.append('eventDate', payload.eventDate);
form.append('issueDate', payload.issueDate);
if (payload.dueDate) form.append('dueDate', payload.dueDate);
form.append('totalAmountMinor', String(payload.totalAmountMinor));