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:
@@ -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,
|
||||
|
||||
@@ -3541,6 +3541,7 @@
|
||||
"selectTiming": "— Zahlungsablauf wählen —",
|
||||
"eventName": "Anlass",
|
||||
"eventDate": "Anlassdatum",
|
||||
"eventNamePlaceholder": "z.B. Hochzeit Schmidt 2024",
|
||||
"eventTimeStart": "Startzeit",
|
||||
"eventTimeEnd": "Endzeit",
|
||||
"customer": "Kunde",
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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));
|
||||
|
||||
Reference in New Issue
Block a user