Accounting rule: nabidky, objednavky (incl. confirmation PDF) and objednavky
vydane are NOT tax documents - VAT belongs only on invoices. Per user
decision this is a FULL removal including DB columns.
- migration: DROP orders.vat_rate/apply_vat, issued_orders.vat_rate/apply_vat,
issued_order_items.vat_rate, quotations.vat_rate/apply_vat (applied to
dev + test DBs)
- services: net-only totals everywhere (computeIssuedOrderTotals(items) ->
{total}; enrichOrder/enrichQuotation net; per-currency list totals net)
- PDFs (offers, order confirmation, issued order): no VAT columns/summary,
single 'Celkem bez DPH' / 'Total excl. VAT' total, note under totals:
'Ceny jsou uvedeny bez DPH. DPH bude uctovano dle platnych predpisu.';
duplicate Cena/Celkem column merged (desc width 56%); orders-pdf render
extracted as exported renderOrderConfirmationHtml for testability
- frontend: Uplatnit DPH checkboxes, VAT selects and per-item VAT columns
removed from OfferDetail/OrderDetail/IssuedOrderDetail/
OrderConfirmationModal/ReceivedOrders manual-create; list footers read
'Celkem bez DPH'; invoice-from-order prefill now takes the company default
VAT (invoice decides its own VAT)
- tests: suites reworked to net math; new pdf-vat-note.test.ts pins the
exact cs+en note text and VAT-free layout on all three PDFs
Invoices and received invoices keep their VAT handling unchanged.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
47 lines
1.5 KiB
TypeScript
47 lines
1.5 KiB
TypeScript
import { z } from "zod";
|
|
import {
|
|
nonNegativeNumberFromForm,
|
|
positiveNumberFromForm,
|
|
nullableIntIdFromForm,
|
|
isoDateString,
|
|
} 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(),
|
|
delivery_terms: z.string().max(500).nullish(),
|
|
payment_terms: z.string().max(500).nullish(),
|
|
issued_by: z.string().max(255).nullish(),
|
|
// 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(),
|
|
notes: z.string().nullish(),
|
|
internal_notes: z.string().nullish(),
|
|
items: z.array(IssuedOrderItemSchema).optional(),
|
|
});
|
|
|
|
export const UpdateIssuedOrderSchema = CreateIssuedOrderSchema.partial();
|