feat(suppliers)!: full customers model - structured address + custom fields
The dodavatele modal is now an exact mirror of the customers modal (minus the PDF field-order picker): Nazev+ARES, Ulice, Mesto+PSC, Zeme, ICO+ARES, DIC, and the same "Vlastni pole" editor (maxWidth md). Two migrations on sklad_suppliers: - structured street/city/postal_code/country replace the free-text address blob (best-effort split: street / PSC regex / city) - custom_fields LONGTEXT replaces contact_person/email/phone/notes; existing values are preserved as labeled custom fields The encode/decode of the custom_fields blob is shared with customers via the new utils/custom-fields.ts. The PO PDF supplier block renders the structured address + custom-field lines like the customer block; the supplier picker/detail selects and types follow. Legacy clients sending the dropped keys are silently stripped (tested). Suppliers list shows Ulice/Mesto instead of the dropped contact columns; search covers name/ico/city. BREAKING CHANGE: sklad_suppliers.address, contact_person, email, phone, notes columns dropped (data migrated); deploy must run prisma migrate deploy + generate. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -117,11 +117,12 @@ function buildAddressLines(
|
||||
}
|
||||
|
||||
/**
|
||||
* Address block for the sklad_suppliers counterparty. Unlike customers (which
|
||||
* have structured street/city/postal columns), suppliers.address is a single
|
||||
* Text blob — split it on newlines into one rendered line each (a blob without
|
||||
* newlines renders as one line). IČO/DIČ come from the supplier's ico/dic
|
||||
* columns, prefixed with the same translated labels the customer block used.
|
||||
* Address block for the sklad_suppliers counterparty — full customer model
|
||||
* (structured street/city/postal_code/country + custom_fields JSON; the old
|
||||
* dedicated address/contact columns were dropped 2026-06). IČO/DIČ come from
|
||||
* the supplier's ico/dic columns, prefixed with the same translated labels
|
||||
* the customer block uses; custom fields render as appended lines in array
|
||||
* order (suppliers have no PDF field-order picker).
|
||||
*/
|
||||
function buildSupplierLines(
|
||||
supplier: Record<string, unknown> | null,
|
||||
@@ -130,14 +131,52 @@ function buildSupplierLines(
|
||||
if (!supplier) return { name: "", lines: [] };
|
||||
const name = String(supplier.name || "");
|
||||
const lines: string[] = [];
|
||||
if (supplier.address) {
|
||||
for (const part of String(supplier.address).split(/\r?\n/)) {
|
||||
const line = part.trim();
|
||||
if (line) lines.push(line);
|
||||
}
|
||||
}
|
||||
if (supplier.street) lines.push(String(supplier.street));
|
||||
const cityLine = [supplier.postal_code, supplier.city]
|
||||
.filter(Boolean)
|
||||
.map(String)
|
||||
.join(" ")
|
||||
.trim();
|
||||
if (cityLine) lines.push(cityLine);
|
||||
if (supplier.country) lines.push(String(supplier.country));
|
||||
if (supplier.ico) lines.push(`${tObj.ico}${supplier.ico}`);
|
||||
if (supplier.dic) lines.push(`${tObj.dic}${supplier.dic}`);
|
||||
|
||||
// Custom fields ("Vlastní pole") — same blob format as customers; malformed
|
||||
// JSON degrades to no extra lines rather than failing the PDF.
|
||||
if (supplier.custom_fields) {
|
||||
let parsed: unknown;
|
||||
try {
|
||||
parsed =
|
||||
typeof supplier.custom_fields === "string"
|
||||
? JSON.parse(supplier.custom_fields)
|
||||
: supplier.custom_fields;
|
||||
} catch {
|
||||
parsed = null;
|
||||
}
|
||||
const fields =
|
||||
parsed && typeof parsed === "object" && !Array.isArray(parsed)
|
||||
? ((parsed as Record<string, unknown>).fields as Array<{
|
||||
name?: string;
|
||||
value?: string;
|
||||
showLabel?: boolean;
|
||||
}>)
|
||||
: Array.isArray(parsed)
|
||||
? (parsed as Array<{
|
||||
name?: string;
|
||||
value?: string;
|
||||
showLabel?: boolean;
|
||||
}>)
|
||||
: [];
|
||||
for (const f of fields ?? []) {
|
||||
const value = (f?.value || "").trim();
|
||||
if (!value) continue;
|
||||
const label = (f?.name || "").trim();
|
||||
lines.push(
|
||||
f?.showLabel !== false && label ? `${label}: ${value}` : value,
|
||||
);
|
||||
}
|
||||
}
|
||||
return { name, lines };
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user