feat(invoices)!: Obsah sections, internal-only notes, unified per-page PDF header+footer
Invoices now mirror the issued-orders document model: - New invoice_sections table (CZ/EN rich-text "Obsah") edited via the shared SectionsEditor, printed inline right after the items on the PDF. Full-replace on update, same transaction as items. - Printed notes dropped: the notes column is removed (migration merges existing content into internal_notes first); the form field is now "Interni poznamky", never printed. Legacy payloads sending notes are silently stripped. - Form cleanup: Cislo faktury and Vystavil fields removed (number lives in the header, issued_by auto-fills); page header title restyled to the orders/offers pattern (number span + status chip). - Unified per-page PDF header for the red-accent family: shared buildPdfHeaderTemplate in pdf-shared (22mm logo, red heading, red rule) rendered by a Puppeteer headerTemplate on EVERY page of both invoices and issued orders (incl. the /file fallback render); body headers are print-hidden. htmlToPdf gained the headerTemplate option. - Footer parity: invoices get the per-page "Vystavil + Strana X z Y" footer; the invoice bottom block (notice + QR/VAT recap + Prevzal) is break-inside: avoid so a page break can never split it. - @page margins now match the template space (32mm top, 18mm bottom) - Chromium lays out by CSS @page margins, which also fixes issued orders' content running into the 18mm footer zone on full pages. BREAKING CHANGE: invoices.notes column dropped (data merged into internal_notes); deploy must run prisma migrate deploy + generate. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -6,6 +6,7 @@ import {
|
||||
positiveNumberFromForm,
|
||||
nullableIntIdFromForm,
|
||||
booleanFromForm,
|
||||
DocumentSectionSchema,
|
||||
} from "./common";
|
||||
|
||||
const InvoiceItemSchema = z.object({
|
||||
@@ -38,9 +39,14 @@ export const CreateInvoiceSchema = z.object({
|
||||
issued_by: z.string().max(255).nullish(),
|
||||
billing_text: z.string().max(8000).nullish(),
|
||||
language: z.string().max(20).optional().default("cs"),
|
||||
notes: z.string().max(8000).nullish(),
|
||||
// `notes` was dropped (printed-notes block removed — free-form PDF content
|
||||
// lives in the sections); legacy clients still sending it are silently
|
||||
// stripped by z.object. internal_notes is never printed.
|
||||
internal_notes: z.string().max(8000).nullish(),
|
||||
items: z.array(InvoiceItemSchema).optional(),
|
||||
// Rich-text CZ/EN "Obsah" sections rendered after the items on the PDF
|
||||
// (mirrors issued orders — shared DocumentSectionSchema, DB-aligned limits).
|
||||
sections: z.array(DocumentSectionSchema).optional(),
|
||||
});
|
||||
|
||||
export const UpdateInvoiceSchema = z.object({
|
||||
@@ -61,10 +67,10 @@ export const UpdateInvoiceSchema = z.object({
|
||||
issue_date: z.union([z.string().max(255), z.null()]).optional(),
|
||||
due_date: z.union([z.string().max(255), z.null()]).optional(),
|
||||
tax_date: z.union([z.string().max(255), z.null()]).optional(),
|
||||
notes: z.string().max(8000).nullish(),
|
||||
internal_notes: z.string().max(8000).nullish(),
|
||||
paid_date: z.union([z.string().max(255), z.null()]).optional(),
|
||||
items: z.array(InvoiceItemSchema).optional(),
|
||||
sections: z.array(DocumentSectionSchema).optional(),
|
||||
});
|
||||
|
||||
export type CreateInvoiceInput = z.infer<typeof CreateInvoiceSchema>;
|
||||
|
||||
Reference in New Issue
Block a user