feat: enhance invoice saving functionality with new top fields and transport modes
- Added InvoiceTopFieldsFormData to handle additional invoice fields. - Updated saveInvoice function to validate and process new fields. - Integrated transport modes fetching in the invoice edit page. - Refactored financials and compliance data handling to accommodate new structure. - Improved user feedback with toast notifications instead of alerts.
This commit is contained in:
@@ -2,6 +2,7 @@
|
||||
import { api } from '$lib/api';
|
||||
|
||||
export interface CustomsBroker {
|
||||
id: number;
|
||||
type?: string | null;
|
||||
broker_key: string;
|
||||
name?: string | null;
|
||||
@@ -111,15 +112,15 @@ export const customsBrokersApi = {
|
||||
* Elimina un agente aduanal
|
||||
*/
|
||||
delete: (brokerKey: string, companyId: string) => {
|
||||
return api.delete<CustomsBroker>(`/v1/a76/customs-brokers/${brokerKey}?company_id=${companyId}`);
|
||||
return api.delete<CustomsBroker>(`/v1/a76/customs-brokers/${brokerKey}/?company_id=${companyId}`);
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* Actualiza la información de un agente aduanal
|
||||
*/
|
||||
update: (brokerKey: string, data: CreateCustomsBrokerData) => {
|
||||
const companyId = data.company_id;
|
||||
return api.put<CustomsBroker>(`/v1/a76/customs-brokers/${brokerKey}?company_id=${companyId}`, data);
|
||||
return api.put<CustomsBroker>(`/v1/a76/customs-brokers/${brokerKey}/?company_id=${companyId}`, data);
|
||||
},
|
||||
|
||||
/**
|
||||
|
||||
@@ -20,22 +20,22 @@ export interface InvoiceComplianceMx {
|
||||
destination?: string | null;
|
||||
manifest_number?: string | null;
|
||||
provider_header?: string | null;
|
||||
provider_id?: string | null;
|
||||
provider_id?: number | null;
|
||||
sold_to_header?: string | null;
|
||||
sold_to_id?: string | null;
|
||||
sold_to_id?: number | null;
|
||||
shipped_to_header?: string | null;
|
||||
shipped_to_id?: string | null;
|
||||
shipped_by_header?: string | null;
|
||||
shipped_by_id?: string | null;
|
||||
customs_broker_id?: string | null;
|
||||
customs_broker_us_id?: string | null;
|
||||
shipped_by_id?: number | null;
|
||||
customs_broker_id?: number | null;
|
||||
customs_broker_us_id?: number | null;
|
||||
broker_invoice_num?: string | null;
|
||||
broker_invoice_date?: string | null;
|
||||
is_mixed?: boolean | null;
|
||||
waste_type?: string | null;
|
||||
scrap_type?: string | null;
|
||||
appendix_17?: number | null;
|
||||
is_regime_change?: string | null;
|
||||
is_regime_change?: boolean | null;
|
||||
which_exchange_rate?: string | null;
|
||||
value_method?: string | null;
|
||||
act_value?: string | null;
|
||||
@@ -179,6 +179,7 @@ export interface Invoice {
|
||||
system?: string | null;
|
||||
operation_type?: OperationType | null;
|
||||
invoice_type?: string | null;
|
||||
document_type?: string | null;
|
||||
invoice_number?: string | null;
|
||||
project_number?: string | null;
|
||||
purchase_order?: string | null;
|
||||
@@ -195,8 +196,8 @@ export interface Invoice {
|
||||
capture_user?: string | null;
|
||||
traffic_light_status?: string | null;
|
||||
process_log?: string | null;
|
||||
status_rec?: number | null;
|
||||
status_rep?: string | null;
|
||||
is_updated_rec?: number | null;
|
||||
is_updated_rep?: string | null;
|
||||
observation_es?: string | null;
|
||||
observation_en?: string | null;
|
||||
comments_status?: string | null;
|
||||
@@ -206,9 +207,9 @@ export interface Invoice {
|
||||
path_xml?: string | null;
|
||||
subcompany?: string | null;
|
||||
party_count?: number | null;
|
||||
generate_id?: string | null;
|
||||
generate_id?: boolean | null;
|
||||
generate_desc_parties?: string | null;
|
||||
apply_manual_discount?: string | null;
|
||||
apply_manual_discount?: boolean | null;
|
||||
is_bulk?: boolean | null;
|
||||
download_substance?: boolean | null;
|
||||
download_class?: boolean | null;
|
||||
@@ -235,6 +236,7 @@ export interface CreateInvoiceData {
|
||||
system: string;
|
||||
operation_type: OperationType;
|
||||
invoice_type: string;
|
||||
document_type: string;
|
||||
invoice_number: string;
|
||||
project_number?: string | null;
|
||||
purchase_order?: string | null;
|
||||
@@ -250,8 +252,8 @@ export interface CreateInvoiceData {
|
||||
capture_user?: string | null;
|
||||
traffic_light_status?: string | null;
|
||||
process_log?: string | null;
|
||||
status_rec?: number | null;
|
||||
status_rep?: string | null;
|
||||
is_updated_rec?: number | null;
|
||||
is_updated_rep?: string | null;
|
||||
observation_es?: string | null;
|
||||
observation_en?: string | null;
|
||||
comments_status?: string | null;
|
||||
@@ -261,9 +263,9 @@ export interface CreateInvoiceData {
|
||||
path_xml?: string | null;
|
||||
subcompany?: string | null;
|
||||
party_count?: number | null;
|
||||
generate_id?: string | null;
|
||||
generate_id?: boolean | null;
|
||||
generate_desc_parties?: string | null;
|
||||
apply_manual_discount?: string | null;
|
||||
apply_manual_discount?: boolean | null;
|
||||
is_bulk?: boolean | null;
|
||||
download_substance?: boolean | null;
|
||||
download_class?: boolean | null;
|
||||
@@ -282,6 +284,7 @@ export interface CreateInvoiceData {
|
||||
export interface UpdateInvoiceData {
|
||||
operation_type?: OperationType | null;
|
||||
invoice_type?: string | null;
|
||||
document_type?: string | null;
|
||||
invoice_number?: string | null;
|
||||
project_number?: string | null;
|
||||
purchase_order?: string | null;
|
||||
@@ -355,7 +358,7 @@ export const invoicesApi = {
|
||||
const params = new URLSearchParams({
|
||||
company_id: companyId.toString()
|
||||
});
|
||||
return api.put<Invoice>(`/v1/a76/invoices/${invoiceId}?${params.toString()}`, data);
|
||||
return api.put<Invoice>(`/v1/a76/invoices/${invoiceId}/?${params.toString()}`, data);
|
||||
},
|
||||
|
||||
/**
|
||||
|
||||
@@ -100,20 +100,6 @@ export function createColumns(onSuccess?: () => void): ColumnDef<Invoice>[] {
|
||||
return renderSnippet(typeSnippet, { label, colorClass });
|
||||
}
|
||||
},
|
||||
{
|
||||
accessorKey: "invoice_number",
|
||||
header: "Número de Factura",
|
||||
cell: ({ row }) => {
|
||||
const numberSnippet = createRawSnippet<[{ number?: string | null }]>((getNumber) => {
|
||||
const { number } = getNumber();
|
||||
return {
|
||||
render: () =>
|
||||
`<code class="relative rounded bg-muted px-[0.3rem] py-[0.2rem] font-mono text-sm font-semibold">${number || 'N/A'}</code>`
|
||||
};
|
||||
});
|
||||
return renderSnippet(numberSnippet, { number: row.original.invoice_number });
|
||||
}
|
||||
},
|
||||
{
|
||||
accessorKey: "invoice_type",
|
||||
header: "Tipo",
|
||||
@@ -128,6 +114,20 @@ export function createColumns(onSuccess?: () => void): ColumnDef<Invoice>[] {
|
||||
return renderSnippet(typeSnippet, { type: row.original.invoice_type });
|
||||
}
|
||||
},
|
||||
{
|
||||
accessorKey: "invoice_number",
|
||||
header: "Número de Factura",
|
||||
cell: ({ row }) => {
|
||||
const numberSnippet = createRawSnippet<[{ number?: string | null }]>((getNumber) => {
|
||||
const { number } = getNumber();
|
||||
return {
|
||||
render: () =>
|
||||
`<code class="relative rounded bg-muted px-[0.3rem] py-[0.2rem] font-mono text-sm font-semibold">${number || 'N/A'}</code>`
|
||||
};
|
||||
});
|
||||
return renderSnippet(numberSnippet, { number: row.original.invoice_number });
|
||||
}
|
||||
},
|
||||
{
|
||||
accessorKey: "project_number",
|
||||
header: "Proyecto",
|
||||
|
||||
@@ -16,56 +16,9 @@
|
||||
exists?: boolean;
|
||||
} = $props();
|
||||
|
||||
if (!formData && invoice?.financials) {
|
||||
if (!formData && invoice) {
|
||||
formData = {
|
||||
// Currency & Exchange
|
||||
currency: invoice.financials.currency || '',
|
||||
currency_type: invoice.financials.currency_type || '',
|
||||
exchange_rate: invoice.financials.exchange_rate || null,
|
||||
exchange_rate_mm: invoice.financials.exchange_rate_mm || null,
|
||||
// Values
|
||||
value_mn: invoice.financials.value_mn || null,
|
||||
value_me: invoice.financials.value_me || null,
|
||||
value_mc: invoice.financials.value_mc || null,
|
||||
customs_value_mn: invoice.financials.customs_value_mn || null,
|
||||
customs_value_me: invoice.financials.customs_value_me || null,
|
||||
// Raw materials
|
||||
raw_material_value_mn: invoice.financials.raw_material_value_mn || null,
|
||||
raw_material_value_me: invoice.financials.raw_material_value_me || null,
|
||||
// Aggregate values
|
||||
aggregate_value_mn: invoice.financials.aggregate_value_mn || null,
|
||||
aggregate_value_me: invoice.financials.aggregate_value_me || null,
|
||||
aggregate_value_mc: invoice.financials.aggregate_value_mc || null,
|
||||
// Mexican values
|
||||
mexican_value_mn: invoice.financials.mexican_value_mn || null,
|
||||
mexican_value_me: invoice.financials.mexican_value_me || null,
|
||||
mexican_value_mc: invoice.financials.mexican_value_mc || null,
|
||||
// National packaging
|
||||
national_packaging_mn: invoice.financials.national_packaging_mn || null,
|
||||
national_packaging_me: invoice.financials.national_packaging_me || null,
|
||||
national_packaging_mc: invoice.financials.national_packaging_mc || null,
|
||||
// Costs & increments
|
||||
freight: invoice.financials.freight || null,
|
||||
insurance: invoice.financials.insurance || null,
|
||||
insurance_value: invoice.financials.insurance_value || null,
|
||||
packaging: invoice.financials.packaging || null,
|
||||
other_increments: invoice.financials.other_increments || null,
|
||||
total_increments_mn: invoice.financials.total_increments_mn || null,
|
||||
total_increments_me: invoice.financials.total_increments_me || null,
|
||||
// Taxes
|
||||
iva_mn: invoice.financials.iva_mn || null,
|
||||
iva_me: invoice.financials.iva_me || null,
|
||||
iva_mc: invoice.financials.iva_mc || null,
|
||||
iva_factor: invoice.financials.iva_factor || '',
|
||||
tax_value_me: invoice.financials.tax_value_me || null,
|
||||
seal_value_2500: invoice.financials.seal_value_2500 || false,
|
||||
// Weights & quantities
|
||||
total_quantity: invoice.financials.total_quantity || null,
|
||||
gross_weight: invoice.financials.gross_weight || null,
|
||||
net_weight: invoice.financials.net_weight || null,
|
||||
bundle_count: invoice.financials.bundle_count || null,
|
||||
weight_factor: invoice.financials.weight_factor || null,
|
||||
// Additional fields not in backend
|
||||
// Campos de esta pestaña
|
||||
numero_tipo_transporte: '',
|
||||
es_ferrocarril: 'no',
|
||||
numero_bl: '',
|
||||
@@ -88,54 +41,7 @@
|
||||
exists = true;
|
||||
} else if (!formData) {
|
||||
formData = {
|
||||
// Currency & Exchange
|
||||
currency: '',
|
||||
currency_type: '',
|
||||
exchange_rate: null,
|
||||
exchange_rate_mm: null,
|
||||
// Values
|
||||
value_mn: null,
|
||||
value_me: null,
|
||||
value_mc: null,
|
||||
customs_value_mn: null,
|
||||
customs_value_me: null,
|
||||
// Raw materials
|
||||
raw_material_value_mn: null,
|
||||
raw_material_value_me: null,
|
||||
// Aggregate values
|
||||
aggregate_value_mn: null,
|
||||
aggregate_value_me: null,
|
||||
aggregate_value_mc: null,
|
||||
// Mexican values
|
||||
mexican_value_mn: null,
|
||||
mexican_value_me: null,
|
||||
mexican_value_mc: null,
|
||||
// National packaging
|
||||
national_packaging_mn: null,
|
||||
national_packaging_me: null,
|
||||
national_packaging_mc: null,
|
||||
// Costs & increments
|
||||
freight: null,
|
||||
insurance: null,
|
||||
insurance_value: null,
|
||||
packaging: null,
|
||||
other_increments: null,
|
||||
total_increments_mn: null,
|
||||
total_increments_me: null,
|
||||
// Taxes
|
||||
iva_mn: null,
|
||||
iva_me: null,
|
||||
iva_mc: null,
|
||||
iva_factor: '',
|
||||
tax_value_me: null,
|
||||
seal_value_2500: false,
|
||||
// Weights & quantities
|
||||
total_quantity: null,
|
||||
gross_weight: null,
|
||||
net_weight: null,
|
||||
bundle_count: null,
|
||||
weight_factor: null,
|
||||
// Additional fields not in backend
|
||||
// Campos de esta pestaña
|
||||
numero_tipo_transporte: '',
|
||||
es_ferrocarril: 'no',
|
||||
numero_bl: '',
|
||||
|
||||
@@ -24,7 +24,8 @@
|
||||
customsSections = [],
|
||||
codePedimentoRegimens = [],
|
||||
defaultOperationType = undefined,
|
||||
defaultInvoiceType = undefined
|
||||
defaultInvoiceType = undefined,
|
||||
operationType = undefined
|
||||
}: {
|
||||
invoice: Invoice | null;
|
||||
formData?: any;
|
||||
@@ -42,48 +43,27 @@
|
||||
codePedimentoRegimens?: any[];
|
||||
defaultOperationType?: number | null;
|
||||
defaultInvoiceType?: string | null;
|
||||
operationType?: number | null;
|
||||
} = $props();
|
||||
|
||||
if (!formData) {
|
||||
if (invoice) {
|
||||
// Editando una factura existente
|
||||
let operationType: number | null = null;
|
||||
if (invoice.operation_type) {
|
||||
operationType = invoice.operation_type === 'exp' ? 1 : 2;
|
||||
}
|
||||
|
||||
formData = {
|
||||
// TOP fields
|
||||
is_pedimento_pending: false,
|
||||
pedimento: invoice.compliance_mx?.pedimento || '',
|
||||
remesa: invoice.compliance_mx?.remesa || '',
|
||||
invoice_number: invoice.invoice_number || '',
|
||||
invoice_date: invoice.invoice_date || '',
|
||||
emission_date: '',
|
||||
|
||||
// Extra fields
|
||||
operation_type: operationType,
|
||||
|
||||
// RANGO DE FECHAS fields
|
||||
fecha_pedimento_del: '',
|
||||
fecha_pedimento_al: '',
|
||||
clave_pedimento: '',
|
||||
regimen_pedimento: '',
|
||||
|
||||
// LEFT fields
|
||||
provider_header: invoice.compliance_mx?.provider_header || '',
|
||||
provider_header: invoice.compliance_mx?.provider_header || 'proveedor',
|
||||
provider_id: invoice.compliance_mx?.provider_id || null,
|
||||
sold_to_header: invoice.compliance_mx?.sold_to_header || '',
|
||||
sold_to_header: invoice.compliance_mx?.sold_to_header || 'consignado_a',
|
||||
sold_to_id: invoice.compliance_mx?.sold_to_id || null,
|
||||
shipped_to_header: invoice.compliance_mx?.shipped_to_header || '',
|
||||
shipped_to_header: invoice.compliance_mx?.shipped_to_header || 'enviado_a',
|
||||
shipped_to_id: invoice.compliance_mx?.shipped_to_id || null,
|
||||
customs_broker_id: invoice.compliance_mx?.customs_broker_id || null,
|
||||
customs_broker_us_id: null,
|
||||
customs_broker_us_id: invoice.compliance_mx?.customs_broker_us_id || null,
|
||||
|
||||
// RIGHT fields
|
||||
currency_type: invoice.financials?.currency_type || '',
|
||||
currency_mode: 'extranjera', // extranjera, nacional, captura
|
||||
weight_type: '',
|
||||
currency: invoice.financials?.currency || 'foreign', // foreign, local, manual
|
||||
weight_type: 'kgs',
|
||||
iva_factor: invoice.financials?.iva_factor || null,
|
||||
carrier_id: invoice.logistics?.[0]?.carrier_id || null,
|
||||
transport_id: '',
|
||||
@@ -91,43 +71,26 @@
|
||||
transport_type: invoice.logistics?.[0]?.transport_type || '',
|
||||
transport_num: invoice.logistics?.[0]?.vehicle_num || '',
|
||||
aduana: invoice.compliance_mx?.aduana || '',
|
||||
invoice_type: invoice.invoice_type || '',
|
||||
clave_regimen_aduanero: '',
|
||||
document_type: invoice.document_type || '',
|
||||
};
|
||||
console.log('FormData cargado para edición:', formData);
|
||||
} else {
|
||||
// Creando una nueva factura
|
||||
formData = {
|
||||
// TOP fields
|
||||
is_pedimento_pending: false,
|
||||
pedimento: '',
|
||||
remesa: '',
|
||||
invoice_number: '',
|
||||
invoice_date: '',
|
||||
emission_date: '',
|
||||
|
||||
// Extra fields
|
||||
operation_type: defaultOperationType ?? null,
|
||||
|
||||
// RANGO DE FECHAS fields
|
||||
fecha_pedimento_del: '',
|
||||
fecha_pedimento_al: '',
|
||||
clave_pedimento: '',
|
||||
regimen_pedimento: '',
|
||||
|
||||
// LEFT fields
|
||||
provider_header: '',
|
||||
provider_header: 'proveedor',
|
||||
provider_id: null,
|
||||
sold_to_header: '',
|
||||
sold_to_header: 'consignado_a',
|
||||
sold_to_id: null,
|
||||
shipped_to_header: '',
|
||||
shipped_to_header: 'enviado_a',
|
||||
shipped_to_id: null,
|
||||
customs_broker_id: null,
|
||||
customs_broker_us_id: null,
|
||||
|
||||
// RIGHT fields
|
||||
currency_type: '',
|
||||
currency_mode: 'extranjera', // extranjera, nacional, captura
|
||||
weight_type: '',
|
||||
currency: 'foreign', // foreign, local, manual
|
||||
weight_type: 'kgs',
|
||||
iva_factor: null,
|
||||
carrier_id: null,
|
||||
transport_id: '',
|
||||
@@ -135,21 +98,29 @@
|
||||
transport_type: '',
|
||||
transport_num: '',
|
||||
aduana: '',
|
||||
invoice_type: defaultInvoiceType ?? '',
|
||||
clave_regimen_aduanero: '',
|
||||
document_type: '',
|
||||
};
|
||||
}
|
||||
} else {
|
||||
// Si formData ya existe, asegurar que tiene currency_mode
|
||||
if (formData.currency_mode === undefined) {
|
||||
formData.currency_mode = 'extranjera';
|
||||
// Si formData ya existe, asegurar que tiene valores por defecto
|
||||
if (formData.currency === undefined) {
|
||||
formData.currency = 'foreign';
|
||||
}
|
||||
if (!formData.provider_header) {
|
||||
formData.provider_header = 'proveedor';
|
||||
}
|
||||
if (!formData.sold_to_header) {
|
||||
formData.sold_to_header = 'consignado_a';
|
||||
}
|
||||
if (!formData.shipped_to_header) {
|
||||
formData.shipped_to_header = 'enviado_a';
|
||||
}
|
||||
}
|
||||
|
||||
// Opciones de tipo de peso
|
||||
const weightTypeOptions = [
|
||||
{ value: 'kg', label: 'Kilogramos (kg)' },
|
||||
{ value: 'lb', label: 'Libras (lb)' }
|
||||
{ value: 'kgs', label: 'Kilogramos (kg)' },
|
||||
{ value: 'lbs', label: 'Libras (lb)' }
|
||||
];
|
||||
|
||||
// Opciones de encabezados
|
||||
@@ -161,11 +132,11 @@
|
||||
const soldToHeaderOptions = $derived([
|
||||
{ value: 'consignado_a', label: 'Consignado a' },
|
||||
{ value: 'vendido_a', label: 'Vendido a' },
|
||||
{ value: formData.operation_type === 1 ? 'exportado_a' : 'importador', label: formData.operation_type === 1 ? 'Exportado a' : 'Importador' }
|
||||
{ value: operationType === 1 ? 'exportado_a' : 'importador', label: operationType === 1 ? 'Exportado a' : 'Importador' }
|
||||
]);
|
||||
|
||||
const shippedToHeaderOptions = $derived(
|
||||
formData.operation_type === 1
|
||||
operationType === 1
|
||||
? [
|
||||
{ value: 'enviado_por', label: 'Enviado Por' },
|
||||
{ value: 'destinatario', label: 'Destinatario' },
|
||||
@@ -189,7 +160,7 @@
|
||||
|
||||
// Filtrar regímenes por tipo de operación (1='E' exp, 2='I' imp) y obtener valores únicos
|
||||
const filteredRegimens = $derived.by(() => {
|
||||
const typeCode = formData.operation_type === 1 ? 'E' : formData.operation_type === 2 ? 'I' : null;
|
||||
const typeCode = operationType === 1 ? 'E' : operationType === 2 ? 'I' : null;
|
||||
const filtered = codePedimentoRegimens.filter(r => r.type_code === typeCode);
|
||||
|
||||
// Obtener solo regímenes únicos por regimen_code
|
||||
@@ -205,10 +176,10 @@
|
||||
|
||||
// Efecto: Limpiar régimen si no existe en los regímenes filtrados al cambiar operation_type
|
||||
$effect(() => {
|
||||
if (formData.clave_regimen_aduanero && filteredRegimens.length > 0) {
|
||||
const regimenExists = filteredRegimens.some(r => r.regimen_code === formData.clave_regimen_aduanero);
|
||||
if (formData.document_type && filteredRegimens.length > 0) {
|
||||
const regimenExists = filteredRegimens.some(r => r.regimen_code === formData.document_type);
|
||||
if (!regimenExists) {
|
||||
formData.clave_regimen_aduanero = '';
|
||||
formData.document_type = '';
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -283,7 +254,8 @@
|
||||
</Select.Item>
|
||||
{/each}
|
||||
</Select.Content>
|
||||
</Select.Root>
|
||||
</Select.Root>
|
||||
<span class="text-red-500">*</span>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-4 gap-3 space-y-1.5">
|
||||
@@ -328,7 +300,8 @@
|
||||
</Select.Item>
|
||||
{/each}
|
||||
</Select.Content>
|
||||
</Select.Root>
|
||||
</Select.Root>
|
||||
<span class="text-red-500">*</span>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-4 gap-3 space-y-1.5">
|
||||
@@ -374,52 +347,55 @@
|
||||
{/each}
|
||||
</Select.Content>
|
||||
</Select.Root>
|
||||
<span class="text-red-500">*</span>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="space-y-1.5">
|
||||
<Label for="customs_broker_id" class="text-xs">Agente Aduanal Mex:</Label>
|
||||
<Label for="customs_broker_id" class="text-xs">Agente Aduanal Mex: <span class="text-red-500">*</span></Label>
|
||||
<Select.Root
|
||||
type="single"
|
||||
value={formData.customs_broker_id || customsBrokers[0]?.broker_key || ''}
|
||||
value={formData.customs_broker_id ? String(formData.customs_broker_id) : ''}
|
||||
onValueChange={(v) => {
|
||||
formData.customs_broker_id = v || null;
|
||||
formData.customs_broker_id = v ? parseInt(v) : null;
|
||||
}}
|
||||
>
|
||||
<Select.Trigger id="customs_broker_id" class="h-7 text-xs min-w-[150px] max-w-[300px]">
|
||||
<span class="truncate">
|
||||
{customsBrokers.find(cb => cb.broker_key === (formData.customs_broker_id || customsBrokers[0]?.broker_key))?.name || '...'}
|
||||
{formData.customs_broker_id
|
||||
? customsBrokers.find(cb => cb.id === formData.customs_broker_id)?.name || 'Selecciona...'
|
||||
: 'Selecciona...'}
|
||||
</span>
|
||||
</Select.Trigger>
|
||||
<Select.Content class="max-h-[300px]">
|
||||
{#each customsBrokers as broker}
|
||||
<Select.Item value={broker.broker_key}>
|
||||
<Select.Item value={broker.id.toString()}>
|
||||
{broker.name}
|
||||
</Select.Item>
|
||||
{/each}
|
||||
</Select.Content>
|
||||
</Select.Root>
|
||||
</Select.Root>
|
||||
</div>
|
||||
|
||||
<div class="space-y-1.5">
|
||||
<Label for="customs_broker_us_id" class="text-xs">Agente Aduanal Ame:</Label>
|
||||
<Select.Root
|
||||
type="single"
|
||||
value={formData.customs_broker_us_id || ''}
|
||||
value={formData.customs_broker_us_id ? String(formData.customs_broker_us_id) : ''}
|
||||
onValueChange={(v) => {
|
||||
formData.customs_broker_us_id = v || null;
|
||||
formData.customs_broker_us_id = v ? parseInt(v) : null;
|
||||
}}
|
||||
>
|
||||
<Select.Trigger id="customs_broker_us_id" class=" min-w-[150px] h-7 text-xs">
|
||||
<span class="truncate">
|
||||
{formData.customs_broker_us_id
|
||||
? customsBrokers.find(cb => cb.broker_key === formData.customs_broker_us_id)?.name || '...'
|
||||
: '...'}
|
||||
? customsBrokers.find(cb => cb.id === formData.customs_broker_us_id)?.name || 'Selecciona...'
|
||||
: 'Selecciona...'}
|
||||
</span>
|
||||
</Select.Trigger>
|
||||
<Select.Content class="max-h-[300px]">
|
||||
{#each customsBrokers as broker}
|
||||
<Select.Item value={broker.broker_key}>
|
||||
<Select.Item value={broker.id.toString()}>
|
||||
{broker.name}
|
||||
</Select.Item>
|
||||
{/each}
|
||||
@@ -439,22 +415,22 @@
|
||||
|
||||
<!-- Radio buttons para tipo de moneda -->
|
||||
<div class="space-y-1.5">
|
||||
<RadioGroup.Root bind:value={formData.currency_mode} class="flex gap-4">
|
||||
<RadioGroup.Root bind:value={formData.currency} class="flex gap-4">
|
||||
<div class="flex items-center space-x-2">
|
||||
<RadioGroup.Item value="extranjera" id="currency-extranjera" class="h-4 w-4" />
|
||||
<Label for="currency-extranjera" class="text-xs font-normal cursor-pointer">Extranjera (Dlls)</Label>
|
||||
<RadioGroup.Item value="foreign" id="currency-foreign" class="h-4 w-4" />
|
||||
<Label for="currency-foreign" class="text-xs font-normal cursor-pointer">Extranjera (Dlls)</Label>
|
||||
</div>
|
||||
<div class="flex items-center space-x-2">
|
||||
<RadioGroup.Item value="nacional" id="currency-nacional" class="h-4 w-4" />
|
||||
<Label for="currency-nacional" class="text-xs font-normal cursor-pointer">Nacional (Pesos)</Label>
|
||||
<RadioGroup.Item value="local" id="currency-local" class="h-4 w-4" />
|
||||
<Label for="currency-local" class="text-xs font-normal cursor-pointer">Nacional (Pesos)</Label>
|
||||
</div>
|
||||
<div class="flex items-center space-x-2">
|
||||
<RadioGroup.Item value="captura" id="currency-captura" class="h-4 w-4" />
|
||||
<Label for="currency-captura" class="text-xs font-normal cursor-pointer">De Captura</Label>
|
||||
<RadioGroup.Item value="manual" id="currency-manual" class="h-4 w-4" />
|
||||
<Label for="currency-manual" class="text-xs font-normal cursor-pointer">De Captura</Label>
|
||||
</div>
|
||||
</RadioGroup.Root>
|
||||
</div>
|
||||
{#if formData.currency_mode === 'captura'}
|
||||
{#if formData.currency === 'manual'}
|
||||
<div class="space-y-1.5">
|
||||
<Label for="currency_type" class="text-xs">Moneda:</Label>
|
||||
<Select.Root
|
||||
@@ -484,19 +460,19 @@
|
||||
<Label for="weight_type" class="text-xs">Tipo Peso:</Label>
|
||||
<Select.Root
|
||||
type="single"
|
||||
value={formData.weight_type || ''}
|
||||
value={formData.weight_type || 'kgs'}
|
||||
onValueChange={(v) => {
|
||||
formData.weight_type = v ?? '';
|
||||
formData.weight_type = v ?? 'kgs';
|
||||
}}
|
||||
>
|
||||
<Select.Trigger id="weight_type" class="min-w-[150px] h-7 text-xs">
|
||||
<span class="truncate">
|
||||
{formData.weight_type || '...'}
|
||||
{weightTypeOptions.find(w => w.value === formData.weight_type)?.label || 'Kilogramos (kg)'}
|
||||
</span>
|
||||
</Select.Trigger>
|
||||
<Select.Content>
|
||||
{#each weightTypeOptions as weightType}
|
||||
<Select.Item value={weightType.label}>
|
||||
<Select.Item value={weightType.value}>
|
||||
{weightType.label}
|
||||
</Select.Item>
|
||||
{/each}
|
||||
@@ -508,7 +484,7 @@
|
||||
<Label for="iva_factor" class="text-xs">IVA:</Label>
|
||||
<Input id="iva_factor" type="number" step="0.0001" bind:value={formData.iva_factor} placeholder="0.16" class="h-7 text-xs" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Transportista -->
|
||||
@@ -700,22 +676,22 @@
|
||||
</div>
|
||||
|
||||
<div class="space-y-1.5">
|
||||
<Label for="clave_regimen_aduanero" class="text-xs">Clave de Régimen Aduanero:</Label>
|
||||
<Label for="document_type" class="text-xs">Clave de Régimen Aduanero: <span class="text-red-500">*</span></Label>
|
||||
<Select.Root
|
||||
type="single"
|
||||
value={formData.clave_regimen_aduanero || ''}
|
||||
value={formData.document_type || ''}
|
||||
onValueChange={(v) => {
|
||||
formData.clave_regimen_aduanero = v ?? '';
|
||||
formData.document_type = v ?? '';
|
||||
}}
|
||||
>
|
||||
<Select.Trigger id="clave_regimen_aduanero" class="h-7 text-xs w-full">
|
||||
<Select.Trigger id="document_type" class="h-7 text-xs w-full">
|
||||
<span class="truncate">
|
||||
{#if formData.clave_regimen_aduanero}
|
||||
{codePedimentoRegimens.find(r => r.regimen_code === formData.clave_regimen_aduanero)?.regimen_code || formData.clave_regimen_aduanero}
|
||||
{#if formData.document_type}
|
||||
{codePedimentoRegimens.find(r => r.regimen_code === formData.document_type)?.regimen_code || formData.document_type}
|
||||
{:else if filteredRegimens.length > 0}
|
||||
Selecciona régimen...
|
||||
{:else if formData.operation_type}
|
||||
Sin regímenes para tipo {formData.operation_type}
|
||||
{:else if operationType}
|
||||
Sin regímenes para tipo {operationType}
|
||||
{:else}
|
||||
Selecciona tipo de operación primero
|
||||
{/if}
|
||||
|
||||
@@ -70,7 +70,7 @@
|
||||
<!-- Datos Principales en una fila compacta (reusable across tabs) -->
|
||||
<div class="grid grid-cols-12 gap-3 items-end pb-3">
|
||||
<div class="col-span-1 space-y-1">
|
||||
<Label for="operation_type" class="text-xs">Tipo de Operación *</Label>
|
||||
<Label for="operation_type" class="text-xs">Tipo de Operación<span class="text-red-500">*</span></Label>
|
||||
<Select.Root
|
||||
type="single"
|
||||
value={formData.operation_type !== null ? String(formData.operation_type) : ''}
|
||||
@@ -92,7 +92,7 @@
|
||||
</Select.Root>
|
||||
</div>
|
||||
<div class="col-span-1 space-y-1">
|
||||
<Label for="operation_type" class="text-xs">Tipo de Operación *</Label>
|
||||
<Label for="operation_type" class="text-xs">Tipo de factura <span class="text-red-500">*</span></Label>
|
||||
<Select.Root
|
||||
type="single"
|
||||
value={formData.invoice_type || ''}
|
||||
@@ -160,12 +160,12 @@
|
||||
</div>
|
||||
|
||||
<div class="col-span-2 space-y-1">
|
||||
<Label for="invoice_number" class="text-xs">Núm. Factura *</Label>
|
||||
<Label for="invoice_number" class="text-xs">Núm. Factura <span class="text-red-500">*</span></Label>
|
||||
<Input id="invoice_number" bind:value={formData.invoice_number} class="h-8 text-sm font-medium" required />
|
||||
</div>
|
||||
|
||||
<div class="col-span-2 space-y-1">
|
||||
<Label for="invoice_date" class="text-xs">Fecha Factura</Label>
|
||||
<Label for="invoice_date" class="text-xs">Fecha Factura <span class="text-red-500">*</span></Label>
|
||||
<Input id="invoice_date" type="date" bind:value={formData.invoice_date} class="h-8 text-sm" />
|
||||
</div>
|
||||
|
||||
|
||||
@@ -23,64 +23,10 @@
|
||||
|
||||
if (!formData && invoice) {
|
||||
formData = {
|
||||
// Invoice header fields
|
||||
// Campos de observaciones
|
||||
observation_es: invoice.observation_es || '',
|
||||
observation_en: invoice.observation_en || '',
|
||||
alternate_invoice: invoice.alternate_invoice || '',
|
||||
// Compliance MX fields
|
||||
pedimento: invoice.compliance_mx?.pedimento || '',
|
||||
pedimento_code: invoice.compliance_mx?.pedimento_code || '',
|
||||
pedimento_k1: invoice.compliance_mx?.pedimento_k1 || '',
|
||||
remesa: invoice.compliance_mx?.remesa || null,
|
||||
aduana: invoice.compliance_mx?.aduana || '',
|
||||
port_of_entry: invoice.compliance_mx?.port_of_entry || '',
|
||||
destination: invoice.compliance_mx?.destination || '',
|
||||
manifest_number: invoice.compliance_mx?.manifest_number || '',
|
||||
provider_header: invoice.compliance_mx?.provider_header || '',
|
||||
provider_id: invoice.compliance_mx?.provider_id || null,
|
||||
sold_to_header: invoice.compliance_mx?.sold_to_header || '',
|
||||
sold_to_id: invoice.compliance_mx?.sold_to_id || null,
|
||||
shipped_to_header: invoice.compliance_mx?.shipped_to_header || '',
|
||||
shipped_to_id: invoice.compliance_mx?.shipped_to_id || null,
|
||||
shipped_by_header: invoice.compliance_mx?.shipped_by_header || '',
|
||||
shipped_by_id: invoice.compliance_mx?.shipped_by_id || null,
|
||||
customs_broker_id: invoice.compliance_mx?.customs_broker_id || null,
|
||||
broker_invoice_num: invoice.compliance_mx?.broker_invoice_num || '',
|
||||
broker_invoice_date: invoice.compliance_mx?.broker_invoice_date || '',
|
||||
is_mixed: invoice.compliance_mx?.is_mixed || null,
|
||||
waste_type: invoice.compliance_mx?.waste_type || '',
|
||||
scrap_type: invoice.compliance_mx?.scrap_type || '',
|
||||
appendix_17: invoice.compliance_mx?.appendix_17 || null,
|
||||
is_regime_change: invoice.compliance_mx?.is_regime_change || '',
|
||||
which_exchange_rate: invoice.compliance_mx?.which_exchange_rate || '',
|
||||
value_method: invoice.compliance_mx?.value_method || '',
|
||||
act_value: invoice.compliance_mx?.act_value || '',
|
||||
is_pedimento_pending: invoice.compliance_mx?.is_pedimento_pending || false,
|
||||
is_owner_of_goods: invoice.compliance_mx?.is_owner_of_goods || '',
|
||||
generate_balances: invoice.compliance_mx?.generate_balances || '',
|
||||
was_reviewed_by_company: invoice.compliance_mx?.was_reviewed_by_company || false,
|
||||
edocument: invoice.compliance_mx?.edocument || '',
|
||||
electronic_signature: invoice.compliance_mx?.electronic_signature || '',
|
||||
certificate_number: invoice.compliance_mx?.certificate_number || '',
|
||||
niu_number: invoice.compliance_mx?.niu_number || '',
|
||||
bill_of_lading_count: invoice.compliance_mx?.bill_of_lading_count || '',
|
||||
addendum_vu: invoice.compliance_mx?.addendum_vu || '',
|
||||
origin_destination_cove: invoice.compliance_mx?.origin_destination_cove || '',
|
||||
vucem_operation_num: invoice.compliance_mx?.vucem_operation_num || '',
|
||||
customs_person_line: invoice.compliance_mx?.customs_person_line || null,
|
||||
contingency_mode: invoice.compliance_mx?.contingency_mode || false,
|
||||
enclosure: invoice.compliance_mx?.enclosure || '',
|
||||
guide_type_to_identify: invoice.compliance_mx?.guide_type_to_identify || '',
|
||||
location: invoice.compliance_mx?.location || '',
|
||||
dot_code: invoice.compliance_mx?.dot_code || '',
|
||||
subdivision: invoice.compliance_mx?.subdivision || '',
|
||||
acts_as: invoice.compliance_mx?.acts_as || '',
|
||||
movement_type: invoice.compliance_mx?.movement_type || '',
|
||||
office_document: invoice.compliance_mx?.office_document || '',
|
||||
reason_export: invoice.compliance_mx?.reason_export || '',
|
||||
signature_key: invoice.compliance_mx?.signature_key || '',
|
||||
sem_id: invoice.compliance_mx?.sem_id || null,
|
||||
// Financials fields (incrementables)
|
||||
observation_en: invoice.observation_en || '',
|
||||
// Incrementables
|
||||
freight: invoice.financials?.freight || null,
|
||||
insurance_value: invoice.financials?.insurance_value || null,
|
||||
insurance: invoice.financials?.insurance || null,
|
||||
@@ -88,70 +34,22 @@
|
||||
other_increments: invoice.financials?.other_increments || null,
|
||||
total_increments_mn: invoice.financials?.total_increments_mn || null,
|
||||
total_increments_me: invoice.financials?.total_increments_me || null,
|
||||
// Logistics fields
|
||||
incoterm: invoice.logistics?.[0]?.incoterm || ''
|
||||
// Incoterm y recinto
|
||||
incoterm: invoice.logistics?.[0]?.incoterm || null,
|
||||
enclosure: invoice.compliance_mx?.enclosure || null,
|
||||
// Campos de esta pestaña
|
||||
num_seals: null,
|
||||
movement_type: invoice.compliance_mx?.movement_type || '',
|
||||
alternate_invoice: invoice.alternate_invoice || '',
|
||||
valuation_method: null
|
||||
};
|
||||
exists = true;
|
||||
} else if (!formData) {
|
||||
formData = {
|
||||
// Invoice header fields
|
||||
// Campos de observaciones
|
||||
observation_es: '',
|
||||
observation_en: '',
|
||||
alternate_invoice: '',
|
||||
// Compliance MX fields
|
||||
pedimento: '',
|
||||
pedimento_code: '',
|
||||
pedimento_k1: '',
|
||||
remesa: null,
|
||||
aduana: '',
|
||||
port_of_entry: '',
|
||||
destination: '',
|
||||
manifest_number: '',
|
||||
provider_header: '',
|
||||
provider_id: null,
|
||||
sold_to_header: '',
|
||||
sold_to_id: null,
|
||||
shipped_to_header: '',
|
||||
shipped_to_id: null,
|
||||
shipped_by_header: '',
|
||||
shipped_by_id: null,
|
||||
customs_broker_id: null,
|
||||
broker_invoice_num: '',
|
||||
broker_invoice_date: '',
|
||||
is_mixed: null,
|
||||
waste_type: '',
|
||||
scrap_type: '',
|
||||
appendix_17: null,
|
||||
is_regime_change: '',
|
||||
which_exchange_rate: '',
|
||||
value_method: '',
|
||||
act_value: '',
|
||||
is_pedimento_pending: false,
|
||||
is_owner_of_goods: '',
|
||||
generate_balances: '',
|
||||
was_reviewed_by_company: false,
|
||||
edocument: '',
|
||||
electronic_signature: '',
|
||||
certificate_number: '',
|
||||
niu_number: '',
|
||||
bill_of_lading_count: '',
|
||||
addendum_vu: '',
|
||||
origin_destination_cove: '',
|
||||
vucem_operation_num: '',
|
||||
customs_person_line: null,
|
||||
contingency_mode: false,
|
||||
enclosure: '',
|
||||
guide_type_to_identify: '',
|
||||
location: '',
|
||||
dot_code: '',
|
||||
subdivision: '',
|
||||
acts_as: '',
|
||||
movement_type: '',
|
||||
office_document: '',
|
||||
reason_export: '',
|
||||
signature_key: '',
|
||||
sem_id: null,
|
||||
// Financials fields
|
||||
observation_en: '',
|
||||
// Incrementables
|
||||
freight: null,
|
||||
insurance_value: null,
|
||||
insurance: null,
|
||||
@@ -159,8 +57,14 @@
|
||||
other_increments: null,
|
||||
total_increments_mn: null,
|
||||
total_increments_me: null,
|
||||
// Logistics fields
|
||||
incoterm: ''
|
||||
// Incoterm y recinto
|
||||
incoterm: null,
|
||||
enclosure: null,
|
||||
// Campos de esta pestaña
|
||||
num_seals: null,
|
||||
movement_type: '',
|
||||
alternate_invoice: '',
|
||||
valuation_method: null
|
||||
};
|
||||
exists = false;
|
||||
}
|
||||
|
||||
@@ -13,116 +13,63 @@
|
||||
let {
|
||||
invoice,
|
||||
formData = $bindable(),
|
||||
exists = $bindable()
|
||||
exists = $bindable(),
|
||||
transportModes = []
|
||||
}: {
|
||||
invoice: Invoice | null;
|
||||
formData?: any;
|
||||
exists?: boolean;
|
||||
transportModes?: any[];
|
||||
} = $props();
|
||||
|
||||
if (!formData && invoice?.logistics && invoice.logistics.length > 0) {
|
||||
formData = invoice.logistics.map(l => ({
|
||||
// Carrier info
|
||||
carrier_id: l.carrier_id || '',
|
||||
transport_id: l.transport_id || '',
|
||||
transport_us_id: l.transport_us_id || '',
|
||||
transport_type: l.transport_type || null,
|
||||
transport_num: l.transport_num || '',
|
||||
transport_mode: l.transport_mode || '',
|
||||
driver_name: l.driver_name || '',
|
||||
is_rail: l.is_rail || '',
|
||||
rail_id: l.rail_id || '',
|
||||
// Vehicle & tracking
|
||||
vehicle_num: l.vehicle_num || '',
|
||||
license_plate: l.license_plate || '',
|
||||
license_plate_complete: l.license_plate_complete || '',
|
||||
trailer_num: l.trailer_num || '',
|
||||
seal_number: l.seal_number || '',
|
||||
guide_number: l.guide_number || '',
|
||||
bill_number: l.bill_number || '',
|
||||
reference_number: l.reference_number || '',
|
||||
shipment_number: l.shipment_number || '',
|
||||
// Incoterms
|
||||
incoterm: l.incoterm || '',
|
||||
// Identifiers
|
||||
identifier_1: l.identifier_1 || '',
|
||||
complement_1: l.complement_1 || '',
|
||||
identifier_2: l.identifier_2 || '',
|
||||
complement_2: l.complement_2 || '',
|
||||
// Weight & container
|
||||
weight_type: l.weight_type || '',
|
||||
container_types: l.container_types || '',
|
||||
vehicle_data: l.vehicle_data || '',
|
||||
// Locations
|
||||
origin_location: l.origin_location || '',
|
||||
destination_location: l.destination_location || '',
|
||||
transport_itinerary: l.transport_itinerary || '',
|
||||
destination_goods: l.destination_goods || '',
|
||||
// Dates
|
||||
entry_exit_date: l.entry_exit_date || '',
|
||||
delivery_date: l.delivery_date || '',
|
||||
// Delivery control
|
||||
delivered_status: l.delivered_status || '',
|
||||
received_by: l.received_by || '',
|
||||
// Payment
|
||||
payment_date: l.payment_date || '',
|
||||
payment_receipt_num: l.payment_receipt_num || '',
|
||||
// CTM
|
||||
is_ctm_process: l.is_ctm_process || ''
|
||||
}));
|
||||
if (!formData && invoice) {
|
||||
formData = {
|
||||
// Campo de comentario estatus
|
||||
comments_status: invoice.comments_status || '',
|
||||
// Campos que van en diferentes recursos pero se editan aquí
|
||||
transport_mode: invoice.logistics?.[0]?.transport_mode || null,
|
||||
is_mixed: invoice.compliance_mx?.is_mixed || null,
|
||||
print_stamp: invoice.financials?.seal_value_2500 || false,
|
||||
rule_3121_parties_ii: false,
|
||||
related_doc_id: invoice.related_doc_id || null,
|
||||
code_signature: invoice.compliance_mx?.code_signature || '',
|
||||
electronic_signature: invoice.compliance_mx?.electronic_signature || '',
|
||||
mandatory_person: '',
|
||||
contingency_mode: invoice.compliance_mx?.contingency_mode || false,
|
||||
cove: invoice.compliance_mx?.origin_destination_cove || '',
|
||||
operation_num: invoice.compliance_mx?.vucem_operation_num || '',
|
||||
adendas: invoice.compliance_mx?.addendum_vu || '',
|
||||
observations_vu: invoice.vu_observations || '',
|
||||
certified_number: invoice.compliance_mx?.certificate_number || '',
|
||||
};
|
||||
exists = true;
|
||||
} else if (!formData) {
|
||||
formData = [];
|
||||
formData = {
|
||||
// Campo de comentario estatus
|
||||
comments_status: '',
|
||||
// Campos que van en diferentes recursos pero se editan aquí
|
||||
transport_mode: 'TRUCK',
|
||||
is_mixed: null,
|
||||
print_stamp: false,
|
||||
rule_3121_parties_ii: false,
|
||||
related_doc_id: null,
|
||||
code_signature: '',
|
||||
electronic_signature: '',
|
||||
mandatory_person: '',
|
||||
contingency_mode: false,
|
||||
cove: '',
|
||||
operation_num: '',
|
||||
adendas: '',
|
||||
observations_vu: '',
|
||||
certified_number: '',
|
||||
};
|
||||
exists = false;
|
||||
}
|
||||
|
||||
// Campos adicionales que van en otros recursos
|
||||
let transportMode = $state('TRUCK');
|
||||
// is_mixed va en compliance_mx
|
||||
let isMixed = $state(invoice?.compliance_mx?.is_mixed ? 'yes' : 'no');
|
||||
// related_doc_id va en invoice header
|
||||
let relationDocsId = $state(invoice?.related_doc_id?.toString() || '0');
|
||||
// electronic_signature va en compliance_mx
|
||||
let code_signature = $state(invoice?.compliance_mx?.code_signature || '');
|
||||
let electronicSignature = $state(invoice?.compliance_mx?.electronic_signature || '');
|
||||
// Estos campos no existen en el schema del backend
|
||||
let mandatoryPerson = $state('0');
|
||||
// Campos que no están en el backend
|
||||
let rfc = $state('');
|
||||
let contingencyMode = $state(invoice?.compliance_mx?.contingency_mode || false);
|
||||
let curp = $state('');
|
||||
let rule3121PartiesII = $state<boolean>(false);
|
||||
// origin_destination_cove va en compliance_mx
|
||||
let cove = $state(invoice?.compliance_mx?.origin_destination_cove || '');
|
||||
// vucem_operation_num va en compliance_mx
|
||||
let operationNum = $state(invoice?.compliance_mx?.vucem_operation_num || '');
|
||||
// addendum_vu va en compliance_mx
|
||||
let adendas = $state(invoice?.compliance_mx?.addendum_vu || '');
|
||||
// vu_observations va en invoice header
|
||||
let observationsVU = $state(invoice?.vu_observations || '');
|
||||
// certificate_number va en compliance_mx
|
||||
let certifiedNumber = $state(invoice?.compliance_mx?.certificate_number || '');
|
||||
// seal_value_2500 va en financials
|
||||
let printStamp = $state(invoice?.financials?.seal_value_2500 || false);
|
||||
// comments_status va en invoice header
|
||||
let commentsStatus = $state(invoice?.comments_status || '');
|
||||
|
||||
const transportModes = [
|
||||
{ value: 'TRUCK', label: 'Camión' },
|
||||
{ value: 'TRAIN', label: 'Tren' },
|
||||
{ value: 'SHIP', label: 'Marítimo' },
|
||||
{ value: 'AIR', label: 'Aéreo' },
|
||||
{ value: 'OTHER', label: 'Otro' }
|
||||
];
|
||||
|
||||
function addLogistic() {
|
||||
formData = [...formData, {
|
||||
carrier_id: '',
|
||||
transport_type: null,
|
||||
driver_name: '',
|
||||
vehicle_num: '',
|
||||
license_plate: ''
|
||||
}];
|
||||
}
|
||||
|
||||
function loadInfo() {
|
||||
// Función para cargar información
|
||||
@@ -136,14 +83,18 @@
|
||||
<!-- Modo de Transporte -->
|
||||
<div class="space-y-2">
|
||||
<Label for="transport-mode">Modo de Transporte:</Label>
|
||||
<Select.Root type="single" value={transportMode} onValueChange={(value: string | undefined) => transportMode = value || 'TRUCK'}>
|
||||
<Select.Root
|
||||
type="single"
|
||||
value={formData.transport_mode}
|
||||
onValueChange={(value: string | undefined) => formData.transport_mode = value || 'TRUCK'}
|
||||
>
|
||||
<Select.Trigger id="transport-mode">
|
||||
{transportModes.find(m => m.value === transportMode)?.label || 'Seleccionar modo'}
|
||||
{transportModes.find(m => m.key === formData.transport_mode)?.name || 'Seleccionar modo'}
|
||||
</Select.Trigger>
|
||||
<Select.Content>
|
||||
{#each transportModes as mode}
|
||||
<Select.Item value={mode.value}>
|
||||
{mode.label}
|
||||
<Select.Item value={mode.key}>
|
||||
{mode.name}
|
||||
</Select.Item>
|
||||
{/each}
|
||||
</Select.Content>
|
||||
@@ -154,7 +105,7 @@
|
||||
<div class="space-y-2">
|
||||
<Label class="opacity-0">Spacer</Label>
|
||||
<div class="flex items-center space-x-2">
|
||||
<Checkbox id="print-stamp" bind:checked={printStamp} />
|
||||
<Checkbox id="print-stamp" bind:checked={formData.print_stamp} />
|
||||
<Label for="print-stamp" class="font-normal">
|
||||
Imprimir el Sello por Valor menor a 2500 dlls
|
||||
</Label>
|
||||
@@ -165,7 +116,11 @@
|
||||
<div class="space-y-2">
|
||||
<Label class="opacity-0">Spacer</Label>
|
||||
<Label>Es Mixto?</Label>
|
||||
<RadioGroup bind:value={isMixed} class="flex gap-4">
|
||||
<RadioGroup
|
||||
value={formData.is_mixed === null ? 'no' : (formData.is_mixed ? 'yes' : 'no')}
|
||||
onValueChange={(v) => formData.is_mixed = v === 'yes'}
|
||||
class="flex gap-4"
|
||||
>
|
||||
<div class="flex items-center space-x-2">
|
||||
<RadioGroupItem value="yes" id="mixed-yes" />
|
||||
<Label for="mixed-yes" class="font-normal">Sí</Label>
|
||||
@@ -179,7 +134,7 @@
|
||||
</div>
|
||||
|
||||
<div class="flex items-center space-x-2">
|
||||
<Checkbox id="rule-3121" bind:checked={rule3121PartiesII} />
|
||||
<Checkbox id="rule-3121" bind:checked={formData.rule_3121_parties_ii} />
|
||||
<Label for="rule-3121" class="font-normal">Regla 3.1.21 Partes II</Label>
|
||||
</div>
|
||||
|
||||
@@ -188,8 +143,8 @@
|
||||
<Label class="opacity-0">Spacer</Label>
|
||||
<Label>Comentario Estatus:</Label>
|
||||
<Textarea
|
||||
id="description_es"
|
||||
bind:value={formData.description_es}
|
||||
id="comments_status"
|
||||
bind:value={formData.comments_status}
|
||||
placeholder="Comentario estatus"
|
||||
rows={3}
|
||||
/>
|
||||
@@ -201,14 +156,18 @@
|
||||
<!-- ID Relación Docs -->
|
||||
<div class="space-y-2">
|
||||
<Label for="relation-docs-id">ID Relación Docs:</Label>
|
||||
<Input id="relation-docs-id" bind:value={relationDocsId} />
|
||||
<Input
|
||||
id="relation-docs-id"
|
||||
type="number"
|
||||
bind:value={formData.related_doc_id}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- Firma Electrónica -->
|
||||
<div class="space-y-2 md:col-span-2">
|
||||
<Label for="electronic-sig-1">Firma Electrónica:</Label>
|
||||
<div class="flex gap-2">
|
||||
<Input id="electronic-sig-1" bind:value={code_signature} class="flex-1" />
|
||||
<Input id="electronic-sig-1" bind:value={formData.code_signature} class="flex-1" />
|
||||
<Button variant="outline" size="icon">
|
||||
<Upload class="h-4 w-4" />
|
||||
</Button>
|
||||
@@ -218,7 +177,7 @@
|
||||
<!-- Mandatario/Persona Autorizada -->
|
||||
<div class="space-y-2">
|
||||
<Label for="mandatory-person">Mandatario/Persona Autorizada:</Label>
|
||||
<Input id="mandatory-person" bind:value={mandatoryPerson} />
|
||||
<Input id="mandatory-person" bind:value={formData.mandatory_person} />
|
||||
</div>
|
||||
|
||||
<!-- RFC -->
|
||||
@@ -234,7 +193,7 @@
|
||||
<!-- Modo Contingencia -->
|
||||
<div class="space-y-2 col-span-4">
|
||||
<div class="flex items-center space-x-2">
|
||||
<Checkbox id="contingency-mode" bind:checked={contingencyMode} />
|
||||
<Checkbox id="contingency-mode" bind:checked={formData.contingency_mode} />
|
||||
<Label for="contingency-mode" class="font-normal">Modo Contingencia</Label>
|
||||
</div>
|
||||
|
||||
@@ -242,26 +201,26 @@
|
||||
<!-- COVE -->
|
||||
<div class="space-y-2">
|
||||
<Label for="cove">COVE:</Label>
|
||||
<Input id="cove" bind:value={cove} placeholder="COVE" />
|
||||
<Input id="cove" bind:value={formData.cove} placeholder="COVE" />
|
||||
</div>
|
||||
|
||||
<!-- Número de Operación -->
|
||||
<div class="space-y-2">
|
||||
<Label for="operation-num">Núm Operación:</Label>
|
||||
<Input id="operation-num" bind:value={operationNum} />
|
||||
<Input id="operation-num" bind:value={formData.operation_num} />
|
||||
</div>
|
||||
|
||||
<!-- Adenda(s) -->
|
||||
<div class="space-y-2 md:col-span-2">
|
||||
<Label for="adendas">Adenda(s):</Label>
|
||||
<Input id="adendas" bind:value={adendas} />
|
||||
<Input id="adendas" bind:value={formData.adendas} />
|
||||
</div>
|
||||
|
||||
<!-- Observaciones VU -->
|
||||
<div class="space-y-2 md:col-span-2">
|
||||
<Label for="observations-vu">Observaciones VU:</Label>
|
||||
<div class="flex gap-2">
|
||||
<Textarea id="observations-vu" bind:value={observationsVU} class="flex-1 min-h-[60px]" />
|
||||
<Textarea id="observations-vu" bind:value={formData.observations_vu} class="flex-1 min-h-[60px]" />
|
||||
<Button variant="outline" onclick={loadInfo}>
|
||||
Cargar Info.
|
||||
</Button>
|
||||
@@ -271,13 +230,13 @@
|
||||
<!-- Número Certificado -->
|
||||
<div class="space-y-2">
|
||||
<Label for="certified-num">Número Certificado:</Label>
|
||||
<Input id="certified-num" bind:value={certifiedNumber} />
|
||||
<Input id="certified-num" bind:value={formData.certified_number} />
|
||||
</div>
|
||||
|
||||
<!-- Firma Electrónica 2 -->
|
||||
<div class="space-y-2 md:col-span-2">
|
||||
<Label for="electronic-sig-2">Firma Electrónica:</Label>
|
||||
<Input id="electronic-sig-2" bind:value={electronicSignature} />
|
||||
<Input id="electronic-sig-2" bind:value={formData.electronic_signature} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -2,10 +2,12 @@ import { goto } from '$app/navigation';
|
||||
import { invoicesApi, type CreateInvoiceData, type UpdateInvoiceData, type OperationType } from '$lib/api/dashboard/a76/invoices';
|
||||
|
||||
interface FormDataSet {
|
||||
InvoiceTopFieldsFormData: any;
|
||||
generalFormData: any;
|
||||
observationFormData: any;
|
||||
itemsFormData: any;
|
||||
othersFormData: any;
|
||||
continuationFormData: any;
|
||||
}
|
||||
|
||||
interface SaveInvoiceOptions {
|
||||
@@ -17,23 +19,33 @@ interface SaveInvoiceOptions {
|
||||
|
||||
export async function saveInvoice(options: SaveInvoiceOptions): Promise<{ success: boolean; error?: string; newInvoiceId?: number }> {
|
||||
const { invoiceId, isCreate, companyId, formData } = options;
|
||||
const { generalFormData, observationFormData, itemsFormData, othersFormData } = formData;
|
||||
const { InvoiceTopFieldsFormData, generalFormData, observationFormData, itemsFormData, othersFormData, continuationFormData } = formData;
|
||||
|
||||
try {
|
||||
// Validar campos requeridos para creación
|
||||
if (isCreate && generalFormData) {
|
||||
if (isCreate) {
|
||||
const requiredFields = {
|
||||
operation_type: 'Tipo de Operación',
|
||||
invoice_type: 'Tipo de Factura',
|
||||
invoice_number: 'Número de Factura'
|
||||
invoice_number: 'Número de Factura',
|
||||
document_type: 'Clave de Régimen Aduanero'
|
||||
};
|
||||
|
||||
const missingFields: string[] = [];
|
||||
for (const [field, label] of Object.entries(requiredFields)) {
|
||||
const value = generalFormData[field];
|
||||
if (value === null || value === undefined || value === '') {
|
||||
missingFields.push(label);
|
||||
}
|
||||
|
||||
// Validar campos de InvoiceTopFieldsFormData
|
||||
if (!InvoiceTopFieldsFormData?.operation_type) {
|
||||
missingFields.push(requiredFields.operation_type);
|
||||
}
|
||||
if (!InvoiceTopFieldsFormData?.invoice_type) {
|
||||
missingFields.push(requiredFields.invoice_type);
|
||||
}
|
||||
if (!InvoiceTopFieldsFormData?.invoice_number) {
|
||||
missingFields.push(requiredFields.invoice_number);
|
||||
}
|
||||
// Validar campos de generalFormData
|
||||
if (!generalFormData?.document_type) {
|
||||
missingFields.push(requiredFields.document_type);
|
||||
}
|
||||
|
||||
if (missingFields.length > 0) {
|
||||
@@ -72,62 +84,65 @@ export async function saveInvoice(options: SaveInvoiceOptions): Promise<{ succes
|
||||
}
|
||||
|
||||
function buildInvoicePayload(formData: FormDataSet): CreateInvoiceData | UpdateInvoiceData {
|
||||
const { generalFormData, observationFormData, itemsFormData, othersFormData } = formData;
|
||||
const { InvoiceTopFieldsFormData, generalFormData, observationFormData, itemsFormData, othersFormData, continuationFormData } = formData;
|
||||
|
||||
const payload: CreateInvoiceData | UpdateInvoiceData = {
|
||||
// Datos generales desde el formulario general
|
||||
// Datos generales desde InvoiceTopFieldsFormData
|
||||
system: 'fixed_asset',
|
||||
operation_type: generalFormData?.operation_type !== null && generalFormData?.operation_type !== undefined
|
||||
? (generalFormData.operation_type === 1 ? 'exp' : 'imp') as OperationType
|
||||
operation_type: InvoiceTopFieldsFormData?.operation_type !== null && InvoiceTopFieldsFormData?.operation_type !== undefined
|
||||
? (InvoiceTopFieldsFormData.operation_type === 1 ? 'exp' : 'imp') as OperationType
|
||||
: undefined,
|
||||
invoice_type: generalFormData?.invoice_type || undefined,
|
||||
invoice_number: generalFormData?.invoice_number || undefined,
|
||||
invoice_date: generalFormData?.invoice_date || undefined,
|
||||
emission_date: generalFormData?.emission_date || undefined,
|
||||
invoice_type: InvoiceTopFieldsFormData?.invoice_type || undefined,
|
||||
document_type: generalFormData?.document_type || undefined,
|
||||
invoice_number: InvoiceTopFieldsFormData?.invoice_number || undefined,
|
||||
invoice_date: InvoiceTopFieldsFormData?.invoice_date || undefined,
|
||||
emission_date: InvoiceTopFieldsFormData?.emission_date || undefined,
|
||||
// Observation fields from observationFormData
|
||||
observation_es: observationFormData?.observation_es || undefined,
|
||||
observation_en: observationFormData?.observation_en || undefined,
|
||||
alternate_invoice: observationFormData?.alternate_invoice || undefined,
|
||||
// Fields from othersFormData that go to invoice header
|
||||
related_doc_id: othersFormData?.related_doc_id || undefined,
|
||||
vu_observations: othersFormData?.observations_vu || undefined,
|
||||
comments_status: othersFormData?.comments_status || undefined,
|
||||
};
|
||||
|
||||
// Solo agregar sub-recursos si tienen valores reales
|
||||
|
||||
// Compliance MX
|
||||
const hasComplianceValue = generalFormData?.pedimento || generalFormData?.remesa || generalFormData?.aduana ||
|
||||
const hasComplianceValue = InvoiceTopFieldsFormData?.pedimento || InvoiceTopFieldsFormData?.remesa || generalFormData?.aduana ||
|
||||
generalFormData?.provider_id || generalFormData?.sold_to_id ||
|
||||
generalFormData?.shipped_to_id || generalFormData?.customs_broker_id ||
|
||||
observationFormData?.pedimento || observationFormData?.pedimento_code ||
|
||||
observationFormData?.remesa || observationFormData?.aduana ||
|
||||
observationFormData?.provider_id || observationFormData?.sold_to_id ||
|
||||
observationFormData?.shipped_to_id || observationFormData?.shipped_by_id ||
|
||||
observationFormData?.customs_broker_id || observationFormData?.is_mixed ||
|
||||
observationFormData?.waste_type || observationFormData?.appendix_17 ||
|
||||
observationFormData?.edocument || observationFormData?.electronic_signature ||
|
||||
observationFormData?.sem_id || observationFormData?.enclosure ||
|
||||
observationFormData?.incoterm;
|
||||
observationFormData?.movement_type || observationFormData?.enclosure ||
|
||||
othersFormData?.is_mixed || othersFormData?.contingency_mode ||
|
||||
othersFormData?.cove || othersFormData?.operation_num ||
|
||||
othersFormData?.adendas || othersFormData?.certified_number ||
|
||||
othersFormData?.code_signature || othersFormData?.electronic_signature;
|
||||
|
||||
if (hasComplianceValue) {
|
||||
payload.compliance_mx = buildComplianceMxData(generalFormData, observationFormData);
|
||||
payload.compliance_mx = buildComplianceMxData(InvoiceTopFieldsFormData, generalFormData, othersFormData, observationFormData);
|
||||
}
|
||||
|
||||
// Financials
|
||||
const hasFinancialsValue = generalFormData?.currency_type ||
|
||||
const hasFinancialsValue = generalFormData?.currency || generalFormData?.currency_type ||
|
||||
generalFormData?.iva_factor ||
|
||||
itemsFormData?.currency || itemsFormData?.exchange_rate ||
|
||||
itemsFormData?.value_mn || itemsFormData?.value_me ||
|
||||
itemsFormData?.customs_value_mn || itemsFormData?.freight ||
|
||||
itemsFormData?.insurance;
|
||||
observationFormData?.freight || observationFormData?.insurance ||
|
||||
observationFormData?.insurance_value || observationFormData?.packaging ||
|
||||
observationFormData?.other_increments || observationFormData?.total_increments_mn ||
|
||||
observationFormData?.total_increments_me || othersFormData?.print_stamp;
|
||||
|
||||
if (hasFinancialsValue) {
|
||||
payload.financials = buildFinancialsData(generalFormData, itemsFormData, observationFormData);
|
||||
payload.financials = buildFinancialsData(generalFormData, observationFormData, othersFormData);
|
||||
}
|
||||
|
||||
// Logistics
|
||||
const hasLogisticsFromGeneral = generalFormData?.carrier_id ||
|
||||
generalFormData?.driver_name || generalFormData?.transport_type || generalFormData?.transport_num;
|
||||
|
||||
if (hasLogisticsFromGeneral || (othersFormData && Array.isArray(othersFormData) && othersFormData.length > 0)) {
|
||||
payload.logistics = buildLogisticsData(generalFormData, othersFormData, observationFormData);
|
||||
const hasLogisticsFromObservations = observationFormData?.incoterm;
|
||||
|
||||
if (hasLogisticsFromGeneral || hasLogisticsFromObservations) {
|
||||
payload.logistics = buildLogisticsData(generalFormData, observationFormData);
|
||||
}
|
||||
|
||||
// Eliminar campos undefined para no enviarlos
|
||||
@@ -140,268 +155,63 @@ function buildInvoicePayload(formData: FormDataSet): CreateInvoiceData | UpdateI
|
||||
return payload;
|
||||
}
|
||||
|
||||
function buildComplianceMxData(generalFormData: any, observationFormData: any) {
|
||||
function buildComplianceMxData(InvoiceTopFieldsFormData: any, generalFormData: any, othersFormData: any, observationFormData: any) {
|
||||
return {
|
||||
// Pedimento fields
|
||||
pedimento: generalFormData?.pedimento || observationFormData?.pedimento || null,
|
||||
pedimento_code: observationFormData?.pedimento_code || null,
|
||||
pedimento_k1: observationFormData?.pedimento_k1 || null,
|
||||
remesa: generalFormData?.remesa || observationFormData?.remesa || null,
|
||||
aduana: generalFormData?.aduana || observationFormData?.aduana || null,
|
||||
port_of_entry: observationFormData?.port_of_entry || null,
|
||||
destination: observationFormData?.destination || null,
|
||||
manifest_number: observationFormData?.manifest_number || null,
|
||||
// Client/Provider fields
|
||||
provider_header: generalFormData?.provider_header || observationFormData?.provider_header || null,
|
||||
provider_id: generalFormData?.provider_id || observationFormData?.provider_id || null,
|
||||
sold_to_header: generalFormData?.sold_to_header || observationFormData?.sold_to_header || null,
|
||||
sold_to_id: generalFormData?.sold_to_id || observationFormData?.sold_to_id || null,
|
||||
shipped_to_header: generalFormData?.shipped_to_header || observationFormData?.shipped_to_header || null,
|
||||
shipped_to_id: generalFormData?.shipped_to_id || observationFormData?.shipped_to_id || null,
|
||||
shipped_by_header: observationFormData?.shipped_by_header || null,
|
||||
shipped_by_id: observationFormData?.shipped_by_id || null,
|
||||
// Customs broker fields
|
||||
customs_broker_id: generalFormData?.customs_broker_id || observationFormData?.customs_broker_id || null,
|
||||
customs_broker_us_id: observationFormData?.customs_broker_us_id || null,
|
||||
broker_invoice_num: observationFormData?.broker_invoice_num || null,
|
||||
broker_invoice_date: observationFormData?.broker_invoice_date || null,
|
||||
// Flags & regimes
|
||||
is_mixed: observationFormData?.is_mixed || null,
|
||||
waste_type: observationFormData?.waste_type || null,
|
||||
scrap_type: observationFormData?.scrap_type || null,
|
||||
appendix_17: observationFormData?.appendix_17 || null,
|
||||
is_regime_change: observationFormData?.is_regime_change || null,
|
||||
which_exchange_rate: observationFormData?.which_exchange_rate || null,
|
||||
value_method: observationFormData?.value_method || null,
|
||||
act_value: observationFormData?.act_value || null,
|
||||
is_pedimento_pending: observationFormData?.is_pedimento_pending || null,
|
||||
// Ownership & balances
|
||||
is_owner_of_goods: observationFormData?.is_owner_of_goods || null,
|
||||
generate_balances: observationFormData?.generate_balances || null,
|
||||
was_reviewed_by_company: observationFormData?.was_reviewed_by_company || null,
|
||||
// VUCEM / Digital
|
||||
edocument: observationFormData?.edocument || null,
|
||||
electronic_signature: observationFormData?.electronic_signature || null,
|
||||
certificate_number: observationFormData?.certificate_number || null,
|
||||
niu_number: observationFormData?.niu_number || null,
|
||||
bill_of_lading_count: observationFormData?.bill_of_lading_count || null,
|
||||
addendum_vu: observationFormData?.addendum_vu || null,
|
||||
origin_destination_cove: observationFormData?.origin_destination_cove || null,
|
||||
vucem_operation_num: observationFormData?.vucem_operation_num || null,
|
||||
customs_person_line: observationFormData?.customs_person_line || null,
|
||||
// Additional control
|
||||
contingency_mode: observationFormData?.contingency_mode || null,
|
||||
enclosure: observationFormData?.enclosure || null,
|
||||
guide_type_to_identify: observationFormData?.guide_type_to_identify || null,
|
||||
location: observationFormData?.location || null,
|
||||
// DOT & official
|
||||
dot_code: observationFormData?.dot_code || null,
|
||||
subdivision: observationFormData?.subdivision || null,
|
||||
acts_as: observationFormData?.acts_as || null,
|
||||
// Pedimento fields - desde InvoiceTopFieldsFormData
|
||||
pedimento: InvoiceTopFieldsFormData?.pedimento || null,
|
||||
remesa: Number(InvoiceTopFieldsFormData?.remesa || null),
|
||||
is_pedimento_pending: Boolean(InvoiceTopFieldsFormData?.is_pedimento_pending || false),
|
||||
// Fields from generalFormData
|
||||
aduana: generalFormData?.aduana || null,
|
||||
provider_header: generalFormData?.provider_header || '',
|
||||
provider_id: generalFormData?.provider_id || null,
|
||||
sold_to_header: generalFormData?.sold_to_header || '',
|
||||
sold_to_id: generalFormData?.sold_to_id || null,
|
||||
shipped_to_header: generalFormData?.shipped_to_header || '',
|
||||
shipped_to_id: generalFormData?.shipped_to_id || null,
|
||||
customs_broker_id: Number(generalFormData?.customs_broker_id || null),
|
||||
customs_broker_us_id: Number(generalFormData?.customs_broker_us_id || null),
|
||||
// Fields from observationFormData
|
||||
movement_type: observationFormData?.movement_type || null,
|
||||
office_document: observationFormData?.office_document || null,
|
||||
reason_export: observationFormData?.reason_export || null,
|
||||
signature_key: observationFormData?.signature_key || null,
|
||||
// SM specific
|
||||
sem_id: observationFormData?.sem_id || null,
|
||||
enclosure: observationFormData?.enclosure || null,
|
||||
// Fields from othersFormData
|
||||
is_mixed: othersFormData?.is_mixed || null,
|
||||
contingency_mode: othersFormData?.contingency_mode || false,
|
||||
origin_destination_cove: othersFormData?.cove || null,
|
||||
vucem_operation_num: othersFormData?.operation_num || null,
|
||||
addendum_vu: othersFormData?.adendas || null,
|
||||
certificate_number: othersFormData?.certified_number || null,
|
||||
code_signature: othersFormData?.code_signature || null,
|
||||
electronic_signature: othersFormData?.electronic_signature || null,
|
||||
};
|
||||
}
|
||||
|
||||
function buildFinancialsData(generalFormData: any, itemsFormData: any, observationFormData: any) {
|
||||
function buildFinancialsData(generalFormData: any, observationFormData: any, othersFormData: any) {
|
||||
return {
|
||||
// Currency
|
||||
currency: itemsFormData?.currency || null,
|
||||
currency_type: generalFormData?.currency_type || itemsFormData?.currency_type || null,
|
||||
exchange_rate: itemsFormData?.exchange_rate || null,
|
||||
exchange_rate_mm: itemsFormData?.exchange_rate_mm || null,
|
||||
// Merchandise values
|
||||
value_mn: itemsFormData?.value_mn || null,
|
||||
value_me: itemsFormData?.value_me || null,
|
||||
value_mc: itemsFormData?.value_mc || null,
|
||||
// Customs value
|
||||
customs_value_mn: itemsFormData?.customs_value_mn || null,
|
||||
customs_value_me: itemsFormData?.customs_value_me || null,
|
||||
// Raw materials
|
||||
raw_material_value_mn: itemsFormData?.raw_material_value_mn || null,
|
||||
raw_material_value_me: itemsFormData?.raw_material_value_me || null,
|
||||
// Aggregate value
|
||||
aggregate_value_mn: itemsFormData?.aggregate_value_mn || null,
|
||||
aggregate_value_me: itemsFormData?.aggregate_value_me || null,
|
||||
aggregate_value_mc: itemsFormData?.aggregate_value_mc || null,
|
||||
// Mexican merchandise value
|
||||
mexican_value_mn: itemsFormData?.mexican_value_mn || null,
|
||||
mexican_value_me: itemsFormData?.mexican_value_me || null,
|
||||
mexican_value_mc: itemsFormData?.mexican_value_mc || null,
|
||||
// National packaging
|
||||
national_packaging_mn: itemsFormData?.national_packaging_mn || null,
|
||||
national_packaging_me: itemsFormData?.national_packaging_me || null,
|
||||
national_packaging_mc: itemsFormData?.national_packaging_mc || null,
|
||||
// Costs & increments
|
||||
freight: itemsFormData?.freight || observationFormData?.freight || null,
|
||||
insurance: itemsFormData?.insurance || observationFormData?.insurance || null,
|
||||
insurance_value: itemsFormData?.insurance_value || observationFormData?.insurance_value || null,
|
||||
packaging: itemsFormData?.packaging || observationFormData?.packaging || null,
|
||||
other_increments: itemsFormData?.other_increments || observationFormData?.other_increments || null,
|
||||
total_increments_mn: itemsFormData?.total_increments_mn || observationFormData?.total_increments_mn || null,
|
||||
total_increments_me: itemsFormData?.total_increments_me || observationFormData?.total_increments_me || null,
|
||||
// Taxes
|
||||
iva_mn: itemsFormData?.iva_mn || null,
|
||||
iva_me: itemsFormData?.iva_me || null,
|
||||
iva_mc: itemsFormData?.iva_mc || null,
|
||||
iva_factor: generalFormData?.iva_factor || itemsFormData?.iva_factor || null,
|
||||
tax_value_me: itemsFormData?.tax_value_me || null,
|
||||
seal_value_2500: itemsFormData?.seal_value_2500 || null,
|
||||
// Weights & quantities
|
||||
total_quantity: itemsFormData?.total_quantity || null,
|
||||
gross_weight: itemsFormData?.gross_weight || null,
|
||||
net_weight: itemsFormData?.net_weight || null,
|
||||
bundle_count: itemsFormData?.bundle_count || null,
|
||||
weight_factor: itemsFormData?.weight_factor || null,
|
||||
// Currency from generalFormData
|
||||
currency_type: generalFormData?.currency_type || null,
|
||||
currency: generalFormData?.currency || null,
|
||||
iva_factor: generalFormData?.iva_factor || null,
|
||||
// Costs & increments from observationFormData
|
||||
freight: observationFormData?.freight || null,
|
||||
insurance: observationFormData?.insurance || null,
|
||||
insurance_value: observationFormData?.insurance_value || null,
|
||||
packaging: observationFormData?.packaging || null,
|
||||
other_increments: observationFormData?.other_increments || null,
|
||||
total_increments_mn: observationFormData?.total_increments_mn || null,
|
||||
total_increments_me: observationFormData?.total_increments_me || null,
|
||||
// Seal value from othersFormData
|
||||
seal_value_2500: othersFormData?.print_stamp || false,
|
||||
};
|
||||
}
|
||||
|
||||
function buildLogisticsData(generalFormData: any, othersFormData: any, observationFormData: any) {
|
||||
const hasLogisticsFromGeneral = generalFormData?.carrier_id ||
|
||||
generalFormData?.driver_name || generalFormData?.transport_type || generalFormData?.transport_num;
|
||||
|
||||
if (hasLogisticsFromGeneral) {
|
||||
const logisticsEntry = buildLogisticsEntry(generalFormData, observationFormData);
|
||||
|
||||
// Si también hay datos del formulario de others, combinarlos
|
||||
if (othersFormData && Array.isArray(othersFormData) && othersFormData.length > 0) {
|
||||
// Actualizar el primer elemento con datos del general
|
||||
return [
|
||||
mergeLogisticsEntries(generalFormData, othersFormData[0], observationFormData),
|
||||
// Agregar los demás elementos si existen
|
||||
...othersFormData.slice(1).map((item: any) => buildLogisticsEntryFromOther(item, observationFormData))
|
||||
];
|
||||
} else {
|
||||
// Solo datos del general
|
||||
return [logisticsEntry];
|
||||
}
|
||||
} else {
|
||||
// Solo datos del formulario others
|
||||
return othersFormData.map((item: any) => buildLogisticsEntryFromOther(item, observationFormData));
|
||||
}
|
||||
}
|
||||
|
||||
function buildLogisticsEntry(generalFormData: any, observationFormData: any) {
|
||||
return {
|
||||
function buildLogisticsData(generalFormData: any, observationFormData: any) {
|
||||
// Crear un solo entry de logistics con los datos de generalFormData y observationFormData
|
||||
return [{
|
||||
carrier_id: generalFormData?.carrier_id || null,
|
||||
transport_type: generalFormData?.transport_type || null,
|
||||
transport_mode: null,
|
||||
driver_name: generalFormData?.driver_name || null,
|
||||
is_rail: null,
|
||||
rail_id: null,
|
||||
vehicle_num: generalFormData?.transport_num || null,
|
||||
license_plate: null,
|
||||
seal_number: null,
|
||||
guide_number: null,
|
||||
entry_exit_date: null,
|
||||
incoterm: observationFormData?.incoterm || null,
|
||||
};
|
||||
}
|
||||
|
||||
function mergeLogisticsEntries(generalFormData: any, otherData: any, observationFormData: any) {
|
||||
return {
|
||||
// Carrier info
|
||||
carrier_id: generalFormData?.carrier_id || otherData.carrier_id || null,
|
||||
transport_id: otherData.transport_id || null,
|
||||
transport_us_id: otherData.transport_us_id || null,
|
||||
transport_type: generalFormData?.transport_type || otherData.transport_type || null,
|
||||
transport_num: otherData.transport_num || null,
|
||||
transport_mode: otherData.transport_mode || null,
|
||||
driver_name: generalFormData?.driver_name || otherData.driver_name || null,
|
||||
is_rail: otherData.is_rail || null,
|
||||
rail_id: otherData.rail_id || null,
|
||||
// Vehicle & tracking
|
||||
vehicle_num: generalFormData?.transport_num || otherData.vehicle_num || null,
|
||||
license_plate: otherData.license_plate || null,
|
||||
license_plate_complete: otherData.license_plate_complete || null,
|
||||
trailer_num: otherData.trailer_num || null,
|
||||
seal_number: otherData.seal_number || null,
|
||||
guide_number: otherData.guide_number || null,
|
||||
bill_number: otherData.bill_number || null,
|
||||
reference_number: otherData.reference_number || null,
|
||||
shipment_number: otherData.shipment_number || null,
|
||||
// Incoterms
|
||||
incoterm: otherData.incoterm || observationFormData?.incoterm || null,
|
||||
// Identifiers & complements
|
||||
identifier_1: otherData.identifier_1 || null,
|
||||
complement_1: otherData.complement_1 || null,
|
||||
identifier_2: otherData.identifier_2 || null,
|
||||
complement_2: otherData.complement_2 || null,
|
||||
// Weight & container info
|
||||
weight_type: otherData.weight_type || null,
|
||||
container_types: otherData.container_types || null,
|
||||
vehicle_data: otherData.vehicle_data || null,
|
||||
// Locations & routes
|
||||
origin_location: otherData.origin_location || null,
|
||||
destination_location: otherData.destination_location || null,
|
||||
transport_itinerary: otherData.transport_itinerary || null,
|
||||
destination_goods: otherData.destination_goods || null,
|
||||
// Logistics dates
|
||||
entry_exit_date: otherData.entry_exit_date || null,
|
||||
delivery_date: otherData.delivery_date || null,
|
||||
// Delivery control
|
||||
delivered_status: otherData.delivered_status || null,
|
||||
received_by: otherData.received_by || null,
|
||||
// Payment info
|
||||
payment_date: otherData.payment_date || null,
|
||||
payment_receipt_num: otherData.payment_receipt_num || null,
|
||||
// CTM process
|
||||
is_ctm_process: otherData.is_ctm_process || null,
|
||||
};
|
||||
}
|
||||
|
||||
function buildLogisticsEntryFromOther(item: any, observationFormData: any) {
|
||||
return {
|
||||
// Carrier info
|
||||
carrier_id: item.carrier_id || null,
|
||||
transport_id: item.transport_id || null,
|
||||
transport_us_id: item.transport_us_id || null,
|
||||
transport_type: item.transport_type || null,
|
||||
transport_num: item.transport_num || null,
|
||||
transport_mode: item.transport_mode || null,
|
||||
driver_name: item.driver_name || null,
|
||||
is_rail: item.is_rail || null,
|
||||
rail_id: item.rail_id || null,
|
||||
// Vehicle & tracking
|
||||
vehicle_num: item.vehicle_num || null,
|
||||
license_plate: item.license_plate || null,
|
||||
license_plate_complete: item.license_plate_complete || null,
|
||||
trailer_num: item.trailer_num || null,
|
||||
seal_number: item.seal_number || null,
|
||||
guide_number: item.guide_number || null,
|
||||
bill_number: item.bill_number || null,
|
||||
reference_number: item.reference_number || null,
|
||||
shipment_number: item.shipment_number || null,
|
||||
// Incoterms
|
||||
incoterm: item.incoterm || observationFormData?.incoterm || null,
|
||||
// Identifiers & complements
|
||||
identifier_1: item.identifier_1 || null,
|
||||
complement_1: item.complement_1 || null,
|
||||
identifier_2: item.identifier_2 || null,
|
||||
complement_2: item.complement_2 || null,
|
||||
// Weight & container info
|
||||
weight_type: item.weight_type || null,
|
||||
container_types: item.container_types || null,
|
||||
vehicle_data: item.vehicle_data || null,
|
||||
// Locations & routes
|
||||
origin_location: item.origin_location || null,
|
||||
destination_location: item.destination_location || null,
|
||||
transport_itinerary: item.transport_itinerary || null,
|
||||
destination_goods: item.destination_goods || null,
|
||||
// Logistics dates
|
||||
entry_exit_date: item.entry_exit_date || null,
|
||||
delivery_date: item.delivery_date || null,
|
||||
// Delivery control
|
||||
delivered_status: item.delivered_status || null,
|
||||
received_by: item.received_by || null,
|
||||
// Payment info
|
||||
payment_date: item.payment_date || null,
|
||||
payment_receipt_num: item.payment_receipt_num || null,
|
||||
// CTM process
|
||||
is_ctm_process: item.is_ctm_process || null,
|
||||
};
|
||||
}];
|
||||
}
|
||||
|
||||
@@ -137,6 +137,13 @@ export const load: PageServerLoad = async ({ params, cookies, fetch, url }) => {
|
||||
fetch
|
||||
);
|
||||
|
||||
const transportModesPromise = authenticatedFetch(
|
||||
'v1/public/refrence_data/transport-modes/?page=1&page_size=100',
|
||||
{},
|
||||
cookies,
|
||||
fetch
|
||||
);
|
||||
|
||||
// Si el ID es "new", es una creación
|
||||
if (params.id === 'new') {
|
||||
try {
|
||||
@@ -155,7 +162,8 @@ export const load: PageServerLoad = async ({ params, cookies, fetch, url }) => {
|
||||
codePedimentoRegimensResponse,
|
||||
sealsResponse,
|
||||
incotermsResponse,
|
||||
pedimentosResponse
|
||||
pedimentosResponse,
|
||||
transportModesResponse
|
||||
] = await Promise.all([
|
||||
invoiceTypesPromise,
|
||||
customsBrokersPromise,
|
||||
@@ -171,7 +179,8 @@ export const load: PageServerLoad = async ({ params, cookies, fetch, url }) => {
|
||||
codePedimentoRegimensPromise,
|
||||
sealsPromise,
|
||||
incotermsPromise,
|
||||
pedimentosPromise
|
||||
pedimentosPromise,
|
||||
transportModesPromise
|
||||
]);
|
||||
|
||||
const invoiceTypes = invoiceTypesResponse.ok ? await invoiceTypesResponse.json() : { items: [] };
|
||||
@@ -189,6 +198,7 @@ export const load: PageServerLoad = async ({ params, cookies, fetch, url }) => {
|
||||
const seals = sealsResponse.ok ? await sealsResponse.json() : { items: [] };
|
||||
const incoterms = incotermsResponse.ok ? await incotermsResponse.json() : { items: [] };
|
||||
const pedimentos = pedimentosResponse.ok ? await pedimentosResponse.json() : { items: [] };
|
||||
const transportModes = transportModesResponse.ok ? await transportModesResponse.json() : { items: [] };
|
||||
|
||||
return {
|
||||
invoice: null,
|
||||
@@ -209,6 +219,7 @@ export const load: PageServerLoad = async ({ params, cookies, fetch, url }) => {
|
||||
seals: seals.items || [],
|
||||
incoterms: incoterms.items || [],
|
||||
pedimentos: pedimentos.items || [],
|
||||
transportModes: transportModes.items || [],
|
||||
// Filtros desde query parameters para preselección
|
||||
filters: {
|
||||
operation_type: parsedOperationType,
|
||||
@@ -237,6 +248,7 @@ export const load: PageServerLoad = async ({ params, cookies, fetch, url }) => {
|
||||
seals: [],
|
||||
incoterms: [],
|
||||
pedimentos: [],
|
||||
transportModes: [],
|
||||
filters: {
|
||||
operation_type: parsedOperationType,
|
||||
invoice_type: invoiceTypeParam || null
|
||||
@@ -281,7 +293,8 @@ export const load: PageServerLoad = async ({ params, cookies, fetch, url }) => {
|
||||
codePedimentoRegimensResponse,
|
||||
sealsResponse,
|
||||
incotermsResponse,
|
||||
pedimentosResponse
|
||||
pedimentosResponse,
|
||||
transportModesResponse
|
||||
] = await Promise.all([
|
||||
invoiceTypesPromise,
|
||||
customsBrokersPromise,
|
||||
@@ -297,7 +310,8 @@ export const load: PageServerLoad = async ({ params, cookies, fetch, url }) => {
|
||||
codePedimentoRegimensPromise,
|
||||
sealsPromise,
|
||||
incotermsPromise,
|
||||
pedimentosPromise
|
||||
pedimentosPromise,
|
||||
transportModesPromise
|
||||
]);
|
||||
|
||||
const invoiceTypes = invoiceTypesResponse.ok ? await invoiceTypesResponse.json() : { items: [] };
|
||||
@@ -315,6 +329,7 @@ export const load: PageServerLoad = async ({ params, cookies, fetch, url }) => {
|
||||
const seals = sealsResponse.ok ? await sealsResponse.json() : { items: [] };
|
||||
const incoterms = incotermsResponse.ok ? await incotermsResponse.json() : { items: [] };
|
||||
const pedimentos = pedimentosResponse.ok ? await pedimentosResponse.json() : { items: [] };
|
||||
const transportModes = transportModesResponse.ok ? await transportModesResponse.json() : { items: [] };
|
||||
|
||||
return {
|
||||
invoice,
|
||||
@@ -335,6 +350,7 @@ export const load: PageServerLoad = async ({ params, cookies, fetch, url }) => {
|
||||
seals: seals.items || [],
|
||||
incoterms: incoterms.items || [],
|
||||
pedimentos: pedimentos.items || [],
|
||||
transportModes: transportModes.items || [],
|
||||
// Filtros desde query parameters para preselección
|
||||
filters: {
|
||||
operation_type: parsedOperationType,
|
||||
|
||||
@@ -3,14 +3,12 @@
|
||||
import { browser } from '$app/environment';
|
||||
import { goto } from '$app/navigation';
|
||||
import * as Tabs from '$lib/components/ui/tabs';
|
||||
import * as Alert from '$lib/components/ui/alert';
|
||||
import { Button } from '$lib/components/ui/button';
|
||||
import { Badge } from '$lib/components/ui/badge';
|
||||
import { Separator } from '$lib/components/ui/separator';
|
||||
import { toast } from 'svelte-sonner';
|
||||
import {
|
||||
ArrowLeft,
|
||||
CircleAlert,
|
||||
CircleCheck,
|
||||
FileText,
|
||||
DollarSign,
|
||||
Truck,
|
||||
@@ -62,6 +60,7 @@
|
||||
enclosure?: any[];
|
||||
currencyTypes?: any[];
|
||||
transportTypes?: any[];
|
||||
transportModes?: any[];
|
||||
transporters?: any[];
|
||||
vehicles?: any[];
|
||||
drivers?: any[];
|
||||
@@ -82,22 +81,23 @@
|
||||
|
||||
let activeTab = $state('general');
|
||||
let saving = $state(false);
|
||||
let error = $state<string | null>(null);
|
||||
let success = $state(false);
|
||||
|
||||
// ID de la factura
|
||||
let invoiceId = $state<number | null>(data.invoiceId ?? null);
|
||||
|
||||
// Referencias a los componentes de formulario para obtener sus datos
|
||||
let InvoiceTopFieldsFormData = $state<any>(null);
|
||||
let generalFormData = $state<any>(null);
|
||||
let observationFormData = $state<any>(null);
|
||||
let itemsFormData = $state<any>(null);
|
||||
let othersFormData = $state<any>(null);
|
||||
let continuationFormData = $state<any>(null);
|
||||
|
||||
// Estados para saber si existen datos previos
|
||||
let observationExists = $state(false);
|
||||
let itemsExists = $state(false);
|
||||
let othersExists = $state(false);
|
||||
let continuationExists = $state(false);
|
||||
|
||||
function handleBack() {
|
||||
goto('/dashboard/invoices');
|
||||
@@ -110,8 +110,6 @@
|
||||
|
||||
async function handleSaveAll() {
|
||||
saving = true;
|
||||
error = null;
|
||||
success = false;
|
||||
|
||||
try {
|
||||
const result = await saveInvoice({
|
||||
@@ -119,10 +117,12 @@
|
||||
isCreate: data.isCreate || false,
|
||||
companyId: companyStore?.activeCompany?.id || 0,
|
||||
formData: {
|
||||
InvoiceTopFieldsFormData,
|
||||
generalFormData,
|
||||
observationFormData,
|
||||
itemsFormData,
|
||||
othersFormData
|
||||
othersFormData,
|
||||
continuationFormData
|
||||
}
|
||||
});
|
||||
|
||||
@@ -130,20 +130,20 @@
|
||||
throw new Error(result.error || 'Error al guardar la factura');
|
||||
}
|
||||
|
||||
success = true;
|
||||
setTimeout(() => {
|
||||
success = false;
|
||||
}, 3000);
|
||||
toast.success('Todos los cambios se guardaron correctamente');
|
||||
} catch (e) {
|
||||
console.error('Error saving all:', e);
|
||||
if (e instanceof Error && e.message.includes('401')) {
|
||||
error = 'Sesión expirada. Recargando página...';
|
||||
toast.error('Sesión expirada. Recargando página...');
|
||||
setTimeout(() => {
|
||||
window.location.reload();
|
||||
}, 1500);
|
||||
} else {
|
||||
error = e instanceof Error ? e.message : 'Error al guardar los cambios';
|
||||
const errorMessage = e instanceof Error ? e.message : 'Error al guardar los cambios';
|
||||
toast.error(errorMessage, {
|
||||
description: 'Revisa la consola para más detalles'
|
||||
});
|
||||
}
|
||||
console.error('Error saving all:', e);
|
||||
} finally {
|
||||
saving = false;
|
||||
}
|
||||
@@ -192,29 +192,12 @@
|
||||
|
||||
<Separator />
|
||||
|
||||
<!-- Alertas globales -->
|
||||
{#if error}
|
||||
<Alert.Root variant="destructive">
|
||||
<CircleAlert size={16} />
|
||||
<Alert.Title>Error</Alert.Title>
|
||||
<Alert.Description>{error}</Alert.Description>
|
||||
</Alert.Root>
|
||||
{/if}
|
||||
|
||||
{#if success}
|
||||
<Alert.Root>
|
||||
<CircleCheck size={16} />
|
||||
<Alert.Title>Éxito</Alert.Title>
|
||||
<Alert.Description>Todos los cambios se guardaron correctamente</Alert.Description>
|
||||
</Alert.Root>
|
||||
{/if}
|
||||
|
||||
<!-- Contenido de las tabs con padding inferior para el footer flotante -->
|
||||
<div class="pb-48">
|
||||
<Tabs.Root bind:value={activeTab}>
|
||||
<InvoiceTopFields
|
||||
invoice={data.invoice}
|
||||
bind:formData={generalFormData}
|
||||
bind:formData={InvoiceTopFieldsFormData}
|
||||
invoiceTypes={data.invoiceTypes || []}
|
||||
pedimentos={data.pedimentos || []}
|
||||
defaultOperationType={data.filters?.operation_type ?? undefined}
|
||||
@@ -239,6 +222,7 @@
|
||||
codePedimentoRegimens={data.codePedimentoRegimens || []}
|
||||
defaultOperationType={data.filters?.operation_type ?? undefined}
|
||||
defaultInvoiceType={data.filters?.invoice_type ?? undefined}
|
||||
operationType={InvoiceTopFieldsFormData?.operation_type}
|
||||
/>
|
||||
</Tabs.Content>
|
||||
|
||||
@@ -267,15 +251,16 @@
|
||||
invoice={data.invoice}
|
||||
bind:formData={othersFormData}
|
||||
bind:exists={othersExists}
|
||||
transportModes={data.transportModes || []}
|
||||
/>
|
||||
</Tabs.Content>
|
||||
|
||||
<Tabs.Content value="continuation">
|
||||
<ContinuationTabForm
|
||||
invoice={data.invoice}
|
||||
bind:formData={itemsFormData}
|
||||
bind:exists={itemsExists}
|
||||
/>
|
||||
invoice={data.invoice}
|
||||
bind:formData={continuationFormData}
|
||||
bind:exists={continuationExists}
|
||||
/>
|
||||
</Tabs.Content>
|
||||
</Tabs.Root>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user