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:
@@ -9,48 +9,20 @@ import {
|
||||
CreateCustomerSchema,
|
||||
UpdateCustomerSchema,
|
||||
} from "../../schemas/customers.schema";
|
||||
import {
|
||||
encodeCustomFields,
|
||||
decodeCustomFields as decodeCustomFieldsShared,
|
||||
} from "../../utils/custom-fields";
|
||||
|
||||
const ALLOWED_SORT_FIELDS = ["id", "name", "company_id", "city", "country"];
|
||||
|
||||
/** Encode custom_fields + customer_field_order into a single JSON blob (matching PHP format) */
|
||||
function encodeCustomFields(
|
||||
fields: unknown,
|
||||
fieldOrder: unknown,
|
||||
): string | null {
|
||||
const f = Array.isArray(fields) ? fields : [];
|
||||
const o = Array.isArray(fieldOrder) ? fieldOrder : [];
|
||||
if (f.length === 0 && o.length === 0) return null;
|
||||
return JSON.stringify({ fields: f, field_order: o });
|
||||
}
|
||||
|
||||
/** Decode custom_fields JSON blob into separate fields + field_order for frontend */
|
||||
/** Customer-shaped wrapper over the shared codec (field_order key naming). */
|
||||
function decodeCustomFields(raw: string | null): {
|
||||
custom_fields: unknown[];
|
||||
customer_field_order: string[];
|
||||
} {
|
||||
if (!raw) return { custom_fields: [], customer_field_order: [] };
|
||||
try {
|
||||
const parsed = JSON.parse(raw);
|
||||
// PHP format: { fields: [...], field_order: [...] }
|
||||
if (
|
||||
parsed &&
|
||||
typeof parsed === "object" &&
|
||||
!Array.isArray(parsed) &&
|
||||
"fields" in parsed
|
||||
) {
|
||||
return {
|
||||
custom_fields: parsed.fields || [],
|
||||
customer_field_order: parsed.field_order || [],
|
||||
};
|
||||
}
|
||||
// Legacy TS format: raw array
|
||||
if (Array.isArray(parsed)) {
|
||||
return { custom_fields: parsed, customer_field_order: [] };
|
||||
}
|
||||
return { custom_fields: [], customer_field_order: [] };
|
||||
} catch {
|
||||
return { custom_fields: [], customer_field_order: [] };
|
||||
}
|
||||
const { custom_fields, field_order } = decodeCustomFieldsShared(raw);
|
||||
return { custom_fields, customer_field_order: field_order };
|
||||
}
|
||||
|
||||
export default async function customersRoutes(
|
||||
|
||||
Reference in New Issue
Block a user