Per user decision the rich-text sections now carry all free-form PDF content on issued orders: dropped columns delivery_terms, payment_terms, issued_by, notes (migration applied to dev+test) and their PDF blocks + form fields. Kept: order_text (moved from the bottom card into the Zakladni udaje grid, replacing the Vystavil field) and internal_notes (now the only field in the bottom card, never printed). Sections card is titled 'Obsah' on issued orders; offers keep 'Rozsah projektu' and are untouched. Legacy clients sending the dropped keys are silently stripped (tested). PDF footer 'Vystavil:' stays - it prints the logged-in user, not the dropped column. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
52 lines
1.8 KiB
TypeScript
52 lines
1.8 KiB
TypeScript
import { z } from "zod";
|
|
import {
|
|
nonNegativeNumberFromForm,
|
|
positiveNumberFromForm,
|
|
nullableIntIdFromForm,
|
|
isoDateString,
|
|
DocumentSectionSchema,
|
|
} from "./common";
|
|
|
|
export const IssuedOrderItemSchema = z.object({
|
|
description: z.string().max(500).nullish(),
|
|
item_description: z.string().max(5000).nullish(),
|
|
quantity: positiveNumberFromForm.optional(),
|
|
unit: z.string().max(20).nullish(),
|
|
unit_price: nonNegativeNumberFromForm.optional(),
|
|
position: z.number().int().nonnegative().optional(),
|
|
});
|
|
|
|
const ISSUED_ORDER_STATUSES = [
|
|
"draft",
|
|
"sent",
|
|
"confirmed",
|
|
"completed",
|
|
"cancelled",
|
|
] as const;
|
|
|
|
export const CreateIssuedOrderSchema = z.object({
|
|
po_number: z.string().max(50).nullish(),
|
|
supplier_id: nullableIntIdFromForm.nullish(),
|
|
status: z.enum(ISSUED_ORDER_STATUSES).optional(),
|
|
currency: z.string().max(10).optional(),
|
|
exchange_rate: nonNegativeNumberFromForm.optional(),
|
|
order_date: isoDateString.nullish(),
|
|
delivery_date: isoDateString.nullish(),
|
|
language: z.string().max(5).optional(),
|
|
// Editable heading above the PDF items table; empty/null falls back to the
|
|
// default "Objednáváme si u Vás:" (issued-orders-pdf t.billing).
|
|
order_text: z.string().max(500).nullish(),
|
|
internal_notes: z.string().nullish(),
|
|
items: z.array(IssuedOrderItemSchema).optional(),
|
|
// Rich-text CZ/EN sections rendered on their own PDF page (mirrors offers'
|
|
// scope_sections — shared DocumentSectionSchema, DB-aligned limits).
|
|
sections: z.array(DocumentSectionSchema).optional(),
|
|
});
|
|
|
|
// Update = partial create MINUS the number: PO numbers are immutable
|
|
// (assigned by the sequence on finalize), so the field is stripped before it
|
|
// can ever reach the service (which never reads it on update anyway).
|
|
export const UpdateIssuedOrderSchema = CreateIssuedOrderSchema.partial().omit({
|
|
po_number: true,
|
|
});
|