Mecanismo sort para tablas
This commit is contained in:
@@ -7,7 +7,13 @@ export interface Item {
|
||||
// Helper function to check if an object has any meaningful values
|
||||
export function hasValues(obj: any): boolean {
|
||||
if (!obj || typeof obj !== 'object') return false;
|
||||
return Object.values(obj).some(
|
||||
|
||||
// Si el objeto está intencionalmente vacío o tiene campos que serán usados,
|
||||
// es mejor dejar que el backend valide si es requerido.
|
||||
const values = Object.values(obj);
|
||||
if (values.length === 0) return false;
|
||||
|
||||
return values.some(
|
||||
(val) =>
|
||||
val !== undefined &&
|
||||
val !== null &&
|
||||
@@ -18,7 +24,9 @@ export function hasValues(obj: any): boolean {
|
||||
|
||||
// Clean nested data before sending to API
|
||||
export function cleanLineData(line: any) {
|
||||
const cleaned: any = { ...line };
|
||||
// 1. First, deeply copy and unwrap any Svelte Proxies to ensure a clean JS object
|
||||
const rawLine = JSON.parse(JSON.stringify(line));
|
||||
const cleaned: any = { ...rawLine };
|
||||
|
||||
// Helper function to convert to number or undefined
|
||||
const toNumberOrUndefined = (value: any): number | undefined => {
|
||||
@@ -29,47 +37,88 @@ export function cleanLineData(line: any) {
|
||||
return !isNaN(numValue) && isFinite(numValue) ? numValue : undefined;
|
||||
};
|
||||
|
||||
// Convert integer fields
|
||||
cleaned.part_number = toNumberOrUndefined(cleaned.part_number);
|
||||
// Explicitly keep mandatory fields for a76 schema
|
||||
cleaned.invoice_id = toNumberOrUndefined(rawLine.invoice_id);
|
||||
cleaned.line_number = toNumberOrUndefined(rawLine.line_number);
|
||||
|
||||
// Reconstruction approach for core objects to be 100% sure
|
||||
// We ALWAYS want these objects to exist in the payload even if all fields are null
|
||||
// so the backend validation layer doesn't crash (AttributeError on None)
|
||||
|
||||
cleaned.financial = {
|
||||
unit_cost_usd: rawLine.financial ? toNumberOrUndefined(rawLine.financial.unit_cost_usd) : undefined,
|
||||
unit_cost_mxn: rawLine.financial ? toNumberOrUndefined(rawLine.financial.unit_cost_mxn) : undefined,
|
||||
unit_cost_capture: rawLine.financial ? toNumberOrUndefined(rawLine.financial.unit_cost_capture) : undefined,
|
||||
value_mc: rawLine.financial ? toNumberOrUndefined(rawLine.financial.value_mc) : undefined,
|
||||
value_usd: rawLine.financial ? toNumberOrUndefined(rawLine.financial.value_usd) : undefined,
|
||||
value_mxn: rawLine.financial ? toNumberOrUndefined(rawLine.financial.value_mxn) : undefined
|
||||
};
|
||||
|
||||
cleaned.quantity = {
|
||||
quantity: rawLine.quantity ? (toNumberOrUndefined(rawLine.quantity.quantity) || 0) : 0,
|
||||
net_weight: rawLine.quantity ? toNumberOrUndefined(rawLine.quantity.net_weight) : undefined,
|
||||
gross_weight: rawLine.quantity ? toNumberOrUndefined(rawLine.quantity.gross_weight) : undefined,
|
||||
package_id: rawLine.quantity ? toNumberOrUndefined(rawLine.quantity.package_id) : undefined,
|
||||
package_quantity: rawLine.quantity ? toNumberOrUndefined(rawLine.quantity.package_quantity) : undefined
|
||||
// NOTE: unit_of_measure lives at the top-level LineItem, NOT inside quantity
|
||||
};
|
||||
|
||||
cleaned.description = {
|
||||
description_spanish: rawLine.description ? (rawLine.description.description_spanish || '') : '',
|
||||
description_english: rawLine.description ? (rawLine.description.description_english || '') : '',
|
||||
brand: rawLine.description ? (rawLine.description.brand || '') : '',
|
||||
model: rawLine.description ? (rawLine.description.model || '') : ''
|
||||
};
|
||||
|
||||
cleaned.customs = {
|
||||
fraction: rawLine.customs ? (rawLine.customs.fraction || undefined) : undefined,
|
||||
american_fraction: rawLine.customs ? (rawLine.customs.american_fraction || undefined) : undefined,
|
||||
origin_country: rawLine.customs ? (rawLine.customs.origin_country || undefined) : undefined,
|
||||
fraction_type: rawLine.customs ? (rawLine.customs.fraction_type || undefined) : undefined
|
||||
};
|
||||
|
||||
// Convert integer fields (only if they look like numbers/IDs)
|
||||
if (cleaned.part_number && !isNaN(Number(cleaned.part_number))) {
|
||||
cleaned.part_number = toNumberOrUndefined(cleaned.part_number);
|
||||
}
|
||||
|
||||
cleaned.component_part_number = toNumberOrUndefined(cleaned.component_part_number);
|
||||
cleaned.class_id = toNumberOrUndefined(cleaned.class_id);
|
||||
|
||||
// Ensure part_number is preserved if it's a string (common in some modules)
|
||||
if (rawLine.part_number && !cleaned.part_number) {
|
||||
cleaned.part_number = rawLine.part_number;
|
||||
}
|
||||
|
||||
cleaned.unit_of_measure = toNumberOrUndefined(cleaned.unit_of_measure);
|
||||
cleaned.alternate_unit = toNumberOrUndefined(cleaned.alternate_unit);
|
||||
|
||||
// Remove display-only fields
|
||||
// Remove ALL display-only and UI-specific fields that the backend schema doesn't know about
|
||||
delete cleaned.class_code;
|
||||
delete cleaned.class_unit_of_measure;
|
||||
delete cleaned.class_description;
|
||||
|
||||
// UI specific fields that shouldn't be in the payload
|
||||
delete cleaned.part_description_es;
|
||||
delete cleaned.part_description_en;
|
||||
delete cleaned.part_number_display; // UI display field for part number string
|
||||
delete cleaned.unit_code;
|
||||
delete cleaned.unit_description;
|
||||
delete cleaned.includes_subitems;
|
||||
delete cleaned.payment_method_description;
|
||||
|
||||
// Only delete part_number if it's the string code from UI, but schema expects int ID.
|
||||
// In this codebase, if part_number is populated from existing data, it's an ID.
|
||||
// If it's a new item, it might be cleaned.
|
||||
// Remove any other unknown top-level display fields
|
||||
delete (cleaned as any).class_unit_of_measure_description;
|
||||
|
||||
// Remove display-only fields from nested objects
|
||||
if (cleaned.customs) {
|
||||
delete cleaned.customs.origin_country_name;
|
||||
delete cleaned.customs.fraction_description;
|
||||
if (!hasValues(cleaned.customs)) delete cleaned.customs;
|
||||
// DO NOT delete if empty - backend needs the object structure
|
||||
}
|
||||
|
||||
if (cleaned.fa_data) {
|
||||
delete cleaned.fa_data.includes_subitems;
|
||||
if (!hasValues(cleaned.fa_data)) delete cleaned.fa_data;
|
||||
// Keep fa_data as is otherwise (unwrapped by stringify/parse above)
|
||||
}
|
||||
|
||||
// Remove empty nested objects
|
||||
if (cleaned.financial && !hasValues(cleaned.financial)) delete cleaned.financial;
|
||||
if (cleaned.quantity && !hasValues(cleaned.quantity)) delete cleaned.quantity;
|
||||
if (cleaned.description && !hasValues(cleaned.description)) delete cleaned.description;
|
||||
if (cleaned.reference && !hasValues(cleaned.reference)) delete cleaned.reference;
|
||||
if (cleaned.series != null) {
|
||||
const arr = Array.isArray(cleaned.series) ? cleaned.series : [cleaned.series];
|
||||
cleaned.series = arr
|
||||
|
||||
Reference in New Issue
Block a user