Todos los parametros de SCAI montadas y con su sistema CRUD

This commit is contained in:
2026-04-06 16:03:27 -05:00
parent a297592d84
commit ad4fded2ce
16 changed files with 2579 additions and 525 deletions

View File

@@ -991,6 +991,26 @@ class SettingsPayload(BaseModel):
qsisimpo: Optional[QSisImpoSettings] = None
qsisimporep: Optional[QSisImpoRepSettings] = None
qsisexpo: Optional[QSisExpoSettings] = None
# Unified Invoice Settings
invoices: Optional["InvoiceSettingsMap"] = None
class InvoiceSettingsData(BaseModel):
"""Container for form-specific invoice settings"""
InvoiceTopFieldsFormData: Optional[Dict[str, Any]] = None
generalFormData: Optional[Dict[str, Any]] = None
observationFormData: Optional[Dict[str, Any]] = None
itemsFormData: Optional[Dict[str, Any]] = None
othersFormData: Optional[Dict[str, Any]] = None
continuationFormData: Optional[Dict[str, Any]] = None
class InvoiceSettingsMap(BaseModel):
"""
Map of invoice settings indexed by operation_type (imp/exp)
and then by invoice_type.
Example: {"imp": {"factura_importacion": {...}}}
"""
types: Optional[Dict[str, Dict[str, InvoiceSettingsData]]] = None
class AppSettingRequest(BaseModel):
tenant_id: Optional[int] = None

View File

@@ -1,8 +1,6 @@
from typing import List, Optional
from typing import List, Optional, Any, Dict
from sqlalchemy.orm import Session
from sqlalchemy import select
from fastapi import HTTPException
from api.v1.modules.a76.invoice_settings.models import InvoiceSettings
from api.v1.modules.a76.app_settings.service import AppSettingsService
from api.v1.modules.a76.invoice_settings.dto import InvoiceSettingsRequest, OperationType
def get_settings(
@@ -11,60 +9,90 @@ def get_settings(
company_id: int,
invoice_type: str,
operation_type: OperationType
) -> Optional[InvoiceSettings]:
"""Retrieve settings for a specific context"""
stmt = select(InvoiceSettings).where(
InvoiceSettings.tenant_id == tenant_id,
InvoiceSettings.company_id == company_id,
InvoiceSettings.invoice_type == invoice_type,
InvoiceSettings.operation_type == operation_type.value
)
return db.execute(stmt).scalar_one_or_none()
) -> Optional[Dict[str, Any]]:
"""Retrieve settings for a specific context from app_settings"""
# Use AppSettingsService to get the unifed settings
app_settings = AppSettingsService.get_resolved_settings(db, tenant_id, company_id)
if not app_settings:
return None
# Navigate to: invoices -> types -> {operation_type} -> {invoice_type}
invoices = app_settings.get("invoices", {})
types_map = invoices.get("types", {})
op_map = types_map.get(operation_type.value, {})
settings_payload = op_map.get(invoice_type)
if settings_payload is None:
return None
return {
"id": 0, # Virtual ID for compatibility
"tenant_id": tenant_id,
"company_id": company_id,
"invoice_type": invoice_type,
"operation_type": operation_type,
"settings": settings_payload
}
def list_settings(
db: Session,
tenant_id: int,
company_id: int
) -> List[InvoiceSettings]:
"""List all settings for a company"""
stmt = select(InvoiceSettings).where(
InvoiceSettings.tenant_id == tenant_id,
InvoiceSettings.company_id == company_id
)
return db.execute(stmt).scalars().all()
) -> List[Dict[str, Any]]:
"""List all settings for a company from app_settings"""
app_settings = AppSettingsService.get_resolved_settings(db, tenant_id, company_id)
if not app_settings:
return []
invoices = app_settings.get("invoices", {})
types_map = invoices.get("types", {})
results = []
for op_val, op_map in types_map.items():
for inv_type, settings_payload in op_map.items():
results.append({
"id": 0,
"tenant_id": tenant_id,
"company_id": company_id,
"invoice_type": inv_type,
"operation_type": op_val,
"settings": settings_payload
})
return results
def upsert_settings(
db: Session,
tenant_id: int,
company_id: int,
settings_data: InvoiceSettingsRequest
) -> InvoiceSettings:
"""Create or update settings"""
# Check if exists
existing = get_settings(
db,
tenant_id,
company_id,
settings_data.invoice_type,
settings_data.operation_type
)
) -> Dict[str, Any]:
"""Create or update settings in app_settings"""
# Construct the nested structure for AppSettingsService.upsert_settings
# We use deep_merge in AppSettingsService, so we just send the branch we want to update
payload = {
"invoices": {
"types": {
settings_data.operation_type.value: {
settings_data.invoice_type: settings_data.settings
}
}
}
}
if existing:
existing.settings = settings_data.settings
db.commit()
db.refresh(existing)
return existing
# Create new
new_settings = InvoiceSettings(
# Save using the unified service
AppSettingsService.upsert_settings(
db,
tenant_id=tenant_id,
company_id=company_id,
invoice_type=settings_data.invoice_type,
operation_type=settings_data.operation_type.value,
settings=settings_data.settings
settings=payload
)
db.add(new_settings)
db.commit()
db.refresh(new_settings)
return new_settings
# Return the same structure as get_settings for consistency
return {
"id": 0,
"tenant_id": tenant_id,
"company_id": company_id,
"invoice_type": settings_data.invoice_type,
"operation_type": settings_data.operation_type,
"settings": settings_data.settings
}

View File

@@ -13,13 +13,15 @@
formData = $bindable(),
exists = $bindable(),
operationType = undefined,
invoiceType = undefined
invoiceType = undefined,
isSettings = false
}: {
invoice: Invoice | null;
formData?: any;
exists?: boolean;
operationType?: number;
invoiceType?: string;
isSettings?: boolean;
} = $props();
if (!formData && invoice) {
@@ -90,6 +92,15 @@
};
exists = false;
}
$effect.pre(() => {
if (formData) {
if (formData.es_ferrocarril === undefined) formData.es_ferrocarril = 'no';
if (formData.is_mixed === undefined) formData.is_mixed = false;
if (formData.reason_export === undefined) formData.reason_export = '1';
}
});
let showPortModal = $state(false);
function handlePortSelect(section: any) {
@@ -119,7 +130,7 @@
<Input id="vehicle_data" bind:value={formData.vehicle_data} class="mb-2 h-7 text-xs" />
<div class="space-y-1.5">
<Label class="text-xs">Es Ferrocarril?</Label>
<RadioGroup bind:value={formData.es_ferrocarril} class="flex gap-4">
<RadioGroup value={formData.es_ferrocarril} onValueChange={(v) => formData.es_ferrocarril = v} class="flex gap-4">
<div class="flex items-center gap-2">
<RadioGroupItem value="si" id="ferrocarril_si" />
<Label for="ferrocarril_si" class="text-xs">SI</Label>
@@ -203,10 +214,10 @@
{#if operationType === 1 || invoiceType === 'CR'}
<div class="space-y-3 pt-1">
<div class="space-y-1.5">
<div class="space-y-1.5 pt-4">
<Label class="text-xs">Razón de exportación:</Label>
<RadioGroup bind:value={formData.reason_export} class="flex flex-wrap gap-4">
<div class="flex items-center gap-2">
<RadioGroup value={formData.reason_export} onValueChange={(v) => formData.reason_export = v} class="flex flex-wrap gap-4">
<div class="flex items-center space-x-2">
<RadioGroupItem value="1" id="reason_vendido" />
<Label for="reason_vendido" class="text-xs text-muted-foreground">Vendido</Label>
</div>

View File

@@ -33,7 +33,8 @@
operationType = undefined,
defaultOperationType = undefined,
exchangeRate = undefined,
invoiceType = undefined
invoiceType = undefined,
isSettings = false
}: {
invoice: Invoice | null;
formData?: any;
@@ -54,6 +55,7 @@
operationType?: number | null;
exchangeRate?: number | null;
invoiceType?: string;
isSettings?: boolean;
} = $props();
let showManifestModal = $state(false);
@@ -88,7 +90,7 @@
// RIGHT fields
currency_type: invoice.financials?.currency_type || '',
currency: invoice.financials?.currency || 'foreign', // foreign, local, manual
exchange_rate: invoice.financials?.exchange_rate || null, // Added exchange_rate
exchange_rate: invoice.financials?.exchange_rate || null,
weight_type: 'kgs',
iva_factor: invoice.financials?.iva_factor || null,
carrier_id: invoice.logistics?.carrier_id || null,
@@ -120,7 +122,7 @@
// RIGHT fields
currency_type: '',
currency: 'foreign', // foreign, local, manual
exchange_rate: null, // Added exchange_rate
exchange_rate: null,
weight_type: 'kgs',
iva_factor: null,
carrier_id: null,
@@ -135,33 +137,20 @@
electronic_signature: ''
};
}
} else {
// Si formData ya existe, asegurar que tiene valores por defecto
if (formData.currency === undefined) {
formData.currency = 'foreign';
}
$effect.pre(() => {
if (formData) {
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';
if (!formData.shipped_by_header) formData.shipped_by_header = 'enviado_por';
if (formData.manifest_number === undefined) formData.manifest_number = '';
if (formData.code_signature === undefined) formData.code_signature = '';
if (formData.electronic_signature === undefined) formData.electronic_signature = '';
}
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';
}
if (!formData.shipped_by_header) {
formData.shipped_by_header = 'enviado_por';
}
if (formData.manifest_number === undefined) {
formData.manifest_number = '';
}
if (formData.code_signature === undefined) {
formData.code_signature = '';
}
if (formData.electronic_signature === undefined) {
formData.electronic_signature = '';
}
}
});
// Opciones de tipo de peso
const weightTypeOptions = [
@@ -378,7 +367,7 @@
{/each}
</Select.Content>
</Select.Root>
<span class="text-red-500 font-bold">*</span>
{#if !isSettings}<span class="text-red-500 font-bold">*</span>{/if}
<!-- Row 2: Consignado a / Vendido a / Importador -->
<Select.Root
@@ -427,7 +416,7 @@
{/each}
</Select.Content>
</Select.Root>
<span class="text-red-500 font-bold">*</span>
{#if !isSettings}<span class="text-red-500 font-bold">*</span>{/if}
<!-- Row 3: Enviado a -->
<Select.Root
@@ -477,12 +466,12 @@
{/each}
</Select.Content>
</Select.Root>
<span class="text-red-500 font-bold">*</span>
{#if !isSettings}<span class="text-red-500 font-bold">*</span>{/if}
</div>
<div class="space-y-1.5">
<Label for="customs_broker_id" class="text-xs"
>Agente Aduanal Mex: <span class="text-red-500">*</span></Label
>Agente Aduanal Mex: {#if !isSettings}<span class="text-red-500">*</span>{/if}</Label
>
<Select.Root
type="single"

View File

@@ -14,7 +14,8 @@
pedimentos = [],
defaultOperationType = undefined,
defaultInvoiceType = undefined,
invoiceType = undefined
invoiceType = undefined,
isSettings = false
}: {
invoice: Invoice | null;
formData?: any;
@@ -23,6 +24,7 @@
defaultOperationType?: string | null;
defaultInvoiceType?: string | null;
invoiceType?: string;
isSettings?: boolean;
} = $props();
function handlePedimentoChange(pedimentoId: string) {
@@ -68,47 +70,47 @@
});
if (!formData) {
let operationType: string | null = null;
let opType: string | null = null;
if (invoice?.operation_type) {
operationType = invoice.operation_type;
opType = invoice.operation_type;
} else if (defaultOperationType !== undefined) {
operationType = defaultOperationType ?? null;
opType = (defaultOperationType as string) ?? null;
}
formData = {
is_pedimento_pending: false,
pedimento_id: invoice?.compliance_mx?.pedimento_id || '',
remesa: invoice?.compliance_mx?.remesa || '',
invoice_number: invoice?.invoice_number || '',
invoice_date: invoice?.invoice_date || new Date().toISOString().split('T')[0],
emission_date: new Date().toISOString().split('T')[0],
operation_type: operationType,
operation_type: opType,
invoice_type: invoice?.invoice_type || (defaultInvoiceType ?? ''),
// Campos del pedimento (se llenarán al seleccionar un pedimento)
fecha_pedimento_del: '',
fecha_pedimento_al: '',
clave_pedimento: '',
regimen_pedimento: '',
// Campos específicos para MEX
iva_factor: invoice?.financials?.iva_factor || '',
alternate_invoice: invoice?.alternate_invoice || ''
};
} else {
// Si formData ya existe pero operation_type está vacío, usar defaultOperationType
if (
!formData.operation_type &&
defaultOperationType !== undefined &&
defaultOperationType !== null
) {
formData.operation_type = defaultOperationType;
}
$effect.pre(() => {
if (formData) {
if (
!formData.operation_type &&
defaultOperationType !== undefined &&
defaultOperationType !== null
) {
formData.operation_type = defaultOperationType;
}
if (formData.iva_factor === undefined)
formData.iva_factor = invoice?.financials?.iva_factor || '';
if (formData.alternate_invoice === undefined)
formData.alternate_invoice = invoice?.alternate_invoice || '';
}
// Ensure new fields exist if formData was created before
if (formData.iva_factor === undefined)
formData.iva_factor = invoice?.financials?.iva_factor || '';
if (formData.alternate_invoice === undefined)
formData.alternate_invoice = invoice?.alternate_invoice || '';
}
});
// Filter invoice types based on operation type
let filteredInvoiceTypes = $derived(
invoiceTypes.filter((type) => {
@@ -253,34 +255,36 @@
</div>
{/if}
<div class="min-w-[140px] flex-[2] space-y-1">
<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>
{#if !isSettings}
<div class="min-w-[140px] flex-[2] space-y-1">
<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={!isSettings}
/>
</div>
<div class="min-w-[140px] flex-[2] space-y-1">
<Label for="invoice_date" class="text-xs">
{formData.operation_type === 'exp' || invoiceType === 'CR'
? 'Fecha'
: invoiceType === 'MEX'
? 'Fecha de Entrada'
: '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>
<div class="min-w-[140px] flex-[2] space-y-1">
<Label for="invoice_date" class="text-xs">
{formData.operation_type === 'exp' || invoiceType === 'CR'
? 'Fecha'
: invoiceType === 'MEX'
? 'Fecha de Entrada'
: '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>
<div class="min-w-[140px] flex-[2] space-y-1">
<Label for="emission_date" class="text-xs">Fecha Emisión</Label>
<Input id="emission_date" type="date" bind:value={formData.emission_date} class="h-8 text-sm" />
</div>
<div class="min-w-[140px] flex-[2] space-y-1">
<Label for="emission_date" class="text-xs">Fecha Emisión</Label>
<Input id="emission_date" type="date" bind:value={formData.emission_date} class="h-8 text-sm" />
</div>
{/if}
{#if invoiceType === 'MEX'}
<div class="min-w-[90px] flex-1 space-y-1">

View File

@@ -15,7 +15,8 @@
legends = [],
enclosure = [],
operationType = undefined,
invoiceType = undefined
invoiceType = undefined,
isSettings = false
}: {
invoice: Invoice | null;
formData?: any;
@@ -27,6 +28,7 @@
enclosure?: any[];
operationType?: number;
invoiceType?: string;
isSettings?: boolean;
} = $props();
let selectedLegendCode = $state<string>('');

View File

@@ -16,7 +16,8 @@
exists = $bindable(),
transportModes = [],
operationType = undefined,
invoiceType = undefined
invoiceType = undefined,
isSettings = false
}: {
invoice: Invoice | null;
formData?: any;
@@ -24,6 +25,7 @@
transportModes?: any[];
operationType?: number;
invoiceType?: string;
isSettings?: boolean;
} = $props();
if (!formData && invoice) {
@@ -96,6 +98,13 @@
exists = false;
}
$effect.pre(() => {
if (formData) {
if (formData.transport_mode === undefined) formData.transport_mode = 'TRUCK';
if (formData.is_mixed === undefined) formData.is_mixed = false;
}
});
// Campos que no están en el backend
let rfc = $state('');
let curp = $state('');

View File

@@ -0,0 +1,727 @@
<script lang="ts">
import * as Tabs from '$lib/components/ui/tabs';
import { Input } from '$lib/components/ui/input';
import { Label } from '$lib/components/ui/label';
import { Checkbox } from '$lib/components/ui/checkbox';
import { Textarea } from '$lib/components/ui/textarea';
import { RadioGroup, RadioGroupItem } from '$lib/components/ui/radio-group';
let {
formData = $bindable()
}: { formData: any } = $props();
const defaultFormData = {
// General — Reporte de descarga
FraccMexDes: false,
TipoFraccMexDes: false,
ColValorDes: false,
ColPesoDes: false,
// General — Decimales
DecimalesPeso: null,
DecimalesCant: null,
DecimalesCosto: null,
DecimalesValor: null,
// General — Formas de cálculo
BaseCostoMPoTotal: 'materia_prima',
CalVATotAgreMP: 'mp_formula',
CalVABaseCapt: false,
CalEmpaqueBaseCapt: false,
CalPesoBaseDescarga: false,
LocCombinacionParametro: 'F1',
// General — Opciones de descarga
DescargaSust: false,
DescargaClase: false,
DescargaDef: false,
VentQueueAct: false,
ColCantPorPeso: false,
// General 2 — Límites
CantLimiteMin: null,
PesoLimiteMin: null,
ValorLimiteMin: null,
CantLimite: null,
PesoLimite: null,
ValorLimite: null,
PesoNetoDesDifFac: null,
// General 2 — Checkboxes
RestringeExpoMP: false,
OcultCantCons: false,
DescExtraAmePartes: false,
InCambioRegDesc: false,
DescNoContemCant: false,
ValidaCantparCanDes: false,
SolicitarPswdActual: false,
SolicitarContrasenaAdministrador: false,
// Mexicana
PorParteClaseMex: 'parte',
CodigoBarras: false,
CantPNCodBar: false,
DTACeroCodBar: false,
NumParteMex: false,
PaisOrigenMex: false,
FraccionExp: false,
TipoFraccMex: false,
TasaFraccMex: false,
CostoUnitMex: false,
OrdenCompMex: false,
UMEquivalenteMex: false,
ParteComplementariaMex: false,
ParteCompleMexPartida: false,
IncluirFracAmeBil: false,
ImprimirLote: false,
ImprimirNumEntrada: false,
OcultarEmpaqueMex: false,
OcultarFechaHora: false,
ValorDllsMexPesos: false,
CostoUnitMPMex: false,
OcultaColVA: false,
FirmaFMex: '',
// Americana
TomarValorMexEnFacAme: false,
MuestraFree: false,
CodigoSCAC: false,
ValorPacking1Dlls: false,
PrefijoFraccMult: false,
PaisOpcAme: false,
CostAmePaisParte: false,
AsignaFracc9801: false,
ValorExcFracc9801: null,
CalcCostosAmeBaseMex: false,
CostosAmePais: false,
ImprimirOrdenVenta: false,
CalcularValoresAmericanosEnBaseAPartida: false,
PaisOrigenAme: false,
FraccionAme: false,
UMEquivalenteAme: false,
FDAInformacionAME: false,
OrdenCompAme: false,
OcultarEmpaqueAme: false,
LocDecimalesPesosAmericana: null,
LocDecimalesCantidadAme: null,
LocDecimalesCostosAme: null,
LocDecimalesValoresAme: null,
FirmaFAme: '',
InfoAdicional: '',
// Desperdicio
FormaDesperdicio: '0',
// Packing
LocLeyendaPacking: '',
PackingOrdenVenta: false,
IncluirLineaDelPO: false,
PackingPedClave: false
};
if (!formData) formData = { ...defaultFormData };
$effect.pre(() => {
if (formData) {
for (const key in defaultFormData) {
if (formData[key] === undefined) {
formData[key] = defaultFormData[key as keyof typeof defaultFormData];
}
}
}
});
let activeSubTab = $state('general');
</script>
<div class="w-full">
<Tabs.Root bind:value={activeSubTab} class="flex flex-col">
<div class="w-full overflow-x-auto pb-2 mb-4">
<Tabs.List class="inline-flex md:flex w-full bg-muted/60 p-1 rounded-md">
<Tabs.Trigger value="general" class="flex-1 text-xs">General</Tabs.Trigger>
<Tabs.Trigger value="general2" class="flex-1 text-xs">General 2</Tabs.Trigger>
<Tabs.Trigger value="mexicana" class="flex-1 text-xs">Fact. Mexicana</Tabs.Trigger>
<Tabs.Trigger value="americana" class="flex-1 text-xs">Fact. Americana</Tabs.Trigger>
<Tabs.Trigger value="desperdicio" class="flex-1 text-xs">Desperdicio</Tabs.Trigger>
<Tabs.Trigger value="packing" class="flex-1 text-xs">Packing</Tabs.Trigger>
</Tabs.List>
</div>
<!-- ===== GENERAL ===== -->
<Tabs.Content value="general" class="space-y-6">
<!-- Reporte de descarga -->
<div class="space-y-4 border rounded-md p-4 bg-muted/10">
<h4 class="text-sm font-semibold text-muted-foreground uppercase border-b pb-2">Reporte de descarga según el tipo de factura</h4>
<p class="text-xs text-muted-foreground italic">Incluye en la columna descripción:</p>
<div class="grid grid-cols-1 md:grid-cols-2 gap-3 pt-1">
<div class="flex items-center gap-2">
<Checkbox id="cr_FraccMexDes" bind:checked={formData.FraccMexDes} />
<Label for="cr_FraccMexDes" class="text-sm">La Fracción Arancelaria</Label>
</div>
<div class="flex items-center gap-2">
<Checkbox id="cr_TipoFraccMexDes" bind:checked={formData.TipoFraccMexDes} />
<Label for="cr_TipoFraccMexDes" class="text-sm">Preferencia Arancelaria</Label>
</div>
<div class="flex items-center gap-2">
<Checkbox id="cr_ColValorDes" bind:checked={formData.ColValorDes} />
<Label for="cr_ColValorDes" class="text-sm">Ocultar la Columna de Valor del Reporte</Label>
</div>
<div class="flex items-center gap-2">
<Checkbox id="cr_ColPesoDes" bind:checked={formData.ColPesoDes} />
<Label for="cr_ColPesoDes" class="text-sm">Ocultar la Columna de Peso Neto del Reporte</Label>
</div>
</div>
</div>
<!-- Número de decimales -->
<div class="space-y-4 border rounded-md p-4 bg-muted/10">
<h4 class="text-sm font-semibold text-muted-foreground uppercase border-b pb-2">Número de Decimales en los Campos</h4>
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-4 pt-2">
<div class="space-y-1.5">
<Label class="text-xs">De Peso Neto y Bruto</Label>
<Input type="number" bind:value={formData.DecimalesPeso} class="h-8 text-sm" />
</div>
<div class="space-y-1.5">
<Label class="text-xs">De Cantidades</Label>
<Input type="number" bind:value={formData.DecimalesCant} class="h-8 text-sm" />
</div>
<div class="space-y-1.5">
<Label class="text-xs">De Costos Unitarios</Label>
<Input type="number" bind:value={formData.DecimalesCosto} class="h-8 text-sm" />
</div>
<div class="space-y-1.5">
<Label class="text-xs">De Valores</Label>
<Input type="number" bind:value={formData.DecimalesValor} class="h-8 text-sm" />
</div>
</div>
</div>
<!-- Formas de cálculo -->
<div class="space-y-4 border rounded-md p-4 bg-muted/10">
<h4 class="text-sm font-semibold text-muted-foreground uppercase border-b pb-2">Formas del Cálculo de Valores y V.A.</h4>
<div class="grid grid-cols-1 md:grid-cols-2 gap-6 pt-2">
<!-- BaseCostoMPoTotal -->
<div class="space-y-2">
<Label class="text-xs font-semibold">Cálculo del valor con base en costo capturado</Label>
<RadioGroup value={formData.BaseCostoMPoTotal} onValueChange={(v) => formData.BaseCostoMPoTotal = v} class="flex gap-4">
<div class="flex items-center gap-2">
<RadioGroupItem value="materia_prima" id="cr_base_mp" />
<Label for="cr_base_mp" class="text-sm">Materia Prima</Label>
</div>
<div class="flex items-center gap-2">
<RadioGroupItem value="valor_total" id="cr_base_vt" />
<Label for="cr_base_vt" class="text-sm">Valor Total</Label>
</div>
</RadioGroup>
</div>
<!-- CalVATotAgreMP -->
<div class="space-y-2" class:opacity-50={formData.BaseCostoMPoTotal !== 'valor_total'}>
<Label class="text-xs font-semibold">Fórmula de cálculo cuando es por valor total</Label>
<RadioGroup
value={formData.CalVATotAgreMP}
onValueChange={(v) => formData.CalVATotAgreMP = v}
class="flex flex-col gap-2"
>
<div class="flex items-start gap-2">
<RadioGroupItem value="mp_formula" id="cr_calva_mp" class="mt-0.5" />
<Label for="cr_calva_mp" class="text-sm leading-tight">MP = Valor total Valor Agregado</Label>
</div>
<div class="flex items-start gap-2">
<RadioGroupItem value="va_formula" id="cr_calva_va" class="mt-0.5" />
<Label for="cr_calva_va" class="text-sm leading-tight">VA = Valor Total Valor Descarga</Label>
</div>
</RadioGroup>
</div>
</div>
<div class="grid grid-cols-1 md:grid-cols-2 gap-3 pt-4 border-t mt-2">
<div class="flex items-center gap-2">
<Checkbox id="cr_CalVABaseCapt" bind:checked={formData.CalVABaseCapt} />
<Label for="cr_CalVABaseCapt" class="text-sm">Cálculo del Valor Agregado en Base a lo capturado</Label>
</div>
<div class="flex items-center gap-2">
<Checkbox id="cr_CalEmpaqueBaseCapt" bind:checked={formData.CalEmpaqueBaseCapt} />
<Label for="cr_CalEmpaqueBaseCapt" class="text-sm">Cálculo del Valor Empaque en Base a lo capturado</Label>
</div>
<div class="flex items-center gap-2">
<Checkbox id="cr_CalPesoBaseDescarga" bind:checked={formData.CalPesoBaseDescarga} />
<Label for="cr_CalPesoBaseDescarga" class="text-sm">Cálculo de Pesos Neto/Bruto en Base a lo Descargado</Label>
</div>
</div>
<!-- Combinación de Parámetros -->
<div class="pt-4 border-t mt-2 space-y-2">
<Label class="text-xs font-semibold text-muted-foreground uppercase">Combinación de Parámetros</Label>
<RadioGroup value={formData.LocCombinacionParametro} onValueChange={(v) => formData.LocCombinacionParametro = v} class="flex flex-wrap gap-3">
{#each ['F1','F2','F3','F4','F5','F6'] as opt}
<div class="flex items-center gap-1.5">
<RadioGroupItem value={opt} id="cr_comb_{opt}" />
<Label for="cr_comb_{opt}" class="text-sm">{opt}</Label>
</div>
{/each}
</RadioGroup>
</div>
</div>
<!-- Opciones de descarga al actualizar -->
<div class="space-y-4 border rounded-md p-4 bg-muted/10">
<h4 class="text-sm font-semibold text-muted-foreground uppercase border-b pb-2">Opciones de Descarga al Actualizar Factura</h4>
<div class="grid grid-cols-1 md:grid-cols-2 gap-3 pt-2">
<div class="flex items-center gap-2">
<Checkbox id="cr_DescargaSust" bind:checked={formData.DescargaSust} />
<Label for="cr_DescargaSust" class="text-sm">1) En caso de insuficiencias descargar por Sustituto</Label>
</div>
<div class="flex items-center gap-2">
<Checkbox id="cr_DescargaClase" bind:checked={formData.DescargaClase} />
<Label for="cr_DescargaClase" class="text-sm">2) En caso de insuficiencias Descargar por Clase</Label>
</div>
<div class="flex items-center gap-2">
<Checkbox id="cr_DescargaDef" bind:checked={formData.DescargaDef} />
<Label for="cr_DescargaDef" class="text-sm">3) Descarga de definitivo en caso de insuficiencia TEM</Label>
</div>
<div class="flex items-center gap-2">
<Checkbox id="cr_VentQueueAct" bind:checked={formData.VentQueueAct} />
<Label for="cr_VentQueueAct" class="text-sm">Mostrar la ventana de la descarga de la factura</Label>
</div>
<div class="flex items-center gap-2">
<Checkbox id="cr_ColCantPorPeso" bind:checked={formData.ColCantPorPeso} />
<Label for="cr_ColCantPorPeso" class="text-sm">Remplaza Columna Cantidad por la de Peso Neto</Label>
</div>
</div>
</div>
</Tabs.Content>
<!-- ===== GENERAL 2 ===== -->
<Tabs.Content value="general2" class="space-y-6">
<!-- Límites min/max en grid 2 col -->
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<!-- Mínimos -->
<div class="space-y-4 border rounded-md p-4 bg-muted/10">
<h4 class="text-sm font-semibold text-muted-foreground uppercase border-b pb-2">Mínimos límites para actualizar facturas</h4>
<div class="space-y-3 pt-2">
<div class="space-y-1.5">
<Label class="text-xs">Cantidad Mínima para Exportar</Label>
<Input type="number" bind:value={formData.CantLimiteMin} class="h-8 text-sm" />
</div>
<div class="space-y-1.5">
<Label class="text-xs">Peso Mínimo para Exportar</Label>
<Input type="number" bind:value={formData.PesoLimiteMin} class="h-8 text-sm" />
</div>
<div class="space-y-1.5">
<Label class="text-xs">Valor Mínimo para Exportar</Label>
<Input type="number" bind:value={formData.ValorLimiteMin} class="h-8 text-sm" />
</div>
</div>
</div>
<!-- Máximos -->
<div class="space-y-4 border rounded-md p-4 bg-muted/10">
<h4 class="text-sm font-semibold text-muted-foreground uppercase border-b pb-2">Máximos límites para actualizar facturas</h4>
<div class="space-y-3 pt-2">
<div class="space-y-1.5">
<Label class="text-xs">Cantidad Máxima para Exportar</Label>
<Input type="number" bind:value={formData.CantLimite} class="h-8 text-sm" />
</div>
<div class="space-y-1.5">
<Label class="text-xs">Peso Máximo para Exportar</Label>
<Input type="number" bind:value={formData.PesoLimite} class="h-8 text-sm" />
</div>
<div class="space-y-1.5">
<Label class="text-xs">Valor Máximo para Exportar</Label>
<Input type="number" bind:value={formData.ValorLimite} class="h-8 text-sm" />
</div>
</div>
</div>
</div>
<!-- Límite Peso Neto diferencial -->
<div class="border rounded-md p-4 bg-muted/10 space-y-1.5">
<Label class="text-xs font-semibold text-muted-foreground uppercase">Límite entre Peso Neto Fac vs Peso Neto Descarga</Label>
<Input type="number" bind:value={formData.PesoNetoDesDifFac} class="h-8 text-sm max-w-xs" />
</div>
<!-- Opciones -->
<div class="space-y-4 border rounded-md p-4 bg-muted/10">
<h4 class="text-sm font-semibold text-muted-foreground uppercase border-b pb-2">Otras Opciones</h4>
<div class="grid grid-cols-1 md:grid-cols-2 gap-3 pt-2">
<div class="flex items-start gap-2">
<Checkbox id="cr_RestringeExpoMP" bind:checked={formData.RestringeExpoMP} class="mt-0.5" />
<Label for="cr_RestringeExpoMP" class="text-sm leading-snug">Restringe la exportación de Materias Primas (excepto Material EV y EM)</Label>
</div>
<div class="flex items-center gap-2">
<Checkbox id="cr_OcultCantCons" bind:checked={formData.OcultCantCons} />
<Label for="cr_OcultCantCons" class="text-sm">Oculta la Columna Cantidad en el Consolidado</Label>
</div>
<div class="flex items-start gap-2">
<Checkbox id="cr_DescExtraAmePartes" bind:checked={formData.DescExtraAmePartes} class="mt-0.5" />
<Label for="cr_DescExtraAmePartes" class="text-sm leading-snug">Asignar el campo de número de parte desperdicio de partes, en la Descripción Extra Ame</Label>
</div>
<div class="flex items-start gap-2">
<Checkbox id="cr_InCambioRegDesc" bind:checked={formData.InCambioRegDesc} class="mt-0.5" />
<Label for="cr_InCambioRegDesc" class="text-sm leading-snug">Incluye Descargos en Cambios de Régimen Factura Mex. Vertical por Orden Captura</Label>
</div>
<div class="flex items-start gap-2">
<Checkbox id="cr_DescNoContemCant" bind:checked={formData.DescNoContemCant} class="mt-0.5" />
<Label for="cr_DescNoContemCant" class="text-sm leading-snug">No contempla la cantidad de la partida y se va directo al BOM</Label>
</div>
<div class="flex items-start gap-2">
<Checkbox id="cr_ValidaCantparCanDes" bind:checked={formData.ValidaCantparCanDes} class="mt-0.5" />
<Label for="cr_ValidaCantparCanDes" class="text-sm leading-snug">Valida Totales de las Cantidades de las Partidas vs las Cantidades de las Descargas</Label>
</div>
<div class="flex items-center gap-2">
<Checkbox id="cr_SolicitarPswdActual" bind:checked={formData.SolicitarPswdActual} />
<Label for="cr_SolicitarPswdActual" class="text-sm">Solicitar Autorización para Actualizar Facturas</Label>
</div>
<div class="flex items-start gap-2">
<Checkbox id="cr_SolicitarContrasenaAdministrador" bind:checked={formData.SolicitarContrasenaAdministrador} class="mt-0.5" />
<Label for="cr_SolicitarContrasenaAdministrador" class="text-sm leading-snug">Solicitar Autorización para Pasar por Alto la Validación de Temporalidad en Base a la Fecha de Pago de Pedimento</Label>
</div>
</div>
</div>
</Tabs.Content>
<!-- ===== FACTURA MEXICANA ===== -->
<Tabs.Content value="mexicana" class="space-y-6">
<!-- Imprimir por -->
<div class="space-y-4 border rounded-md p-4 bg-muted/10">
<h4 class="text-sm font-semibold text-muted-foreground uppercase">Imprimir por</h4>
<RadioGroup value={formData.PorParteClaseMex} onValueChange={(v) => formData.PorParteClaseMex = v} class="flex gap-4">
<div class="flex items-center gap-2">
<RadioGroupItem value="parte" id="cr_mex_parte" />
<Label for="cr_mex_parte" class="text-sm">Parte</Label>
</div>
<div class="flex items-center gap-2">
<RadioGroupItem value="clase" id="cr_mex_clase" />
<Label for="cr_mex_clase" class="text-sm">Clase</Label>
</div>
</RadioGroup>
</div>
<!-- Grid: Código de barras (izq) + Incluir en descripción (der) -->
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<!-- Código de barras -->
<div class="space-y-3 border rounded-md p-4 bg-muted/10">
<h4 class="text-sm font-semibold text-muted-foreground uppercase border-b pb-2">Código de Barras</h4>
<div class="flex items-center gap-2">
<Checkbox id="cr_CodigoBarras" bind:checked={formData.CodigoBarras} />
<Label for="cr_CodigoBarras" class="text-sm">Imprimir código de barras en la parte inferior</Label>
</div>
<div class="flex items-center gap-2">
<Checkbox id="cr_CantPNCodBar" bind:checked={formData.CantPNCodBar} />
<Label for="cr_CantPNCodBar" class="text-sm">Sustituir la Cantidad por el Peso Neto</Label>
</div>
<div class="flex items-center gap-2">
<Checkbox id="cr_DTACeroCodBar" bind:checked={formData.DTACeroCodBar} />
<Label for="cr_DTACeroCodBar" class="text-sm">Sustituir el valor del DTA por el valor cero</Label>
</div>
<!-- Mostrar en la factura (debajo de código de barras) -->
<h4 class="text-sm font-semibold text-muted-foreground uppercase border-b pb-2 pt-4 mt-4">Mostrar en la Factura</h4>
<div class="flex items-start gap-2">
<Checkbox id="cr_ValorDllsMexPesos" bind:checked={formData.ValorDllsMexPesos} class="mt-0.5" />
<Label for="cr_ValorDllsMexPesos" class="text-sm leading-snug">Total en Dólares al T.C. de la Factura Expo (aplica en moneda nacional)</Label>
</div>
<div class="flex items-center gap-2">
<Checkbox id="cr_CostoUnitMPMex" bind:checked={formData.CostoUnitMPMex} />
<Label for="cr_CostoUnitMPMex" class="text-sm">Costo Unitario Materia Prima</Label>
</div>
<div class="flex items-center gap-2">
<Checkbox id="cr_OcultaColVA" bind:checked={formData.OcultaColVA} />
<Label for="cr_OcultaColVA" class="text-sm">Ocultar Columna de Valor Agregado</Label>
</div>
</div>
<!-- Incluir en descripción -->
<div class="space-y-3 border rounded-md p-4 bg-muted/10">
<h4 class="text-sm font-semibold text-muted-foreground uppercase border-b pb-2">Incluir en la Columna de Descripción</h4>
<div class="flex items-center gap-2">
<Checkbox id="cr_NumParteMex" bind:checked={formData.NumParteMex} />
<Label for="cr_NumParteMex" class="text-sm">El Número de Parte</Label>
</div>
<div class="flex items-center gap-2">
<Checkbox id="cr_PaisOrigenMex" bind:checked={formData.PaisOrigenMex} />
<Label for="cr_PaisOrigenMex" class="text-sm">El País de Origen</Label>
</div>
<div class="flex items-center gap-2">
<Checkbox id="cr_FraccionExp" bind:checked={formData.FraccionExp} />
<Label for="cr_FraccionExp" class="text-sm">La Fracción Arancelaria</Label>
</div>
<div class="flex items-center gap-2">
<Checkbox id="cr_TipoFraccMex" bind:checked={formData.TipoFraccMex} />
<Label for="cr_TipoFraccMex" class="text-sm">Preferencia de la Fracción</Label>
</div>
<div class="flex items-center gap-2">
<Checkbox id="cr_TasaFraccMex" bind:checked={formData.TasaFraccMex} />
<Label for="cr_TasaFraccMex" class="text-sm">La Tasa de la Fracción</Label>
</div>
<div class="flex items-center gap-2">
<Checkbox id="cr_CostoUnitMex" bind:checked={formData.CostoUnitMex} />
<Label for="cr_CostoUnitMex" class="text-sm">El Costo Unitario</Label>
</div>
<div class="flex items-start gap-2">
<Checkbox id="cr_OrdenCompMex" bind:checked={formData.OrdenCompMex} class="mt-0.5" />
<Label for="cr_OrdenCompMex" class="text-sm leading-snug">El No. de Orden de Venta (factura por orden de captura)</Label>
</div>
<div class="flex items-center gap-2">
<Checkbox id="cr_UMEquivalenteMex" bind:checked={formData.UMEquivalenteMex} />
<Label for="cr_UMEquivalenteMex" class="text-sm">La U.M. Equivalente</Label>
</div>
<!-- Parte Complementaria -->
<div class="pt-3 border-t space-y-2">
<p class="text-xs font-semibold text-muted-foreground uppercase">Parte Complementaria de:</p>
<div class="flex items-center gap-2">
<Checkbox id="cr_ParteComplementariaMex" bind:checked={formData.ParteComplementariaMex} />
<Label for="cr_ParteComplementariaMex" class="text-sm">Número de parte</Label>
</div>
<div class="flex items-center gap-2">
<Checkbox id="cr_ParteCompleMexPartida" bind:checked={formData.ParteCompleMexPartida} />
<Label for="cr_ParteCompleMexPartida" class="text-sm">La partida</Label>
</div>
</div>
<div class="flex items-center gap-2">
<Checkbox id="cr_IncluirFracAmeBil" bind:checked={formData.IncluirFracAmeBil} />
<Label for="cr_IncluirFracAmeBil" class="text-sm">La Fracción Americana</Label>
</div>
<div class="flex items-center gap-2">
<Checkbox id="cr_ImprimirLote" bind:checked={formData.ImprimirLote} />
<Label for="cr_ImprimirLote" class="text-sm">Lote</Label>
</div>
<div class="flex items-center gap-2">
<Checkbox id="cr_ImprimirNumEntrada" bind:checked={formData.ImprimirNumEntrada} />
<Label for="cr_ImprimirNumEntrada" class="text-sm">Núm. Entrada</Label>
</div>
</div>
</div>
<!-- Ocultar en factura -->
<div class="space-y-3 border rounded-md p-4 bg-muted/10">
<h4 class="text-sm font-semibold text-muted-foreground uppercase border-b pb-2">Ocultar en Factura</h4>
<div class="grid grid-cols-1 md:grid-cols-2 gap-3 pt-1">
<div class="flex items-center gap-2">
<Checkbox id="cr_OcultarEmpaqueMex" bind:checked={formData.OcultarEmpaqueMex} />
<Label for="cr_OcultarEmpaqueMex" class="text-sm">El Material Tipo (EM)</Label>
</div>
<div class="flex items-center gap-2">
<Checkbox id="cr_OcultarFechaHora" bind:checked={formData.OcultarFechaHora} />
<Label for="cr_OcultarFechaHora" class="text-sm">Ocultar Fecha y Hora</Label>
</div>
</div>
</div>
<!-- Firma -->
<div class="space-y-3 border rounded-md p-4 bg-muted/10">
<Label for="cr_FirmaFMex" class="text-sm font-semibold text-muted-foreground uppercase">Firma en Factura</Label>
<Textarea id="cr_FirmaFMex" bind:value={formData.FirmaFMex} class="h-24 resize-y" />
</div>
</Tabs.Content>
<!-- ===== FACTURA AMERICANA ===== -->
<Tabs.Content value="americana" class="space-y-6">
<!-- Imprimir por: solo Parte -->
<div class="space-y-2 border rounded-md p-4 bg-muted/10">
<h4 class="text-sm font-semibold text-muted-foreground uppercase">Imprimir por</h4>
<p class="text-sm text-muted-foreground">Se imprime por <span class="font-semibold text-foreground">Parte</span></p>
</div>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<!-- Opciones principales -->
<div class="space-y-3 border rounded-md p-4 bg-muted/10">
<h4 class="text-sm font-semibold text-muted-foreground uppercase border-b pb-2">Opciones</h4>
<div class="flex items-center gap-2">
<Checkbox id="cr_TomarValorMexEnFacAme" bind:checked={formData.TomarValorMexEnFacAme} />
<Label for="cr_TomarValorMexEnFacAme" class="text-sm">Toma Valor de la Descarga</Label>
</div>
<div class="flex items-start gap-2">
<Checkbox id="cr_MuestraFree" bind:checked={formData.MuestraFree} class="mt-0.5" />
<Label for="cr_MuestraFree" class="text-sm leading-snug">Muestra FREE si en la columna Duty Rate es 0</Label>
</div>
<div class="flex items-center gap-2">
<Checkbox id="cr_CodigoSCAC" bind:checked={formData.CodigoSCAC} />
<Label for="cr_CodigoSCAC" class="text-sm">Imprimir el Código de Barras SCAC</Label>
</div>
<div class="flex items-center gap-2">
<Checkbox id="cr_ValorPacking1Dlls" bind:checked={formData.ValorPacking1Dlls} />
<Label for="cr_ValorPacking1Dlls" class="text-sm">Valor Packing a 1 Dlls</Label>
</div>
<div class="flex items-start gap-2">
<Checkbox id="cr_PrefijoFraccMult" bind:checked={formData.PrefijoFraccMult} class="mt-0.5" />
<Label for="cr_PrefijoFraccMult" class="text-sm leading-snug">Imprime Prefijo a Nivel Partes en las Fracciones Americanas</Label>
</div>
<div class="flex items-start gap-2">
<Checkbox id="cr_PaisOpcAme" bind:checked={formData.PaisOpcAme} class="mt-0.5" />
<Label for="cr_PaisOpcAme" class="text-sm leading-snug">Mostrar el país opcional para las partidas de la factura</Label>
</div>
<div class="flex items-start gap-2">
<Checkbox id="cr_CostAmePaisParte" bind:checked={formData.CostAmePaisParte} class="mt-0.5" />
<Label for="cr_CostAmePaisParte" class="text-sm leading-snug">Cálculo de los Costos Americanos en Base al País de Origen de la Partida</Label>
</div>
<!-- Fracción 9801 -->
<div class="flex items-center gap-2">
<Checkbox id="cr_AsignaFracc9801" bind:checked={formData.AsignaFracc9801} />
<Label for="cr_AsignaFracc9801" class="text-sm">Asigna fracción 9801 donde el país de origen es USA con valor mayor de:</Label>
</div>
<div class="flex items-center gap-2 pl-6" class:opacity-50={!formData.AsignaFracc9801}>
<Input type="number" bind:value={formData.ValorExcFracc9801} disabled={!formData.AsignaFracc9801} class="h-8 text-sm w-32" />
<span class="text-sm text-muted-foreground">dlls por No. parte</span>
</div>
<div class="flex items-center gap-2">
<Checkbox id="cr_CalcCostosAmeBaseMex" bind:checked={formData.CalcCostosAmeBaseMex} />
<Label for="cr_CalcCostosAmeBaseMex" class="text-sm">Cálculo Especial de Costos Americanos</Label>
</div>
<div class="flex items-start gap-2">
<Checkbox id="cr_CostosAmePais" bind:checked={formData.CostosAmePais} class="mt-0.5" />
<Label for="cr_CostosAmePais" class="text-sm leading-snug">Calcula los Costos Americanos en Base al País de Exportación para las Materias Primas Retornadas</Label>
</div>
<div class="flex items-start gap-2">
<Checkbox id="cr_ImprimirOrdenVenta" bind:checked={formData.ImprimirOrdenVenta} class="mt-0.5" />
<Label for="cr_ImprimirOrdenVenta" class="text-sm leading-snug">Imprimir Orden Venta en Factura Americana Consolidada por Parte</Label>
</div>
<div class="flex items-start gap-2">
<Checkbox id="cr_CalcularValoresAmericanosEnBaseAPartida" bind:checked={formData.CalcularValoresAmericanosEnBaseAPartida} class="mt-0.5" />
<Label for="cr_CalcularValoresAmericanosEnBaseAPartida" class="text-sm leading-snug">Tomar Valores de la Partida en Factura Americana</Label>
</div>
</div>
<!-- Derecha: Incluir en descripción + Ocultar -->
<div class="space-y-4">
<div class="space-y-3 border rounded-md p-4 bg-muted/10">
<h4 class="text-sm font-semibold text-muted-foreground uppercase border-b pb-2">Incluir en Descripción</h4>
<div class="flex items-center gap-2">
<Checkbox id="cr_PaisOrigenAme" bind:checked={formData.PaisOrigenAme} />
<Label for="cr_PaisOrigenAme" class="text-sm">El País de Origen</Label>
</div>
<div class="flex items-center gap-2">
<Checkbox id="cr_FraccionAme" bind:checked={formData.FraccionAme} />
<Label for="cr_FraccionAme" class="text-sm">La Fracción Americana</Label>
</div>
<div class="flex items-center gap-2">
<Checkbox id="cr_UMEquivalenteAme" bind:checked={formData.UMEquivalenteAme} />
<Label for="cr_UMEquivalenteAme" class="text-sm">La U.M. Equivalente</Label>
</div>
<div class="flex items-center gap-2">
<Checkbox id="cr_FDAInformacionAME" bind:checked={formData.FDAInformacionAME} />
<Label for="cr_FDAInformacionAME" class="text-sm">La información del FDA</Label>
</div>
<div class="flex items-center gap-2">
<Checkbox id="cr_OrdenCompAme" bind:checked={formData.OrdenCompAme} />
<Label for="cr_OrdenCompAme" class="text-sm">La Orden de Venta</Label>
</div>
</div>
<div class="space-y-3 border rounded-md p-4 bg-muted/10">
<h4 class="text-sm font-semibold text-muted-foreground uppercase border-b pb-2">Ocultar en Factura y en Generación de Interfase</h4>
<div class="flex items-center gap-2">
<Checkbox id="cr_OcultarEmpaqueAme" bind:checked={formData.OcultarEmpaqueAme} />
<Label for="cr_OcultarEmpaqueAme" class="text-sm">El Material de Empaque (EM)</Label>
</div>
</div>
</div>
</div>
<!-- Decimales + textos -->
<div class="space-y-4 border rounded-md p-4 bg-muted/10">
<h4 class="text-sm font-semibold text-muted-foreground uppercase border-b pb-2">Decimales</h4>
<div class="grid grid-cols-2 md:grid-cols-4 gap-4 pt-2">
<div class="space-y-1.5">
<Label class="text-xs">Peso</Label>
<Input type="number" bind:value={formData.LocDecimalesPesosAmericana} class="h-8 text-sm" />
</div>
<div class="space-y-1.5">
<Label class="text-xs">Cant</Label>
<Input type="number" bind:value={formData.LocDecimalesCantidadAme} class="h-8 text-sm" />
</div>
<div class="space-y-1.5">
<Label class="text-xs">Costos</Label>
<Input type="number" bind:value={formData.LocDecimalesCostosAme} class="h-8 text-sm" />
</div>
<div class="space-y-1.5">
<Label class="text-xs">Valores</Label>
<Input type="number" bind:value={formData.LocDecimalesValoresAme} class="h-8 text-sm" />
</div>
</div>
</div>
<div class="space-y-3 border rounded-md p-4 bg-muted/10">
<Label for="cr_FirmaFAme" class="text-sm font-semibold text-muted-foreground uppercase">Firma de la Factura</Label>
<Textarea id="cr_FirmaFAme" bind:value={formData.FirmaFAme} class="h-24 resize-y" />
</div>
<div class="space-y-3 border rounded-md p-4 bg-muted/10">
<Label for="cr_InfoAdicional" class="text-sm font-semibold text-muted-foreground uppercase">Información Adicional</Label>
<Textarea id="cr_InfoAdicional" bind:value={formData.InfoAdicional} class="h-24 resize-y" />
</div>
</Tabs.Content>
<!-- ===== DESPERDICIO ===== -->
<Tabs.Content value="desperdicio" class="space-y-6">
<div class="space-y-4 border rounded-md p-4 bg-muted/10">
<h4 class="text-sm font-semibold text-muted-foreground uppercase border-b pb-2">Forma de Descarga de Merma y Desperdicio</h4>
<RadioGroup
value={formData.FormaDesperdicio}
onValueChange={(v) => formData.FormaDesperdicio = v}
class="flex flex-col gap-4 pt-2"
>
<div class="flex items-start gap-3 p-3 rounded-md border bg-background">
<RadioGroupItem value="0" id="cr_desp_0" class="mt-0.5" />
<Label for="cr_desp_0" class="text-sm leading-snug cursor-pointer">
<span class="font-semibold">0)</span> No contempla la Merma y Desperdicios
</Label>
</div>
<div class="flex items-start gap-3 p-3 rounded-md border bg-background">
<RadioGroupItem value="1" id="cr_desp_1" class="mt-0.5" />
<Label for="cr_desp_1" class="text-sm leading-snug cursor-pointer">
<span class="font-semibold">1)</span> Descarga Merma y Genera Reporte de Desperdicio
</Label>
</div>
<div class="flex items-start gap-3 p-3 rounded-md border bg-background">
<RadioGroupItem value="2" id="cr_desp_2" class="mt-0.5" />
<Label for="cr_desp_2" class="text-sm leading-snug cursor-pointer">
<span class="font-semibold">2)</span> Genera Reporte de Desperdicio y Merma para ser sugerido
<span class="block text-xs text-muted-foreground mt-0.5">(Aparta el desperdicio para que después sea descargado — primeras entradas/salidas)</span>
</Label>
</div>
<div class="flex items-start gap-3 p-3 rounded-md border bg-background">
<RadioGroupItem value="3" id="cr_desp_3" class="mt-0.5" />
<Label for="cr_desp_3" class="text-sm leading-snug cursor-pointer">
<span class="font-semibold">3)</span> Aparta Desperdicio y Descarga Merma
<span class="block text-xs text-muted-foreground mt-0.5">(Descarga parcialmente el desperdicio y descarga la merma en base a la importación, considerando la cantidad exportada)</span>
</Label>
</div>
</RadioGroup>
</div>
</Tabs.Content>
<!-- ===== PACKING ===== -->
<Tabs.Content value="packing" class="space-y-6">
<div class="space-y-4 border rounded-md p-4 bg-muted/10">
<h4 class="text-sm font-semibold text-muted-foreground uppercase border-b pb-2">Opciones de Packing List</h4>
<div class="space-y-2 pt-2">
<Label for="cr_LocLeyendaPacking" class="text-xs font-semibold text-muted-foreground uppercase">Leyenda Packing (Adicional)</Label>
<Textarea id="cr_LocLeyendaPacking" bind:value={formData.LocLeyendaPacking} class="h-20 resize-y" />
</div>
<div class="grid grid-cols-1 md:grid-cols-2 gap-3 pt-2 border-t mt-4">
<div class="flex items-center gap-2">
<Checkbox id="cr_PackingOrdenVenta" bind:checked={formData.PackingOrdenVenta} />
<Label for="cr_PackingOrdenVenta" class="text-sm">Imprimir Orden de Venta</Label>
</div>
<div class="flex items-center gap-2">
<Checkbox id="cr_IncluirLineaDelPO" bind:checked={formData.IncluirLineaDelPO} />
<Label for="cr_IncluirLineaDelPO" class="text-sm">Incluir Línea Del PO</Label>
</div>
<div class="flex items-center gap-2">
<Checkbox id="cr_PackingPedClave" bind:checked={formData.PackingPedClave} />
<Label for="cr_PackingPedClave" class="text-sm">Imprimir el Pedimento y Clave</Label>
</div>
</div>
</div>
</Tabs.Content>
</Tabs.Root>
</div>

View File

@@ -0,0 +1,363 @@
<script lang="ts">
import * as Tabs from '$lib/components/ui/tabs';
import { Input } from '$lib/components/ui/input';
import { Label } from '$lib/components/ui/label';
import { Checkbox } from '$lib/components/ui/checkbox';
import { Textarea } from '$lib/components/ui/textarea';
import { RadioGroup, RadioGroupItem } from '$lib/components/ui/radio-group';
import { Select, SelectContent, SelectItem, SelectTrigger } from '$lib/components/ui/select';
import { Button } from '$lib/components/ui/button';
import { Search } from 'lucide-svelte';
let {
formData = $bindable(),
drivers = []
}: {
formData: any;
drivers?: any[];
} = $props();
const transportOptions = [
{ value: 'transporte', label: 'Transporte' },
{ value: 'caja', label: 'Caja' },
{ value: 'placas', label: 'Placas' },
{ value: 'camion', label: 'Camión' },
{ value: 'buque', label: 'Buque' },
{ value: 'ferrobarcaza', label: 'Ferrobarcaza' },
{ value: 'contenedor', label: 'Contenedor' },
{ value: 'avion', label: 'Avión' }
];
const defaultFormData = {
// General
Conductor: '',
Transporte: '',
ImpOrdenComp: false,
DecimalesPeso: null,
DecimalesCant: null,
DecimalesCosto: null,
DecimalesValor: null,
// Mexicana
PorParteClaseMex: 'parte',
NumParteMex: false,
TipoFraccMex: false,
TasaFraccMex: false,
UMAlternaMex: false,
PaisOrigenMex: false,
FraccionImp: false,
UMEquivalenteMex: false,
AgregarVAenProdTerminados: false,
OcultarFechaHora: false,
FirmaFMex: '',
// Americana (igual que temporal)
PorParteClaseAMe: 'parte',
NumParteAme: false,
FraccionAme: false,
PaisOrigenAme: false,
UMEquivalenteAme: false,
LeyendaFacAme: '',
FirmaFAme: '',
// Packing List (solo orden de compra + línea PO)
PackingOrdenCompra: false,
IncluirLineaDelPO: false
};
if (!formData) {
formData = { ...defaultFormData };
}
$effect.pre(() => {
if (formData) {
for (const key in defaultFormData) {
if (formData[key] === undefined) {
formData[key] = defaultFormData[key as keyof typeof defaultFormData];
}
}
}
});
let activeSubTab = $state('general');
// Conductor picker modal (simple: muestra una selección del catálogo de drivers)
let showConductorPicker = $state(false);
function selectConductor(driver: any) {
formData.Conductor = driver.name ?? driver.driver_name ?? driver.full_name ?? String(driver);
showConductorPicker = false;
}
</script>
<!-- Conductor picker modal -->
{#if showConductorPicker}
<div class="fixed inset-0 z-50 flex items-center justify-center bg-black/50">
<div class="bg-background border rounded-xl shadow-xl p-6 w-full max-w-md space-y-4">
<h3 class="text-base font-semibold">Seleccionar Conductor</h3>
{#if drivers && drivers.length > 0}
<ul class="max-h-72 overflow-y-auto divide-y rounded-md border">
{#each drivers as driver}
<li>
<button
class="w-full text-left px-4 py-2 text-sm hover:bg-muted transition-colors"
onclick={() => selectConductor(driver)}
>
{driver.name ?? driver.driver_name ?? driver.full_name ?? JSON.stringify(driver)}
</button>
</li>
{/each}
</ul>
{:else}
<p class="text-sm text-muted-foreground text-center py-6">No hay conductores registrados.</p>
{/if}
<div class="flex justify-end">
<Button variant="outline" size="sm" onclick={() => showConductorPicker = false}>Cerrar</Button>
</div>
</div>
</div>
{/if}
<div class="w-full">
<Tabs.Root bind:value={activeSubTab} class="flex flex-col">
<div class="w-full overflow-x-auto pb-2 mb-4">
<Tabs.List class="inline-flex md:flex w-full bg-muted/60 p-1 rounded-md">
<Tabs.Trigger value="general" class="flex-1">General</Tabs.Trigger>
<Tabs.Trigger value="mexicana" class="flex-1">Factura Mexicana y Bilingüe</Tabs.Trigger>
<Tabs.Trigger value="americana" class="flex-1">Factura Americana</Tabs.Trigger>
<Tabs.Trigger value="packing" class="flex-1">Packing List</Tabs.Trigger>
</Tabs.List>
</div>
<!-- GENERAL TAB -->
<Tabs.Content value="general" class="space-y-6">
<!-- Conductor y Transporte -->
<div class="space-y-4 border rounded-md p-4 bg-muted/10">
<h4 class="text-sm font-semibold text-muted-foreground uppercase border-b pb-2">Datos de Transporte</h4>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4 pt-2">
<!-- Conductor -->
<div class="space-y-1.5">
<Label class="text-xs">Conductor</Label>
<div class="flex gap-2">
<Input
id="cm_Conductor"
bind:value={formData.Conductor}
placeholder="Nombre del conductor..."
class="h-8 text-sm flex-1"
/>
<Button
variant="outline"
size="sm"
class="h-8 px-2"
onclick={() => showConductorPicker = true}
title="Buscar conductor del catálogo"
>
<Search size={14} />
</Button>
</div>
</div>
<!-- Tipo de Transporte -->
<div class="space-y-1.5">
<Label class="text-xs">Tipo de Transporte</Label>
<Select
type="single"
value={formData.Transporte}
onValueChange={(v) => formData.Transporte = v}
>
<SelectTrigger class="h-8 text-sm">
{transportOptions.find(o => o.value === formData.Transporte)?.label || 'Seleccionar...'}
</SelectTrigger>
<SelectContent>
{#each transportOptions as opt}
<SelectItem value={opt.value}>{opt.label}</SelectItem>
{/each}
</SelectContent>
</Select>
</div>
</div>
<!-- Imprimir orden de compra por partida -->
<div class="flex items-center gap-2 pt-2">
<Checkbox id="cm_ImpOrdenComp" bind:checked={formData.ImpOrdenComp} />
<Label for="cm_ImpOrdenComp" class="text-sm">Imprimir la orden de compra por partida</Label>
</div>
</div>
<!-- Número de decimales -->
<div class="space-y-4 border rounded-md p-4 bg-muted/10">
<h4 class="text-sm font-semibold text-muted-foreground uppercase border-b pb-2">Número de Decimales</h4>
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-4 pt-2">
<div class="space-y-1.5">
<Label class="text-xs">Peso Neto y Bruto</Label>
<Input type="number" bind:value={formData.DecimalesPeso} class="h-8 text-sm" />
</div>
<div class="space-y-1.5">
<Label class="text-xs">En Cantidades</Label>
<Input type="number" bind:value={formData.DecimalesCant} class="h-8 text-sm" />
</div>
<div class="space-y-1.5">
<Label class="text-xs">Costos Unitarios</Label>
<Input type="number" bind:value={formData.DecimalesCosto} class="h-8 text-sm" />
</div>
<div class="space-y-1.5">
<Label class="text-xs">En Valores</Label>
<Input type="number" bind:value={formData.DecimalesValor} class="h-8 text-sm" />
</div>
</div>
</div>
</Tabs.Content>
<!-- MEXICANA TAB -->
<Tabs.Content value="mexicana" class="space-y-6">
<!-- Imprimir por -->
<div class="space-y-4 border rounded-md p-4 bg-muted/10">
<h4 class="text-sm font-semibold text-muted-foreground uppercase">Imprimir por</h4>
<RadioGroup
value={formData.PorParteClaseMex}
onValueChange={(v) => formData.PorParteClaseMex = v}
class="flex gap-4"
>
<div class="flex items-center gap-2">
<RadioGroupItem value="parte" id="cm_mex_imprimir_parte" />
<Label for="cm_mex_imprimir_parte" class="text-sm">Parte</Label>
</div>
<div class="flex items-center gap-2">
<RadioGroupItem value="clase" id="cm_mex_imprimir_clase" />
<Label for="cm_mex_imprimir_clase" class="text-sm">Clase</Label>
</div>
</RadioGroup>
</div>
<!-- Incluir en la columna de descripción -->
<div class="space-y-4 border rounded-md p-4 bg-muted/10">
<h4 class="text-sm font-semibold text-muted-foreground uppercase border-b pb-2">Incluir en la columna de descripción</h4>
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4 pt-2">
<div class="flex items-center gap-2">
<Checkbox id="cm_NumParteMex" bind:checked={formData.NumParteMex} />
<Label for="cm_NumParteMex" class="text-sm">El número de parte</Label>
</div>
<div class="flex items-center gap-2">
<Checkbox id="cm_TipoFraccMex" bind:checked={formData.TipoFraccMex} />
<Label for="cm_TipoFraccMex" class="text-sm">El tipo de fracción</Label>
</div>
<div class="flex items-center gap-2">
<Checkbox id="cm_TasaFraccMex" bind:checked={formData.TasaFraccMex} />
<Label for="cm_TasaFraccMex" class="text-sm">La tasa de fracción</Label>
</div>
<div class="flex items-center gap-2">
<Checkbox id="cm_UMAlternaMex" bind:checked={formData.UMAlternaMex} />
<Label for="cm_UMAlternaMex" class="text-sm">Cantidad alterna</Label>
</div>
<div class="flex items-center gap-2">
<Checkbox id="cm_PaisOrigenMex" bind:checked={formData.PaisOrigenMex} />
<Label for="cm_PaisOrigenMex" class="text-sm">El país de origen</Label>
</div>
<div class="flex items-center gap-2">
<Checkbox id="cm_FraccionImp" bind:checked={formData.FraccionImp} />
<Label for="cm_FraccionImp" class="text-sm">La fracción arancelaria</Label>
</div>
<div class="flex items-center gap-2">
<Checkbox id="cm_UMEquivalenteMex" bind:checked={formData.UMEquivalenteMex} />
<Label for="cm_UMEquivalenteMex" class="text-sm">La U.M. Equivalente</Label>
</div>
</div>
<!-- Opciones adicionales fuera de la sub-sección -->
<div class="grid grid-cols-1 md:grid-cols-2 gap-4 pt-4 border-t mt-4">
<div class="flex items-center gap-2">
<Checkbox id="cm_AgregarVAenProdTerminados" bind:checked={formData.AgregarVAenProdTerminados} />
<Label for="cm_AgregarVAenProdTerminados" class="text-sm">Agregar VA en Prod. Terminados</Label>
</div>
<div class="flex items-center gap-2">
<Checkbox id="cm_OcultarFechaHora" bind:checked={formData.OcultarFechaHora} />
<Label for="cm_OcultarFechaHora" class="text-sm">Ocultar Fecha y Hora</Label>
</div>
</div>
</div>
<!-- Firma -->
<div class="space-y-4 border rounded-md p-4 bg-muted/10">
<h4 class="text-sm font-semibold text-muted-foreground uppercase border-b pb-2">Firma en Lecturas</h4>
<div class="space-y-2 pt-2">
<Textarea id="cm_FirmaFMex" bind:value={formData.FirmaFMex} class="h-24 resize-y" />
</div>
</div>
</Tabs.Content>
<!-- AMERICANA TAB (igual que temporal) -->
<Tabs.Content value="americana" class="space-y-6">
<!-- Imprimir por -->
<div class="space-y-4 border rounded-md p-4 bg-muted/10">
<h4 class="text-sm font-semibold text-muted-foreground uppercase">Imprimir por</h4>
<RadioGroup
value={formData.PorParteClaseAMe}
onValueChange={(v) => formData.PorParteClaseAMe = v}
class="flex gap-4"
>
<div class="flex items-center gap-2">
<RadioGroupItem value="parte" id="cm_ame_imprimir_parte" />
<Label for="cm_ame_imprimir_parte" class="text-sm">Parte</Label>
</div>
<div class="flex items-center gap-2">
<RadioGroupItem value="clase" id="cm_ame_imprimir_clase" />
<Label for="cm_ame_imprimir_clase" class="text-sm">Clase</Label>
</div>
</RadioGroup>
</div>
<!-- Incluir en la columna de descripción -->
<div class="space-y-4 border rounded-md p-4 bg-muted/10">
<h4 class="text-sm font-semibold text-muted-foreground uppercase border-b pb-2">Incluir en la columna de descripción</h4>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4 pt-2">
<div class="flex items-center gap-2">
<Checkbox id="cm_NumParteAme" bind:checked={formData.NumParteAme} />
<Label for="cm_NumParteAme" class="text-sm">El número de parte</Label>
</div>
<div class="flex items-center gap-2">
<Checkbox id="cm_FraccionAme" bind:checked={formData.FraccionAme} />
<Label for="cm_FraccionAme" class="text-sm">La fracción americana</Label>
</div>
<div class="flex items-center gap-2">
<Checkbox id="cm_PaisOrigenAme" bind:checked={formData.PaisOrigenAme} />
<Label for="cm_PaisOrigenAme" class="text-sm">El país de origen</Label>
</div>
<div class="flex items-center gap-2">
<Checkbox id="cm_UMEquivalenteAme" bind:checked={formData.UMEquivalenteAme} />
<Label for="cm_UMEquivalenteAme" class="text-sm">La U.M. N. Equivalente</Label>
</div>
</div>
</div>
<!-- Textos libres -->
<div class="space-y-4 border rounded-md p-4 bg-muted/10">
<div class="space-y-2">
<Label for="cm_LeyendaFacAme" class="text-sm font-semibold text-muted-foreground">Leyenda factura</Label>
<Textarea id="cm_LeyendaFacAme" bind:value={formData.LeyendaFacAme} class="h-24 resize-y" />
</div>
<div class="space-y-2 pt-4">
<Label for="cm_FirmaFAme" class="text-sm font-semibold text-muted-foreground">Firma en factura americana</Label>
<Textarea id="cm_FirmaFAme" bind:value={formData.FirmaFAme} class="h-24 resize-y" />
</div>
</div>
</Tabs.Content>
<!-- PACKING LIST TAB -->
<Tabs.Content value="packing" class="space-y-6">
<div class="space-y-4 border rounded-md p-4 bg-muted/10">
<h4 class="text-sm font-semibold text-muted-foreground uppercase border-b pb-2">Opciones de Packing List</h4>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4 pt-2">
<div class="flex items-center gap-2">
<Checkbox id="cm_PackingOrdenCompra" bind:checked={formData.PackingOrdenCompra} />
<Label for="cm_PackingOrdenCompra" class="text-sm">Imprimir orden de compra</Label>
</div>
<div class="flex items-center gap-2">
<Checkbox id="cm_IncluirLineaDelPO" bind:checked={formData.IncluirLineaDelPO} />
<Label for="cm_IncluirLineaDelPO" class="text-sm">Incluir línea de PO</Label>
</div>
</div>
</div>
</Tabs.Content>
</Tabs.Root>
</div>

View File

@@ -0,0 +1,422 @@
<script lang="ts">
import * as Tabs from '$lib/components/ui/tabs';
import { Input } from '$lib/components/ui/input';
import { Label } from '$lib/components/ui/label';
import { Checkbox } from '$lib/components/ui/checkbox';
import { Textarea } from '$lib/components/ui/textarea';
import { RadioGroup, RadioGroupItem } from '$lib/components/ui/radio-group';
let {
formData = $bindable()
}: {
formData: any;
} = $props();
const defaultFormData = {
DecimalesPeso: null,
DecimalesCant: null,
DecimalesValor: null,
DecimalesCosto: null,
ControlRemesa: false,
RemesaInicio: null,
RemesaFinal: null,
CantLimiteMin: null,
PesoLimiteMin: null,
ValorLimiteMin: null,
ValorLimiteParMin: null,
CantLimite: null,
PesoLimite: null,
ValorLimite: null,
ValorLimitePar: null,
RestringeImpoPT: false,
ActualizarPartePartida: false,
CalcIGIBaseCapt: false,
LocAPOrigen: false,
SolicitarContrasenaAdministrador: false,
// Mexicana
PorParteClaseMex: 'parte',
NumParteMex: false,
PaisOrigenMex: false,
PerPagRenglon: false,
UMEquivalenteMex: false,
UMAlternaMex: false,
FraccionImp: false,
TasaFraccMex: false,
TipoFraccMex: false,
ImpOrdenCom: false,
ParteComplementariaMex: false,
ParteCompleMexPartida: false,
ImprimirLote: false,
ImprimirNumEntrada: false,
CodigoBarras: false,
UMAuxiliarMex: false,
AgregarVAenProdTerminados: false,
OcultarFechaHora: false,
FirmaFMex: '',
// Americana
PorParteClaseAMe: 'parte',
NumParteAme: false,
FraccionAme: false,
PaisOrigenAme: false,
UMEquivalenteAme: false,
LeyendaFacAme: '',
FirmaFAme: '',
// Packing list
PackingPedClave: false,
PackingOrdenCompra: false,
PorOrdenPorOCPack: 'captura',
IncluirLineaDelPO: false
};
if (!formData) {
formData = { ...defaultFormData };
}
$effect.pre(() => {
if (formData) {
for (const key in defaultFormData) {
if (formData[key] === undefined) {
formData[key] = defaultFormData[key as keyof typeof defaultFormData];
}
}
}
});
let activeSubTab = $state('general');
</script>
<div class="w-full">
<Tabs.Root bind:value={activeSubTab} class="flex flex-col">
<div class="w-full overflow-x-auto pb-2 mb-4">
<Tabs.List class="inline-flex md:flex w-full bg-muted/60 p-1 rounded-md">
<Tabs.Trigger value="general" class="flex-1">General</Tabs.Trigger>
<Tabs.Trigger value="mexicana" class="flex-1">Factura Mexicana y Bilingüe</Tabs.Trigger>
<Tabs.Trigger value="americana" class="flex-1">Factura Americana</Tabs.Trigger>
<Tabs.Trigger value="packing" class="flex-1">Packing List</Tabs.Trigger>
</Tabs.List>
</div>
<!-- GENERAL TAB -->
<Tabs.Content value="general" class="space-y-6">
<!-- Configuración de Decimales -->
<div class="space-y-4 border rounded-md p-4 bg-muted/10">
<h4 class="text-sm font-semibold text-muted-foreground uppercase">Configuración de Decimales</h4>
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-4">
<div class="space-y-1.5">
<Label class="text-xs">Decimales (Peso Neto y Bruto)</Label>
<Input type="number" bind:value={formData.DecimalesPeso} class="h-8 text-sm" />
</div>
<div class="space-y-1.5">
<Label class="text-xs">Decimales (Cantidades)</Label>
<Input type="number" bind:value={formData.DecimalesCant} class="h-8 text-sm" />
</div>
<div class="space-y-1.5">
<Label class="text-xs">Decimales (Valores)</Label>
<Input type="number" bind:value={formData.DecimalesValor} class="h-8 text-sm" />
</div>
<div class="space-y-1.5">
<Label class="text-xs">Decimales (Costos Unitarios)</Label>
<Input type="number" bind:value={formData.DecimalesCosto} class="h-8 text-sm" />
</div>
</div>
</div>
<!-- Control Remesa -->
<div class="space-y-4 border rounded-md p-4 bg-muted/10">
<div class="flex items-center gap-2 mb-2 border-b pb-2">
<Checkbox id="ControlRemesa" bind:checked={formData.ControlRemesa} />
<Label for="ControlRemesa" class="font-semibold text-muted-foreground uppercase">Control Remesa por Rangos</Label>
</div>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4" class:opacity-50={!formData.ControlRemesa}>
<div class="space-y-1.5">
<Label class="text-xs">De la Remesa</Label>
<Input type="number" bind:value={formData.RemesaInicio} disabled={!formData.ControlRemesa} class="h-8 text-sm" />
</div>
<div class="space-y-1.5">
<Label class="text-xs">A la Remesa</Label>
<Input type="number" bind:value={formData.RemesaFinal} disabled={!formData.ControlRemesa} class="h-8 text-sm" />
</div>
</div>
</div>
<!-- Limites Minimos -->
<div class="space-y-4 border rounded-md p-4 bg-muted/10">
<h4 class="text-sm font-semibold text-muted-foreground uppercase border-b pb-2">Mínimos límites para actualizar las facturas</h4>
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-4 pt-2">
<div class="space-y-1.5">
<Label class="text-xs">Cantidad Mínima</Label>
<Input type="number" bind:value={formData.CantLimiteMin} class="h-8 text-sm" />
</div>
<div class="space-y-1.5">
<Label class="text-xs">Peso Mínimo</Label>
<Input type="number" bind:value={formData.PesoLimiteMin} class="h-8 text-sm" />
</div>
<div class="space-y-1.5">
<Label class="text-xs">Valor Mínimo</Label>
<Input type="number" bind:value={formData.ValorLimiteMin} class="h-8 text-sm" />
</div>
<div class="space-y-1.5">
<Label class="text-xs">Valor Mínimo por Partida</Label>
<Input type="number" bind:value={formData.ValorLimiteParMin} class="h-8 text-sm" />
</div>
</div>
</div>
<!-- Limites Maximos -->
<div class="space-y-4 border rounded-md p-4 bg-muted/10">
<h4 class="text-sm font-semibold text-muted-foreground uppercase border-b pb-2">Máximos límites para actualizar las facturas</h4>
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-4 pt-2">
<div class="space-y-1.5">
<Label class="text-xs">Cantidad Máxima</Label>
<Input type="number" bind:value={formData.CantLimite} class="h-8 text-sm" />
</div>
<div class="space-y-1.5">
<Label class="text-xs">Peso Máximo</Label>
<Input type="number" bind:value={formData.PesoLimite} class="h-8 text-sm" />
</div>
<div class="space-y-1.5">
<Label class="text-xs">Valor Máximo</Label>
<Input type="number" bind:value={formData.ValorLimite} class="h-8 text-sm" />
</div>
<div class="space-y-1.5">
<Label class="text-xs">Valor Máximo por Partida</Label>
<Input type="number" bind:value={formData.ValorLimitePar} class="h-8 text-sm" />
</div>
</div>
</div>
<!-- Otras Opciones (Footer) -->
<div class="space-y-4 border rounded-md p-4 bg-muted/10">
<h4 class="text-sm font-semibold text-muted-foreground uppercase border-b pb-2">Otras Opciones</h4>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4 pt-2">
<div class="flex items-center gap-2">
<Checkbox id="RestringeImpoPT" bind:checked={formData.RestringeImpoPT} />
<Label for="RestringeImpoPT" class="text-sm">Restringe la importación de Productos Terminados</Label>
</div>
<div class="flex items-center gap-2">
<Checkbox id="ActualizarPartePartida" bind:checked={formData.ActualizarPartePartida} />
<Label for="ActualizarPartePartida" class="text-sm">Actualiza datos del número de parte en base a captura de partidas</Label>
</div>
<div class="flex items-center gap-2">
<Checkbox id="CalcIGIBaseCapt" bind:checked={formData.CalcIGIBaseCapt} />
<Label for="CalcIGIBaseCapt" class="text-sm">Cálculo del Valor IGI en Base a lo capturado</Label>
</div>
<div class="flex items-center gap-2">
<Checkbox id="LocAPOrigen" bind:checked={formData.LocAPOrigen} />
<Label for="LocAPOrigen" class="text-sm">Advertencia País de Origen</Label>
</div>
<div class="flex items-center gap-2 md:col-span-2">
<Checkbox id="SolicitarContrasenaAdministrador" bind:checked={formData.SolicitarContrasenaAdministrador} />
<Label for="SolicitarContrasenaAdministrador" class="text-sm">Solicitar Autorización para Pasar por Alto la Validacion de Temporalidad en Base a Fecha de Pago de Pedimento</Label>
</div>
</div>
</div>
</Tabs.Content>
<!-- MEXICANA TAB -->
<Tabs.Content value="mexicana" class="space-y-6">
<!-- Imprimir por -->
<div class="space-y-4 border rounded-md p-4 bg-muted/10">
<h4 class="text-sm font-semibold text-muted-foreground uppercase">Imprimir por</h4>
<RadioGroup value={formData.PorParteClaseMex} onValueChange={(v) => formData.PorParteClaseMex = v} class="flex gap-4">
<div class="flex items-center gap-2">
<RadioGroupItem value="parte" id="mex_imprimir_parte" />
<Label for="mex_imprimir_parte" class="text-sm">Parte</Label>
</div>
<div class="flex items-center gap-2">
<RadioGroupItem value="clase" id="mex_imprimir_clase" />
<Label for="mex_imprimir_clase" class="text-sm">Clase</Label>
</div>
</RadioGroup>
</div>
<!-- Incluir en la columna de descripción -->
<div class="space-y-4 border rounded-md p-4 bg-muted/10">
<h4 class="text-sm font-semibold text-muted-foreground uppercase border-b pb-2">Incluir en la columna de descripción</h4>
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4 pt-2">
<div class="flex items-center gap-2">
<Checkbox id="NumParteMex" bind:checked={formData.NumParteMex} />
<Label for="NumParteMex" class="text-sm">El número de parte</Label>
</div>
<div class="flex items-center gap-2">
<Checkbox id="PaisOrigenMex" bind:checked={formData.PaisOrigenMex} />
<Label for="PaisOrigenMex" class="text-sm">El país de origen</Label>
</div>
<div class="flex items-center gap-2">
<Checkbox id="PerPagRenglon" bind:checked={formData.PerPagRenglon} />
<Label for="PerPagRenglon" class="text-sm">Permiso y la Página - Renglón</Label>
</div>
<div class="flex items-center gap-2">
<Checkbox id="UMEquivalenteMex" bind:checked={formData.UMEquivalenteMex} />
<Label for="UMEquivalenteMex" class="text-sm">La U.M. Equivalente</Label>
</div>
<div class="flex items-center gap-2">
<Checkbox id="UMAlternaMex" bind:checked={formData.UMAlternaMex} />
<Label for="UMAlternaMex" class="text-sm">Cantidad Alterna</Label>
</div>
<div class="flex items-center gap-2">
<Checkbox id="FraccionImp" bind:checked={formData.FraccionImp} />
<Label for="FraccionImp" class="text-sm">Fracción Arancelaria</Label>
</div>
<div class="flex items-center gap-2">
<Checkbox id="TasaFraccMex" bind:checked={formData.TasaFraccMex} />
<Label for="TasaFraccMex" class="text-sm">Tasa de la Fracción Arancelaria</Label>
</div>
<div class="flex items-center gap-2">
<Checkbox id="TipoFraccMex" bind:checked={formData.TipoFraccMex} />
<Label for="TipoFraccMex" class="text-sm">Preferencia de la Fracción Arancelaria</Label>
</div>
<div class="flex items-center gap-2">
<Checkbox id="ImpOrdenCom" bind:checked={formData.ImpOrdenCom} />
<Label for="ImpOrdenCom" class="text-sm">Orden de Compra (Solo OC)</Label>
</div>
</div>
<!-- Parte Complementaria -->
<div class="mt-4 pt-4 border-t space-y-2">
<h5 class="text-xs font-semibold text-muted-foreground uppercase mb-2">Parte Complementaria de:</h5>
<div class="grid grid-cols-1 sm:grid-cols-2 gap-4 pl-2">
<div class="flex items-center gap-2">
<Checkbox id="ParteComplementariaMex" bind:checked={formData.ParteComplementariaMex} />
<Label for="ParteComplementariaMex" class="text-sm">Número de parte</Label>
</div>
<div class="flex items-center gap-2">
<Checkbox id="ParteCompleMexPartida" bind:checked={formData.ParteCompleMexPartida} />
<Label for="ParteCompleMexPartida" class="text-sm">La partida</Label>
</div>
</div>
</div>
<!-- Más opciones -->
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4 pt-4 border-t mt-4">
<div class="flex items-center gap-2">
<Checkbox id="ImprimirLote" bind:checked={formData.ImprimirLote} />
<Label for="ImprimirLote" class="text-sm">Lote</Label>
</div>
<div class="flex items-center gap-2">
<Checkbox id="ImprimirNumEntrada" bind:checked={formData.ImprimirNumEntrada} />
<Label for="ImprimirNumEntrada" class="text-sm">Núm. Entrada</Label>
</div>
<div class="flex items-center gap-2">
<Checkbox id="CodigoBarras" bind:checked={formData.CodigoBarras} />
<Label for="CodigoBarras" class="text-sm">Imprimir Código de Barras en parte inferior</Label>
</div>
<div class="flex items-center gap-2">
<Checkbox id="UMAuxiliarMex" bind:checked={formData.UMAuxiliarMex} />
<Label for="UMAuxiliarMex" class="text-sm">Muestra UM Auxiliar por UM Comercial</Label>
</div>
<div class="flex items-center gap-2">
<Checkbox id="AgregarVAenProdTerminados" bind:checked={formData.AgregarVAenProdTerminados} />
<Label for="AgregarVAenProdTerminados" class="text-sm">Agregar VA en Prod. Terminados</Label>
</div>
<div class="flex items-center gap-2">
<Checkbox id="OcultarFechaHora" bind:checked={formData.OcultarFechaHora} />
<Label for="OcultarFechaHora" class="text-sm">Ocultar Fecha y Hora</Label>
</div>
</div>
</div>
<!-- Firma -->
<div class="space-y-4 border rounded-md p-4 bg-muted/10">
<h4 class="text-sm font-semibold text-muted-foreground uppercase border-b pb-2">Firmas</h4>
<div class="space-y-2 pt-2">
<Label for="FirmaFMex" class="text-sm">Firma en Factura Mexicana:</Label>
<Textarea id="FirmaFMex" bind:value={formData.FirmaFMex} class="h-24 resize-y" />
</div>
</div>
</Tabs.Content>
<!-- AMERICANA TAB -->
<Tabs.Content value="americana" class="space-y-6">
<!-- Imprimir por -->
<div class="space-y-4 border rounded-md p-4 bg-muted/10">
<h4 class="text-sm font-semibold text-muted-foreground uppercase">Imprimir por</h4>
<RadioGroup value={formData.PorParteClaseAMe} onValueChange={(v) => formData.PorParteClaseAMe = v} class="flex gap-4">
<div class="flex items-center gap-2">
<RadioGroupItem value="parte" id="ame_imprimir_parte" />
<Label for="ame_imprimir_parte" class="text-sm">Parte</Label>
</div>
<div class="flex items-center gap-2">
<RadioGroupItem value="clase" id="ame_imprimir_clase" />
<Label for="ame_imprimir_clase" class="text-sm">Clase</Label>
</div>
</RadioGroup>
</div>
<!-- Incluir en la columna de descripción -->
<div class="space-y-4 border rounded-md p-4 bg-muted/10">
<h4 class="text-sm font-semibold text-muted-foreground uppercase border-b pb-2">Incluir en la columna de descripción</h4>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4 pt-2">
<div class="flex items-center gap-2">
<Checkbox id="NumParteAme" bind:checked={formData.NumParteAme} />
<Label for="NumParteAme" class="text-sm">El número de parte</Label>
</div>
<div class="flex items-center gap-2">
<Checkbox id="FraccionAme" bind:checked={formData.FraccionAme} />
<Label for="FraccionAme" class="text-sm">La fracción americana</Label>
</div>
<div class="flex items-center gap-2">
<Checkbox id="PaisOrigenAme" bind:checked={formData.PaisOrigenAme} />
<Label for="PaisOrigenAme" class="text-sm">El país de origen</Label>
</div>
<div class="flex items-center gap-2">
<Checkbox id="UMEquivalenteAme" bind:checked={formData.UMEquivalenteAme} />
<Label for="UMEquivalenteAme" class="text-sm">La U.M. N. Equivalente</Label>
</div>
</div>
</div>
<!-- Entradas grandes de texto -->
<div class="space-y-4 border rounded-md p-4 bg-muted/10">
<div class="space-y-2">
<Label for="LeyendaFacAme" class="text-sm font-semibold text-muted-foreground">Leyenda factura</Label>
<Textarea id="LeyendaFacAme" bind:value={formData.LeyendaFacAme} class="h-24 resize-y" />
</div>
<div class="space-y-2 pt-4">
<Label for="FirmaFAme" class="text-sm font-semibold text-muted-foreground">Firma en factura americana</Label>
<Textarea id="FirmaFAme" bind:value={formData.FirmaFAme} class="h-24 resize-y" />
</div>
</div>
</Tabs.Content>
<!-- PACKING LIST TAB -->
<Tabs.Content value="packing" class="space-y-6">
<!-- Opciones de Packing List -->
<div class="space-y-4 border rounded-md p-4 bg-muted/10">
<h4 class="text-sm font-semibold text-muted-foreground uppercase border-b pb-2">Opciones de Packing List</h4>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4 pt-2">
<div class="flex items-center gap-2">
<Checkbox id="PackingPedClave" bind:checked={formData.PackingPedClave} />
<Label for="PackingPedClave" class="text-sm">Muestra el número de pedimento y su clave de pedimento en el Packing List</Label>
</div>
<div class="flex items-center gap-2">
<Checkbox id="PackingOrdenCompra" bind:checked={formData.PackingOrdenCompra} />
<Label for="PackingOrdenCompra" class="text-sm">Imprimir orden de compra</Label>
</div>
<div class="flex items-center gap-2">
<Checkbox id="IncluirLineaDelPO" bind:checked={formData.IncluirLineaDelPO} />
<Label for="IncluirLineaDelPO" class="text-sm">Incluir línea de PO</Label>
</div>
</div>
</div>
<!-- Imprimir por -->
<div class="space-y-4 border rounded-md p-4 bg-muted/10">
<h4 class="text-sm font-semibold text-muted-foreground uppercase">Imprimir por</h4>
<RadioGroup value={formData.PorOrdenPorOCPack} onValueChange={(v) => formData.PorOrdenPorOCPack = v} class="flex gap-4">
<div class="flex items-center gap-2">
<RadioGroupItem value="captura" id="pack_imprimir_captura" />
<Label for="pack_imprimir_captura" class="text-sm">Orden de captura</Label>
</div>
<div class="flex items-center gap-2">
<RadioGroupItem value="compra" id="pack_imprimir_compra" />
<Label for="pack_imprimir_compra" class="text-sm">Orden de compra</Label>
</div>
</RadioGroup>
</div>
</Tabs.Content>
</Tabs.Root>
</div>

View File

@@ -0,0 +1,395 @@
<script lang="ts">
import * as Tabs from '$lib/components/ui/tabs';
import { Input } from '$lib/components/ui/input';
import { Label } from '$lib/components/ui/label';
import { Checkbox } from '$lib/components/ui/checkbox';
import { Textarea } from '$lib/components/ui/textarea';
import { RadioGroup, RadioGroupItem } from '$lib/components/ui/radio-group';
let {
formData = $bindable()
}: {
formData: any;
} = $props();
const defaultFormData = {
DecimalesPeso: null,
DecimalesCant: null,
DecimalesValor: null,
DecimalesCosto: null,
// Sin ControlRemesa, RemesaInicio, RemesaFinal (no aplica en definitiva)
CantLimiteMin: null,
PesoLimiteMin: null,
ValorLimiteMin: null,
ValorLimiteParMin: null,
CantLimite: null,
PesoLimite: null,
ValorLimite: null,
ValorLimitePar: null,
RestringeImpoPT: false,
ActualizarPartePartida: false,
// Sin CalcIGIBaseCapt (no aplica en definitiva)
LocAPOrigen: false,
SolicitarContrasenaAdministrador: false,
// Mexicana
PorParteClaseMex: 'parte',
NumParteMex: false,
PaisOrigenMex: false,
PerPagRenglon: false,
UMEquivalenteMex: false,
UMAlternaMex: false,
FraccionImp: false,
TasaFraccMex: false,
// Sin TipoFraccMex (Preferencia de la Fracción Arancelaria — no aplica en definitiva)
ImpOrdenCom: false,
ParteComplementariaMex: false,
ParteCompleMexPartida: false,
ImprimirLote: false,
ImprimirNumEntrada: false,
CodigoBarras: false,
UMAuxiliarMex: false,
AgregarVAenProdTerminados: false,
OcultarFechaHora: false,
FirmaFMex: '',
// Americana
PorParteClaseAMe: 'parte',
NumParteAme: false,
FraccionAme: false,
PaisOrigenAme: false,
UMEquivalenteAme: false,
LeyendaFacAme: '',
FirmaFAme: '',
// Packing list
PackingPedClave: false,
PackingOrdenCompra: false,
PorOrdenPorOCPack: 'captura',
IncluirLineaDelPO: false
};
if (!formData) {
formData = { ...defaultFormData };
}
$effect.pre(() => {
if (formData) {
for (const key in defaultFormData) {
if (formData[key] === undefined) {
formData[key] = defaultFormData[key as keyof typeof defaultFormData];
}
}
}
});
let activeSubTab = $state('general');
</script>
<div class="w-full">
<Tabs.Root bind:value={activeSubTab} class="flex flex-col">
<div class="w-full overflow-x-auto pb-2 mb-4">
<Tabs.List class="inline-flex md:flex w-full bg-muted/60 p-1 rounded-md">
<Tabs.Trigger value="general" class="flex-1">General</Tabs.Trigger>
<Tabs.Trigger value="mexicana" class="flex-1">Factura Mexicana y Bilingüe</Tabs.Trigger>
<Tabs.Trigger value="americana" class="flex-1">Factura Americana</Tabs.Trigger>
<Tabs.Trigger value="packing" class="flex-1">Packing List</Tabs.Trigger>
</Tabs.List>
</div>
<!-- GENERAL TAB -->
<Tabs.Content value="general" class="space-y-6">
<!-- Configuración de Decimales -->
<div class="space-y-4 border rounded-md p-4 bg-muted/10">
<h4 class="text-sm font-semibold text-muted-foreground uppercase">Configuración de Decimales</h4>
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-4">
<div class="space-y-1.5">
<Label class="text-xs">Decimales (Peso Neto y Bruto)</Label>
<Input type="number" bind:value={formData.DecimalesPeso} class="h-8 text-sm" />
</div>
<div class="space-y-1.5">
<Label class="text-xs">Decimales (Cantidades)</Label>
<Input type="number" bind:value={formData.DecimalesCant} class="h-8 text-sm" />
</div>
<div class="space-y-1.5">
<Label class="text-xs">Decimales (Valores)</Label>
<Input type="number" bind:value={formData.DecimalesValor} class="h-8 text-sm" />
</div>
<div class="space-y-1.5">
<Label class="text-xs">Decimales (Costos Unitarios)</Label>
<Input type="number" bind:value={formData.DecimalesCosto} class="h-8 text-sm" />
</div>
</div>
</div>
<!-- Limites Minimos -->
<div class="space-y-4 border rounded-md p-4 bg-muted/10">
<h4 class="text-sm font-semibold text-muted-foreground uppercase border-b pb-2">Mínimos límites para actualizar las facturas</h4>
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-4 pt-2">
<div class="space-y-1.5">
<Label class="text-xs">Cantidad Mínima</Label>
<Input type="number" bind:value={formData.CantLimiteMin} class="h-8 text-sm" />
</div>
<div class="space-y-1.5">
<Label class="text-xs">Peso Mínimo</Label>
<Input type="number" bind:value={formData.PesoLimiteMin} class="h-8 text-sm" />
</div>
<div class="space-y-1.5">
<Label class="text-xs">Valor Mínimo</Label>
<Input type="number" bind:value={formData.ValorLimiteMin} class="h-8 text-sm" />
</div>
<div class="space-y-1.5">
<Label class="text-xs">Valor Mínimo por Partida</Label>
<Input type="number" bind:value={formData.ValorLimiteParMin} class="h-8 text-sm" />
</div>
</div>
</div>
<!-- Limites Maximos -->
<div class="space-y-4 border rounded-md p-4 bg-muted/10">
<h4 class="text-sm font-semibold text-muted-foreground uppercase border-b pb-2">Máximos límites para actualizar las facturas</h4>
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-4 pt-2">
<div class="space-y-1.5">
<Label class="text-xs">Cantidad Máxima</Label>
<Input type="number" bind:value={formData.CantLimite} class="h-8 text-sm" />
</div>
<div class="space-y-1.5">
<Label class="text-xs">Peso Máximo</Label>
<Input type="number" bind:value={formData.PesoLimite} class="h-8 text-sm" />
</div>
<div class="space-y-1.5">
<Label class="text-xs">Valor Máximo</Label>
<Input type="number" bind:value={formData.ValorLimite} class="h-8 text-sm" />
</div>
<div class="space-y-1.5">
<Label class="text-xs">Valor Máximo por Partida</Label>
<Input type="number" bind:value={formData.ValorLimitePar} class="h-8 text-sm" />
</div>
</div>
</div>
<!-- Otras Opciones (Footer) -->
<div class="space-y-4 border rounded-md p-4 bg-muted/10">
<h4 class="text-sm font-semibold text-muted-foreground uppercase border-b pb-2">Otras Opciones</h4>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4 pt-2">
<div class="flex items-center gap-2">
<Checkbox id="def_RestringeImpoPT" bind:checked={formData.RestringeImpoPT} />
<Label for="def_RestringeImpoPT" class="text-sm">Restringe la importación de Productos Terminados</Label>
</div>
<div class="flex items-center gap-2">
<Checkbox id="def_ActualizarPartePartida" bind:checked={formData.ActualizarPartePartida} />
<Label for="def_ActualizarPartePartida" class="text-sm">Actualiza datos del número de parte en base a captura de partidas</Label>
</div>
<div class="flex items-center gap-2">
<Checkbox id="def_LocAPOrigen" bind:checked={formData.LocAPOrigen} />
<Label for="def_LocAPOrigen" class="text-sm">Advertencia País de Origen</Label>
</div>
<div class="flex items-center gap-2 md:col-span-2">
<Checkbox id="def_SolicitarContrasenaAdministrador" bind:checked={formData.SolicitarContrasenaAdministrador} />
<Label for="def_SolicitarContrasenaAdministrador" class="text-sm">Solicitar Autorización para Pasar por Alto la Validacion de Temporalidad en Base a Fecha de Pago de Pedimento</Label>
</div>
</div>
</div>
</Tabs.Content>
<!-- MEXICANA TAB -->
<Tabs.Content value="mexicana" class="space-y-6">
<!-- Imprimir por -->
<div class="space-y-4 border rounded-md p-4 bg-muted/10">
<h4 class="text-sm font-semibold text-muted-foreground uppercase">Imprimir por</h4>
<RadioGroup value={formData.PorParteClaseMex} onValueChange={(v) => formData.PorParteClaseMex = v} class="flex gap-4">
<div class="flex items-center gap-2">
<RadioGroupItem value="parte" id="def_mex_imprimir_parte" />
<Label for="def_mex_imprimir_parte" class="text-sm">Parte</Label>
</div>
<div class="flex items-center gap-2">
<RadioGroupItem value="clase" id="def_mex_imprimir_clase" />
<Label for="def_mex_imprimir_clase" class="text-sm">Clase</Label>
</div>
</RadioGroup>
</div>
<!-- Incluir en la columna de descripción -->
<div class="space-y-4 border rounded-md p-4 bg-muted/10">
<h4 class="text-sm font-semibold text-muted-foreground uppercase border-b pb-2">Incluir en la columna de descripción</h4>
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4 pt-2">
<div class="flex items-center gap-2">
<Checkbox id="def_NumParteMex" bind:checked={formData.NumParteMex} />
<Label for="def_NumParteMex" class="text-sm">El número de parte</Label>
</div>
<div class="flex items-center gap-2">
<Checkbox id="def_PaisOrigenMex" bind:checked={formData.PaisOrigenMex} />
<Label for="def_PaisOrigenMex" class="text-sm">El país de origen</Label>
</div>
<div class="flex items-center gap-2">
<Checkbox id="def_PerPagRenglon" bind:checked={formData.PerPagRenglon} />
<Label for="def_PerPagRenglon" class="text-sm">Permiso y la Página - Renglón</Label>
</div>
<div class="flex items-center gap-2">
<Checkbox id="def_UMEquivalenteMex" bind:checked={formData.UMEquivalenteMex} />
<Label for="def_UMEquivalenteMex" class="text-sm">La U.M. Equivalente</Label>
</div>
<div class="flex items-center gap-2">
<Checkbox id="def_UMAlternaMex" bind:checked={formData.UMAlternaMex} />
<Label for="def_UMAlternaMex" class="text-sm">Cantidad Alterna</Label>
</div>
<div class="flex items-center gap-2">
<Checkbox id="def_FraccionImp" bind:checked={formData.FraccionImp} />
<Label for="def_FraccionImp" class="text-sm">Fracción Arancelaria</Label>
</div>
<div class="flex items-center gap-2">
<Checkbox id="def_TasaFraccMex" bind:checked={formData.TasaFraccMex} />
<Label for="def_TasaFraccMex" class="text-sm">Tasa de la Fracción Arancelaria</Label>
</div>
<!-- Sin TipoFraccMex (Preferencia de la Fracción Arancelaria): no aplica en Importación Definitiva -->
<div class="flex items-center gap-2">
<Checkbox id="def_ImpOrdenCom" bind:checked={formData.ImpOrdenCom} />
<Label for="def_ImpOrdenCom" class="text-sm">Orden de Compra (Solo OC)</Label>
</div>
</div>
<!-- Parte Complementaria -->
<div class="mt-4 pt-4 border-t space-y-2">
<h5 class="text-xs font-semibold text-muted-foreground uppercase mb-2">Parte Complementaria de:</h5>
<div class="grid grid-cols-1 sm:grid-cols-2 gap-4 pl-2">
<div class="flex items-center gap-2">
<Checkbox id="def_ParteComplementariaMex" bind:checked={formData.ParteComplementariaMex} />
<Label for="def_ParteComplementariaMex" class="text-sm">Número de parte</Label>
</div>
<div class="flex items-center gap-2">
<Checkbox id="def_ParteCompleMexPartida" bind:checked={formData.ParteCompleMexPartida} />
<Label for="def_ParteCompleMexPartida" class="text-sm">La partida</Label>
</div>
</div>
</div>
<!-- Más opciones -->
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4 pt-4 border-t mt-4">
<div class="flex items-center gap-2">
<Checkbox id="def_ImprimirLote" bind:checked={formData.ImprimirLote} />
<Label for="def_ImprimirLote" class="text-sm">Lote</Label>
</div>
<div class="flex items-center gap-2">
<Checkbox id="def_ImprimirNumEntrada" bind:checked={formData.ImprimirNumEntrada} />
<Label for="def_ImprimirNumEntrada" class="text-sm">Núm. Entrada</Label>
</div>
<div class="flex items-center gap-2">
<Checkbox id="def_CodigoBarras" bind:checked={formData.CodigoBarras} />
<Label for="def_CodigoBarras" class="text-sm">Imprimir Código de Barras en parte inferior</Label>
</div>
<div class="flex items-center gap-2">
<Checkbox id="def_UMAuxiliarMex" bind:checked={formData.UMAuxiliarMex} />
<Label for="def_UMAuxiliarMex" class="text-sm">Muestra UM Auxiliar por UM Comercial</Label>
</div>
<div class="flex items-center gap-2">
<Checkbox id="def_AgregarVAenProdTerminados" bind:checked={formData.AgregarVAenProdTerminados} />
<Label for="def_AgregarVAenProdTerminados" class="text-sm">Agregar VA en Prod. Terminados</Label>
</div>
<div class="flex items-center gap-2">
<Checkbox id="def_OcultarFechaHora" bind:checked={formData.OcultarFechaHora} />
<Label for="def_OcultarFechaHora" class="text-sm">Ocultar Fecha y Hora</Label>
</div>
</div>
</div>
<!-- Firma -->
<div class="space-y-4 border rounded-md p-4 bg-muted/10">
<h4 class="text-sm font-semibold text-muted-foreground uppercase border-b pb-2">Firmas</h4>
<div class="space-y-2 pt-2">
<Label for="def_FirmaFMex" class="text-sm">Firma en Factura Mexicana:</Label>
<Textarea id="def_FirmaFMex" bind:value={formData.FirmaFMex} class="h-24 resize-y" />
</div>
</div>
</Tabs.Content>
<!-- AMERICANA TAB -->
<Tabs.Content value="americana" class="space-y-6">
<!-- Imprimir por -->
<div class="space-y-4 border rounded-md p-4 bg-muted/10">
<h4 class="text-sm font-semibold text-muted-foreground uppercase">Imprimir por</h4>
<RadioGroup value={formData.PorParteClaseAMe} onValueChange={(v) => formData.PorParteClaseAMe = v} class="flex gap-4">
<div class="flex items-center gap-2">
<RadioGroupItem value="parte" id="def_ame_imprimir_parte" />
<Label for="def_ame_imprimir_parte" class="text-sm">Parte</Label>
</div>
<div class="flex items-center gap-2">
<RadioGroupItem value="clase" id="def_ame_imprimir_clase" />
<Label for="def_ame_imprimir_clase" class="text-sm">Clase</Label>
</div>
</RadioGroup>
</div>
<!-- Incluir en la columna de descripción -->
<div class="space-y-4 border rounded-md p-4 bg-muted/10">
<h4 class="text-sm font-semibold text-muted-foreground uppercase border-b pb-2">Incluir en la columna de descripción</h4>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4 pt-2">
<div class="flex items-center gap-2">
<Checkbox id="def_NumParteAme" bind:checked={formData.NumParteAme} />
<Label for="def_NumParteAme" class="text-sm">El número de parte</Label>
</div>
<div class="flex items-center gap-2">
<Checkbox id="def_FraccionAme" bind:checked={formData.FraccionAme} />
<Label for="def_FraccionAme" class="text-sm">La fracción americana</Label>
</div>
<div class="flex items-center gap-2">
<Checkbox id="def_PaisOrigenAme" bind:checked={formData.PaisOrigenAme} />
<Label for="def_PaisOrigenAme" class="text-sm">El país de origen</Label>
</div>
<div class="flex items-center gap-2">
<Checkbox id="def_UMEquivalenteAme" bind:checked={formData.UMEquivalenteAme} />
<Label for="def_UMEquivalenteAme" class="text-sm">La U.M. N. Equivalente</Label>
</div>
</div>
</div>
<!-- Entradas grandes de texto -->
<div class="space-y-4 border rounded-md p-4 bg-muted/10">
<div class="space-y-2">
<Label for="def_LeyendaFacAme" class="text-sm font-semibold text-muted-foreground">Leyenda factura</Label>
<Textarea id="def_LeyendaFacAme" bind:value={formData.LeyendaFacAme} class="h-24 resize-y" />
</div>
<div class="space-y-2 pt-4">
<Label for="def_FirmaFAme" class="text-sm font-semibold text-muted-foreground">Firma en factura americana</Label>
<Textarea id="def_FirmaFAme" bind:value={formData.FirmaFAme} class="h-24 resize-y" />
</div>
</div>
</Tabs.Content>
<!-- PACKING LIST TAB -->
<Tabs.Content value="packing" class="space-y-6">
<!-- Opciones de Packing List -->
<div class="space-y-4 border rounded-md p-4 bg-muted/10">
<h4 class="text-sm font-semibold text-muted-foreground uppercase border-b pb-2">Opciones de Packing List</h4>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4 pt-2">
<div class="flex items-center gap-2">
<Checkbox id="def_PackingPedClave" bind:checked={formData.PackingPedClave} />
<Label for="def_PackingPedClave" class="text-sm">Muestra el número de pedimento y su clave de pedimento en el Packing List</Label>
</div>
<div class="flex items-center gap-2">
<Checkbox id="def_PackingOrdenCompra" bind:checked={formData.PackingOrdenCompra} />
<Label for="def_PackingOrdenCompra" class="text-sm">Imprimir orden de compra</Label>
</div>
<div class="flex items-center gap-2">
<Checkbox id="def_IncluirLineaDelPO" bind:checked={formData.IncluirLineaDelPO} />
<Label for="def_IncluirLineaDelPO" class="text-sm">Incluir línea de PO</Label>
</div>
</div>
</div>
<!-- Imprimir por -->
<div class="space-y-4 border rounded-md p-4 bg-muted/10">
<h4 class="text-sm font-semibold text-muted-foreground uppercase">Imprimir por</h4>
<RadioGroup value={formData.PorOrdenPorOCPack} onValueChange={(v) => formData.PorOrdenPorOCPack = v} class="flex gap-4">
<div class="flex items-center gap-2">
<RadioGroupItem value="captura" id="def_pack_imprimir_captura" />
<Label for="def_pack_imprimir_captura" class="text-sm">Orden de captura</Label>
</div>
<div class="flex items-center gap-2">
<RadioGroupItem value="compra" id="def_pack_imprimir_compra" />
<Label for="def_pack_imprimir_compra" class="text-sm">Orden de compra</Label>
</div>
</RadioGroup>
</div>
</Tabs.Content>
</Tabs.Root>
</div>

View File

@@ -65,9 +65,9 @@
}
</script>
<div class="flex flex-col gap-2.5 p-4 rounded-xl bg-white/5 border border-white/5 hover:border-primary/30 transition-all group">
<div class="flex flex-col gap-2 {mode === 'switch' ? 'flex-row items-center justify-between md:flex-row' : ''}">
<Label for={key} class="text-sm font-medium {mode === 'switch' ? 'text-white/80 cursor-pointer lg:max-w-[70%]' : 'text-white/40 ml-1'} {disabled ? 'opacity-30 cursor-not-allowed' : ''}">
<div class="flex flex-col gap-2.5">
<div class="flex flex-col gap-2 {mode === 'switch' ? 'flex-row items-center justify-between' : ''}">
<Label for={key} class="text-sm font-medium {disabled ? 'opacity-50 cursor-not-allowed' : ''} {mode === 'switch' ? 'cursor-pointer' : ''}">
{label || key}
</Label>
@@ -78,14 +78,14 @@
onValueChange={handleSelectChange}
disabled={disabled}
>
<Select.Trigger class="w-full bg-[#0f0f0f] border-white/10 text-white rounded-xl focus:ring-primary/40 h-11 px-4 flex items-center justify-between group">
<Select.Trigger class="w-full">
<span class="truncate">
{options.find(opt => String(opt.value) === selectValue)?.label || "Seleccionar..."}
</span>
</Select.Trigger>
<Select.Content class="bg-[#0f0f0f] border-white/10 text-white min-w-[200px]">
<Select.Content>
{#each options as opt}
<Select.Item value={String(opt.value)} label={opt.label} class="hover:bg-primary/20 focus:bg-primary/20 text-white">
<Select.Item value={String(opt.value)} label={opt.label}>
{opt.label}
</Select.Item>
{/each}
@@ -101,7 +101,7 @@
{#each options || [] as opt}
<div class="flex items-center space-x-3">
<RadioGroup.Item value={String(opt.value)} id={`${key}-${opt.value}`} />
<Label for={`${key}-${opt.value}`} class="text-sm font-medium text-white/70 cursor-pointer {disabled ? 'cursor-not-allowed' : ''}">
<Label for={`${key}-${opt.value}`} class="text-sm font-medium cursor-pointer {disabled ? 'cursor-not-allowed' : ''}">
{opt.label}
</Label>
</div>
@@ -115,7 +115,7 @@
disabled={disabled}
/>
{:else}
<div class="relative group space-y-1.5">
<div class="space-y-1.5">
{#if mode === 'path'}
<div class="flex gap-2">
<Input
@@ -124,16 +124,16 @@
oninput={(e: any) => onChange(e.target.value)}
placeholder="Ruta del directorio..."
disabled={disabled}
class="flex-1 bg-[#0f0f0f] border-white/5 text-white rounded-xl focus:ring-primary/40 h-11 px-4 pr-10 hover:border-white/20 transition-all font-mono text-xs"
class="font-mono text-xs text-foreground bg-background"
/>
<Button
variant="outline"
size="icon"
disabled={disabled}
onclick={handleBrowse}
class="h-11 w-11 shrink-0 bg-white/[0.03] border-white/10 hover:bg-white/[0.08] hover:border-primary/50 text-white transition-all shadow-xl"
class="shrink-0"
>
<FolderOpen class="w-4 h-4 text-primary" />
<FolderOpen class="w-4 h-4" />
</Button>
</div>
{:else if mode === 'password'}
@@ -144,7 +144,7 @@
oninput={(e: any) => onChange(e.target.value)}
placeholder="••••••••"
disabled={disabled}
class="bg-[#0f0f0f] border-white/5 text-white rounded-xl focus:ring-primary/40 h-11 px-4 hover:border-white/20 transition-all w-full"
class="text-foreground bg-background"
/>
{:else if mode === 'number'}
<Input
@@ -153,7 +153,7 @@
value={value || ""}
oninput={(e: any) => onChange(Number(e.target.value))}
disabled={disabled}
class="bg-[#0f0f0f] border-white/5 text-white rounded-xl focus:ring-primary/40 h-11 px-4 hover:border-white/20 transition-all w-full text-right"
class="text-right text-foreground bg-background"
/>
{:else}
<Input
@@ -161,11 +161,11 @@
value={value || ""}
oninput={(e: any) => onChange(e.target.value)}
disabled={disabled}
class="bg-[#0f0f0f] border-white/5 text-white rounded-xl focus:ring-primary/40 h-11 px-4 hover:border-white/20 transition-all"
class="text-foreground bg-background"
/>
{/if}
{#if hint}
<p class="text-[10px] text-white/30 ml-1 font-medium italic">
<p class="text-[10px] text-muted-foreground ml-1 font-medium italic">
{hint}
</p>
{/if}
@@ -174,6 +174,3 @@
</div>
</div>
<style>
/* Minimal styling for radio group items if needed */
</style>

View File

@@ -451,28 +451,28 @@
];
</script>
<div class="h-full flex flex-col bg-[#080808] rounded-2xl border border-white/5 overflow-hidden shadow-2xl">
<div class="w-full">
<Tabs.Root value="general" class="flex flex-col h-full">
<Tabs.List class="flex flex-wrap gap-1 p-3 bg-black/60 border-b border-white/5 h-auto">
<Tabs.List class="grid w-full grid-cols-3 md:grid-cols-5 lg:grid-cols-9 bg-muted rounded-md p-1 mb-4">
{#each TABS as tab}
<Tabs.Trigger
value={tab.id}
class="px-5 py-2.5 text-xs font-bold uppercase tracking-wider data-[state=active]:bg-primary data-[state=active]:text-white rounded-lg opacity-40 data-[state=active]:opacity-100 hover:opacity-70"
class="w-full px-3 py-1.5 text-sm font-medium transition-all focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 data-[state=active]:bg-background data-[state=active]:text-foreground data-[state=active]:shadow-sm"
>
{tab.label}
</Tabs.Trigger>
{/each}
</Tabs.List>
<Tabs.Content value="general" class="flex-1 overflow-hidden p-0 m-0 bg-transparent">
<div class="h-full w-full overflow-y-scroll custom-scrollbar p-6 space-y-12 min-h-[600px]">
<Tabs.Content value="general" class="space-y-6">
<div class="space-y-6 py-4">
{#each GENERAL_SECTIONS as section}
<div class="space-y-4">
<div class="flex items-center gap-4">
<h3 class="text-xs font-bold uppercase tracking-[0.2em] text-primary/80 whitespace-nowrap">
<h3 class="font-medium text-lg">
{section.title}
</h3>
<div class="h-[1px] w-full bg-gradient-to-r from-primary/20 to-transparent"></div>
<div class="h-px w-full bg-border mt-2"></div>
</div>
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
@@ -490,15 +490,15 @@
</div>
</Tabs.Content>
<Tabs.Content value="archivos" class="flex-1 overflow-hidden p-0 m-0 bg-transparent">
<div class="h-full w-full overflow-y-scroll custom-scrollbar p-6 space-y-8 min-h-[600px]">
<Tabs.Content value="archivos" class="space-y-6">
<div class="space-y-6 py-4">
{#each ARCHIVOS_SECTIONS as section}
<div class="space-y-6 max-w-3xl mx-auto">
<div class="flex items-center gap-4">
<h3 class="text-xs font-bold uppercase tracking-[0.2em] text-primary/80 whitespace-nowrap">
<h3 class="font-medium text-lg">
{section.title}
</h3>
<div class="h-[1px] w-full bg-gradient-to-r from-primary/20 to-transparent"></div>
<div class="h-px w-full bg-border mt-2"></div>
</div>
<div class="grid grid-cols-1 gap-4">
@@ -516,15 +516,15 @@
</div>
</Tabs.Content>
<Tabs.Content value="continuacion" class="flex-1 overflow-hidden p-0 m-0 bg-transparent">
<div class="h-full w-full overflow-y-scroll custom-scrollbar p-6 space-y-12 min-h-[600px]">
<Tabs.Content value="continuacion" class="space-y-6">
<div class="space-y-6 py-4">
{#each CONTINUACION_SECTIONS as section}
<div class="space-y-4">
<div class="flex items-center gap-4">
<h3 class="text-xs font-bold uppercase tracking-[0.2em] text-primary/80 whitespace-nowrap">
<h3 class="font-medium text-lg">
{section.title}
</h3>
<div class="h-[1px] w-full bg-gradient-to-r from-primary/20 to-transparent"></div>
<div class="h-px w-full bg-border mt-2"></div>
</div>
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
@@ -543,15 +543,15 @@
</div>
</Tabs.Content>
<Tabs.Content value="cont2" class="flex-1 overflow-hidden p-0 m-0 bg-transparent">
<div class="h-full w-full overflow-y-scroll custom-scrollbar p-6 space-y-8 min-h-[600px]">
<Tabs.Content value="cont2" class="space-y-6">
<div class="space-y-6 py-4">
{#each CONT2_SECTIONS as section}
<div class="space-y-6 max-w-4xl mx-auto">
<div class="flex items-center gap-4">
<h3 class="text-xs font-bold uppercase tracking-[0.2em] text-primary/80 whitespace-nowrap">
<h3 class="font-medium text-lg">
{section.title}
</h3>
<div class="h-[1px] w-full bg-gradient-to-r from-primary/20 to-transparent"></div>
<div class="h-px w-full bg-border mt-2"></div>
</div>
<div class="grid grid-cols-1 gap-4">
@@ -569,15 +569,15 @@
</div>
</Tabs.Content>
<Tabs.Content value="cont3" class="flex-1 overflow-hidden p-0 m-0 bg-transparent">
<div class="h-full w-full overflow-y-scroll custom-scrollbar p-6 space-y-12 min-h-[600px]">
<Tabs.Content value="cont3" class="space-y-6">
<div class="space-y-6 py-4">
{#each CONT3_SECTIONS as section}
<div class="space-y-6 max-w-4xl mx-auto">
<div class="flex items-center gap-4">
<h3 class="text-xs font-bold uppercase tracking-[0.2em] text-primary/80 whitespace-nowrap">
<h3 class="font-medium text-lg">
{section.title}
</h3>
<div class="h-[1px] w-full bg-gradient-to-r from-primary/20 to-transparent"></div>
<div class="h-px w-full bg-border mt-2"></div>
</div>
<div class="grid grid-cols-1 gap-4">
@@ -601,18 +601,18 @@
</div>
</Tabs.Content>
<Tabs.Content value="cont4" class="flex-1 overflow-hidden p-0 m-0 bg-transparent">
<div class="h-full w-full overflow-y-scroll custom-scrollbar p-6 space-y-8 min-h-[600px]">
<div class="max-w-4xl mx-auto space-y-12">
<div class="space-y-6 p-6 rounded-2xl border border-white/5 bg-white/[0.01]">
<Tabs.Content value="cont4" class="space-y-6">
<div class="space-y-6 py-4">
<div class="max-w-4xl mx-auto space-y-6">
<div class="space-y-6 p-6 rounded-2xl border border-border bg-muted/20">
{#each CONT4_SECTIONS.filter(s => s.id !== 'additional_options') as section}
<div class="space-y-6">
<div class="flex items-center gap-4">
<h3 class="text-xs font-bold uppercase tracking-[0.2em] text-primary/80 whitespace-nowrap">
<h3 class="font-medium text-lg">
{section.title}
</h3>
<div class="h-[1px] w-full bg-gradient-to-r from-primary/20 to-transparent"></div>
<div class="h-px w-full bg-border mt-2"></div>
</div>
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
@@ -651,10 +651,10 @@
<!-- Outside Options -->
<div class="space-y-6">
<div class="flex items-center gap-4">
<h3 class="text-xs font-bold uppercase tracking-[0.2em] text-white/40 whitespace-nowrap">
<h3 class="font-medium text-lg">
Opciones Adicionales
</h3>
<div class="h-[1px] w-full bg-gradient-to-r from-white/10 to-transparent"></div>
<div class="h-px w-full bg-border mt-2"></div>
</div>
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
@@ -672,16 +672,16 @@
</div>
</Tabs.Content>
<Tabs.Content value="cont5" class="flex-1 overflow-hidden p-0 m-0 bg-transparent">
<div class="h-full w-full overflow-y-scroll custom-scrollbar p-6 space-y-12 min-h-[600px]">
<div class="max-w-4xl mx-auto space-y-12">
<Tabs.Content value="cont5" class="space-y-6">
<div class="space-y-6 py-4">
<div class="max-w-4xl mx-auto space-y-6">
{#each CONT5_SECTIONS as section}
<div class="space-y-6 p-6 rounded-2xl border border-white/5 bg-white/[0.01]">
<div class="space-y-6 p-6 rounded-2xl border border-border bg-muted/20">
<div class="flex items-center gap-4">
<h3 class="text-xs font-bold uppercase tracking-[0.2em] text-primary/80 whitespace-nowrap">
<h3 class="font-medium text-lg">
{section.title}
</h3>
<div class="h-[1px] w-full bg-gradient-to-r from-primary/20 to-transparent"></div>
<div class="h-px w-full bg-border mt-2"></div>
</div>
<div class="grid grid-cols-1 {section.id === 'inv_inicial' ? '' : 'md:grid-cols-2 lg:grid-cols-3'} gap-6">
@@ -705,16 +705,16 @@
</div>
</Tabs.Content>
<Tabs.Content value="cont6" class="flex-1 overflow-hidden p-0 m-0 bg-transparent">
<div class="h-full w-full overflow-y-scroll custom-scrollbar p-6 min-h-[600px]">
<Tabs.Content value="cont6" class="space-y-6">
<div class="space-y-6 py-4">
<div class="max-w-5xl mx-auto grid grid-cols-1 lg:grid-cols-2 gap-12">
<!-- Columna Izquierda: Opciones de Configuración -->
<div class="space-y-8">
<div class="flex items-center gap-4">
<h3 class="text-xs font-bold uppercase tracking-[0.2em] text-primary/80 whitespace-nowrap">
<h3 class="font-medium text-lg">
Opciones de Configuración
</h3>
<div class="h-[1px] w-full bg-gradient-to-r from-primary/20 to-transparent"></div>
<div class="h-px w-full bg-border mt-2"></div>
</div>
<div class="space-y-4">
@@ -734,14 +734,14 @@
</div>
<!-- Columna Derecha: Acciones y Módulos -->
<div class="space-y-12">
<div class="space-y-6">
<!-- Módulos -->
<div class="space-y-8">
<div class="flex items-center gap-4">
<h3 class="text-xs font-bold uppercase tracking-[0.2em] text-primary/80 whitespace-nowrap">
<h3 class="font-medium text-lg">
Módulos del Sistema
</h3>
<div class="h-[1px] w-full bg-gradient-to-r from-primary/20 to-transparent"></div>
<div class="h-px w-full bg-border mt-2"></div>
</div>
<div class="space-y-4">
@@ -760,29 +760,29 @@
<!-- Acciones -->
<div class="space-y-8">
<div class="flex items-center gap-4">
<h3 class="text-xs font-bold uppercase tracking-[0.2em] text-white/40 whitespace-nowrap">
<h3 class="font-medium text-lg">
Acciones de Gestión
</h3>
<div class="h-[1px] w-full bg-gradient-to-r from-white/10 to-transparent"></div>
<div class="h-px w-full bg-border mt-2"></div>
</div>
<div class="grid grid-cols-1 gap-4">
<Button variant="outline" class="w-full flex items-center justify-start gap-4 h-12 rounded-xl border-white/5 bg-white/[0.02] hover:bg-white/[0.05] text-white/80 group">
<Button variant="outline" class="w-full flex items-center justify-start gap-4 h-12 rounded-xl border-border bg-background hover:bg-accent text-foreground group">
<AlertTriangle class="w-5 h-5 text-red-500 group-hover:scale-110 transition-transform" />
Eliminar Accesos Abiertos
</Button>
<Button variant="outline" class="w-full flex items-center justify-start gap-4 h-12 rounded-xl border-white/5 bg-white/[0.02] hover:bg-white/[0.05] text-white/80 group">
<Button variant="outline" class="w-full flex items-center justify-start gap-4 h-12 rounded-xl border-border bg-background hover:bg-accent text-foreground group">
<CreditCard class="w-5 h-5 text-primary group-hover:scale-110 transition-transform" />
Asignar Formas de Pago Para Anexo 31
</Button>
<Button variant="outline" class="w-full flex items-center justify-start gap-4 h-12 rounded-xl border-white/5 bg-white/[0.02] hover:bg-white/[0.05] text-white/80 group">
<Button variant="outline" class="w-full flex items-center justify-start gap-4 h-12 rounded-xl border-border bg-background hover:bg-accent text-foreground group">
<FileEdit class="w-5 h-5 text-primary group-hover:scale-110 transition-transform" />
Corrección de partidas expo
</Button>
<Button variant="outline" class="w-full flex items-center justify-start gap-4 h-12 rounded-xl border-white/5 bg-white/[0.02] hover:bg-white/[0.05] text-white/80 group">
<Button variant="outline" class="w-full flex items-center justify-start gap-4 h-12 rounded-xl border-border bg-background hover:bg-accent text-foreground group">
<RefreshCw class="w-5 h-5 text-primary group-hover:scale-110 transition-transform" />
Actualizar Tarifa
</Button>
@@ -793,20 +793,20 @@
</div>
</Tabs.Content>
<Tabs.Content value="cont7" class="flex-1 overflow-hidden p-0 m-0 bg-transparent">
<div class="h-full w-full overflow-y-scroll custom-scrollbar p-6 space-y-8 min-h-[600px]">
<Tabs.Content value="cont7" class="space-y-6">
<div class="space-y-6 py-4">
{#each CONT7_SECTIONS as section}
<div class="space-y-6 max-w-4xl mx-auto">
<div class="flex items-center gap-4">
<h3 class="text-xs font-bold uppercase tracking-[0.2em] text-primary/80 whitespace-nowrap">
<h3 class="font-medium text-lg">
{section.title}
</h3>
<div class="h-[1px] w-full bg-gradient-to-r from-primary/20 to-transparent"></div>
<div class="h-px w-full bg-border mt-2"></div>
</div>
<div class="grid grid-cols-1 gap-4">
<!-- Especial Row: Activar Valor Agregado Gral + Numeric Input -->
<div class="flex flex-col md:flex-row items-center gap-4 p-4 rounded-xl border border-white/5 bg-white/[0.02]">
<div class="flex flex-col md:flex-row items-center gap-4 p-4 rounded-xl border border-border bg-background">
<div class="flex-1">
<SettingFormField
key="actvaloragre"

View File

@@ -124,13 +124,11 @@
</script>
<Sheet.Root bind:open={helpStore.isOpen}>
<Sheet.Trigger asChild>
<button
class="fixed right-6 bottom-6 z-50 flex h-14 w-14 items-center justify-center rounded-full bg-primary text-primary-foreground shadow-lg transition-transform hover:scale-110 active:scale-95"
aria-label="Ayuda"
>
<HelpCircle size={28} />
</button>
<Sheet.Trigger
class="fixed right-6 bottom-6 z-50 flex h-14 w-14 items-center justify-center rounded-full bg-primary text-primary-foreground shadow-lg transition-transform hover:scale-110 active:scale-95"
aria-label="Ayuda"
>
<HelpCircle size={28} />
</Sheet.Trigger>
<Sheet.Content side="right" class="w-[400px] sm:w-[540px]">
<Sheet.Header>
@@ -170,7 +168,7 @@
>
<span class="font-semibold">{article.title}</span>
<span class="text-xs text-muted-foreground">
Última edición: {browser ? new Date(article.updated_at).toLocaleDateString() : article.updated_at.split('T')[0]}
Última edición: {article.updated_at ? article.updated_at.split('T')[0] : '...'}
</span>
</button>
{/each}

View File

@@ -1,13 +1,21 @@
<script lang="ts">
import { onMount } from 'svelte';
import { browser } from '$app/environment';
import { page } from '$app/stores';
import * as Tabs from '$lib/components/ui/tabs';
import * as Card from '$lib/components/ui/card';
import { Button } from '$lib/components/ui/button';
import { Label } from '$lib/components/ui/label';
import { Input } from '$lib/components/ui/input';
import { LoaderCircle, Save, FileText, Eye, DollarSign, Truck, Package } from 'lucide-svelte';
import { Badge } from '$lib/components/ui/badge';
import { Separator } from '$lib/components/ui/separator';
import {
LoaderCircle, Save, FileText, Eye, DollarSign,
Truck, Package, ArrowLeft
} from 'lucide-svelte';
import { toast } from 'svelte-sonner';
import { api } from '$lib/api';
import { goto } from '$app/navigation';
import { Select, SelectContent, SelectItem, SelectTrigger } from '$lib/components/ui/select';
// Import Form Components
import GeneralTabForm from '$lib/components/dashboard/invoices/edit/general-tab-form.svelte';
@@ -16,6 +24,10 @@
import OthersTabForm from '$lib/components/dashboard/invoices/edit/others-tab-form.svelte';
import InvoiceTopFields from '$lib/components/dashboard/invoices/edit/invoice-top-fields.svelte';
import ContinuationTabForm from '$lib/components/dashboard/invoices/edit/continuation-tab-form.svelte';
import SsimpSettingsForm from '$lib/components/dashboard/invoices/settings/ssimp-settings-form.svelte';
import SsisdefSettingsForm from '$lib/components/dashboard/invoices/settings/ssisdef-settings-form.svelte';
import SsicmSettingsForm from '$lib/components/dashboard/invoices/settings/ssicm-settings-form.svelte';
import SscrSettingsForm from '$lib/components/dashboard/invoices/settings/sscr-settings-form.svelte';
// Props
let { data } = $props();
@@ -28,50 +40,33 @@
let activeTab = $state('general');
let companyStore: any = $state(undefined);
// Form Data State
let InvoiceTopFieldsFormData = $state<any>({});
let generalFormData = $state<any>({});
let observationFormData = $state<any>({});
let itemsFormData = $state<any>({});
let othersFormData = $state<any>({
comments_status: '',
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: ''
});
let continuationFormData = $state<any>({
numero_tipo_transporte: '',
es_ferrocarril: 'no',
numero_bl: '',
cantidad_guias_embarque: null,
destino_origen: '',
puerto_entrada: '',
fue_revisado_equipo: false,
sub_division: false,
funge_como_cd: false,
llego_pedimento: false,
errores_facturacion: [],
semaforo_verde_aduana_mexicana: false,
semaforo_verde_aduana_americana: false,
semaforo_rojo_aduana_mexicana: false,
semaforo_rojo_aduana_americana: false
});
// Form Data State - Initialize as null to let components self-initialize
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);
let ssimpFormData = $state<any>(null);
// Dummy objects for components
let invoice = $state<any>({
financials: { exchange_rate: 0 }
});
// Derived object for components to consume context
// We use a getter to avoid circular reactivity issues during initialization
let invoice = $derived.by(() => ({
id: 0,
tenant_id: 0,
company_id: companyStore?.activeCompany?.id || 0,
capture_date: new Date().toISOString(),
operation_type: selectedOperationType,
invoice_type: selectedInvoiceType,
financials: { exchange_rate: 0 },
compliance_mx: {
pedimento_id: InvoiceTopFieldsFormData?.pedimento_id || '',
remesa: InvoiceTopFieldsFormData?.remesa || ''
},
invoice_number: InvoiceTopFieldsFormData?.invoice_number || '',
invoice_date: InvoiceTopFieldsFormData?.invoice_date || '',
alternate_invoice: observationFormData?.alternate_invoice || ''
}) as any);
// Existence flags (not strictly needed for settings but required by components)
let observationExists = $state(false);
@@ -98,21 +93,12 @@
isLoading = true;
try {
const token = $page.data.user?.token;
const headers: HeadersInit = {
'Content-Type': 'application/json'
};
if (token) {
headers['Authorization'] = `Bearer ${token}`;
}
const res = await fetch(
`/api/v1/a76/invoice-settings/${selectedInvoiceType}?operation_type=${selectedOperationType}&company_id=${companyStore.activeCompany.id}`,
{ headers }
const res = await api.get(
`/v1/a76/invoice-settings/${selectedInvoiceType}?operation_type=${selectedOperationType}&company_id=${companyStore.activeCompany.id}`
);
if (res.ok) {
const settingsData = await res.json();
if (res.status === 200 || res.data) {
const settingsData = res.data;
if (settingsData && settingsData.settings) {
applySettings(settingsData.settings);
} else {
@@ -187,6 +173,7 @@
...(settings.observationFormData || {})
};
itemsFormData = settings.itemsFormData || {};
ssimpFormData = settings.ssimpFormData || {};
othersFormData = {
comments_status: '',
transport_mode: 'TRUCK',
@@ -224,13 +211,7 @@
...(settings.continuationFormData || {})
};
// Update the 'invoice' dummy object to reflect some top fields if needed for display
invoice = {
...invoice,
...InvoiceTopFieldsFormData,
operation_type: selectedOperationType,
invoice_type: selectedInvoiceType
};
// The derived 'invoice' will update automatically because it spread InvoiceTopFieldsFormData
}
function resetForms() {
@@ -288,6 +269,7 @@
valuation_method: null
};
itemsFormData = {};
ssimpFormData = {};
othersFormData = {
comments_status: '',
transport_mode: 'TRUCK',
@@ -322,7 +304,7 @@
semaforo_rojo_aduana_mexicana: false,
semaforo_rojo_aduana_americana: false
};
invoice = { financials: { exchange_rate: 0 } };
// The derived 'invoice' handles itself
}
function cleanObject(obj: any): any {
@@ -346,6 +328,26 @@
return obj;
}
function handleBack() {
goto('/dashboard/invoices');
}
let operationTypeText = $derived.by(() => {
if (selectedOperationType === 'exp') return 'EXPORTACIÓN';
if (selectedOperationType === 'imp') return 'IMPORTACIÓN';
return 'TIPO NO DEFINIDO';
});
let operationColorClass = $derived.by(() => {
if (selectedOperationType === 'exp') return 'bg-blue-500/10 text-blue-600 border-blue-500/20';
if (selectedOperationType === 'imp') return 'bg-emerald-500/10 text-emerald-600 border-emerald-500/20';
return 'bg-muted text-muted-foreground border-border';
});
// Contexto reactivo para componentes
let invoiceType = $derived(selectedInvoiceType || 'TEM');
let operationTypeNumeric = $derived(selectedOperationType === 'exp' ? 1 : 2);
async function handleSaveSettings() {
if (!selectedInvoiceType || !selectedOperationType || !companyStore?.activeCompany?.id) {
toast.error('Por favor selecciona tipo de factura y operación');
@@ -360,6 +362,7 @@
generalFormData: $state.snapshot(generalFormData),
observationFormData: $state.snapshot(observationFormData),
itemsFormData: $state.snapshot(itemsFormData),
ssimpFormData: $state.snapshot(ssimpFormData),
othersFormData: $state.snapshot(othersFormData),
continuationFormData: $state.snapshot(continuationFormData)
};
@@ -374,28 +377,15 @@
};
try {
const token = $page.data.user?.token;
const headers: HeadersInit = {
'Content-Type': 'application/json'
};
if (token) {
headers['Authorization'] = `Bearer ${token}`;
}
const response = await fetch(
`/api/v1/a76/invoice-settings/?company_id=${companyStore.activeCompany.id}`,
{
method: 'PUT',
headers,
body: JSON.stringify(settingsPayload)
}
const response = await api.put(
`/v1/a76/invoice-settings/?company_id=${companyStore.activeCompany.id}`,
settingsPayload
);
if (response.ok) {
if (response.status === 200 || response.data) {
toast.success('Configuración guardada correctamente.');
} else {
const errorData = await response.json().catch(() => ({}));
console.error('Save error details:', errorData);
console.error('Save error details:', response.error || response.validationErrors);
toast.error('Error al guardar la configuración.');
}
} catch (error) {
@@ -407,179 +397,304 @@
}
// Watch for selection changes
// We'll call loadSettings manually when selection changes to avoid reactive loops
$effect(() => {
if (selectedInvoiceType && selectedOperationType && companyStore?.activeCompany?.id) {
if (browser && !InvoiceTopFieldsFormData && companyStore?.activeCompany?.id) {
loadSettings();
}
});
// Handle explicit changes
function handleOperationTypeChange(v: string) {
selectedOperationType = v;
loadSettings();
}
function handleInvoiceTypeChange(v: string) {
selectedInvoiceType = v;
loadSettings();
}
</script>
<div class="container mx-auto py-6 pb-32">
<!-- Added padding bottom for footer -->
<div class="mb-6 flex items-center justify-between">
<div>
<h1 class="text-2xl font-bold tracking-tight">Configuración de Facturas</h1>
<p class="text-muted-foreground">
Define los valores predeterminados para la creación de facturas.
</p>
</div>
</div>
<Card.Root class="mb-6">
<Card.Header>
<Card.Title>Contexto de Configuración</Card.Title>
<Card.Description
>Selecciona el contexto para editar sus valores por defecto.</Card.Description
>
</Card.Header>
<Card.Content class="flex gap-4">
<div class="w-[250px]">
<Label>Tipo de Operación</Label>
<Select type="single" bind:value={selectedOperationType}>
<SelectTrigger>
{operationTypes.find((t) => t.value === selectedOperationType)?.label ||
'Seleccionar...'}
</SelectTrigger>
<SelectContent>
{#each operationTypes as type}
<SelectItem value={type.value}>{type.label}</SelectItem>
{/each}
</SelectContent>
</Select>
</div>
<div class="w-[350px]">
<Label>Tipo de Factura</Label>
<Select type="single" bind:value={selectedInvoiceType}>
<SelectTrigger>
{@const type = data.invoiceTypes.find((t) => t.key === selectedInvoiceType)}
{type ? `${type.key} - ${type.description}` : 'Seleccionar...'}
</SelectTrigger>
<SelectContent class="max-h-[300px]">
{#each data.invoiceTypes as type}
<SelectItem value={type.key}>{type.key} - {type.description}</SelectItem>
{/each}
</SelectContent>
</Select>
</div>
</Card.Content>
</Card.Root>
{#if selectedInvoiceType && selectedOperationType}
{#if isLoading}
<div class="flex justify-center py-12">
<LoaderCircle class="animate-spin h-8 w-8 text-primary" />
</div>
{:else}
<div class="grid gap-6">
<!-- Top Fields (Header) -->
<div class="bg-background rounded-lg border p-4">
<h3 class="font-medium mb-4">Encabezado</h3>
<InvoiceTopFields
{invoice}
bind:formData={InvoiceTopFieldsFormData}
invoiceTypes={data.invoiceTypes || []}
pedimentos={data.pedimentos || []}
defaultOperationType={selectedOperationType}
defaultInvoiceType={selectedInvoiceType}
/>
<Tabs.Root bind:value={activeTab}>
<div class="space-y-4">
<!-- Header -->
<div class="flex items-center justify-between">
<div class="space-y-1">
<div class="flex items-center gap-3">
<Button variant="ghost" size="icon" onclick={handleBack}>
<ArrowLeft size={20} />
</Button>
<h1 class="text-3xl font-bold tracking-tight">
Configuración de Facturas
</h1>
{#if selectedOperationType}
<Badge variant="outline" class="px-3 py-1 text-sm font-bold {operationColorClass}">
{operationTypeText}
</Badge>
{/if}
{#if selectedInvoiceType}
<Badge variant="secondary">
{data.invoiceTypes.find((t: any) => t.key === selectedInvoiceType)?.description || selectedInvoiceType}
</Badge>
{/if}
</div>
<!-- Tabs for detailed sections -->
<Tabs.Root bind:value={activeTab}>
<Tabs.List class="grid w-full grid-cols-5 bg-muted rounded-md p-1 mb-4">
<Tabs.Trigger value="general">General</Tabs.Trigger>
<Tabs.Trigger value="observations">Observaciones</Tabs.Trigger>
<Tabs.Trigger value="items">Partidas</Tabs.Trigger>
<Tabs.Trigger value="others">Otros</Tabs.Trigger>
<Tabs.Trigger value="continuation">Continuación</Tabs.Trigger>
</Tabs.List>
<Tabs.Content value="general">
<GeneralTabForm
{invoice}
bind:formData={generalFormData}
invoiceTypes={data.invoiceTypes || []}
customsBrokers={data.customsBrokers || []}
clients={data.clients || []}
providers={data.providers || []}
currencyTypes={data.currencyTypes || []}
transportTypes={data.transportTypes || []}
transporters={data.transporters || []}
vehicles={data.vehicles || []}
drivers={data.drivers || []}
trailers={data.trailers || []}
customsSections={data.customsSections || []}
codePedimentoRegimens={data.codePedimentoRegimens || []}
operationType={selectedOperationType === 'exp' ? 1 : 2}
exchangeRate={0}
/>
</Tabs.Content>
<Tabs.Content value="observations">
<ObservationsTabForm
{invoice}
bind:formData={observationFormData}
bind:exists={observationExists}
seals={[]}
incoterms={data.incoterms || []}
enclosure={[]}
/>
</Tabs.Content>
<Tabs.Content value="items">
<div class="p-4 border rounded bg-muted/20 text-center">
<p class="text-sm text-muted-foreground">
La configuración predeterminada de partidas es limitada.
</p>
</div>
</Tabs.Content>
<Tabs.Content value="others">
<OthersTabForm
{invoice}
bind:formData={othersFormData}
bind:exists={othersExists}
transportModes={data.transportModes || []}
/>
</Tabs.Content>
<Tabs.Content value="continuation">
<ContinuationTabForm
{invoice}
bind:formData={continuationFormData}
bind:exists={continuationExists}
/>
</Tabs.Content>
</Tabs.Root>
<p class="text-muted-foreground">
Define los valores predeterminados para la creación de facturas.
</p>
</div>
{/if}
{:else}
<div
class="flex flex-col items-center justify-center border-2 border-dashed rounded-lg p-12 text-muted-foreground"
>
<FileText class="h-10 w-10 mb-2 opacity-20" />
<p>Selecciona un tipo de operación y factura para comenzar.</p>
</div>
{/if}
</div>
<!-- Sticky Footer -->
<div
class="fixed bottom-0 left-0 right-0 bg-background/95 backdrop-blur border-t shadow-lg z-10 p-4 transition-all duration-300 group-has-data-[state=collapsed]/sidebar-wrapper:ml-[calc(var(--sidebar-width-icon))] ml-[calc(var(--sidebar-width))]"
>
<div class="container mx-auto max-w-[1400px] flex justify-end gap-3">
<Button variant="outline" onclick={resetForms} disabled={isSaving || !selectedInvoiceType}>
Restablecer
</Button>
<Button onclick={handleSaveSettings} disabled={isSaving || !selectedInvoiceType}>
{#if isSaving}
<LoaderCircle class="mr-2 h-4 w-4 animate-spin" />
Guardando...
<Separator />
<div class="pb-48">
<Card.Root class="mb-8 border-dashed bg-muted/30">
<Card.Header class="py-4">
<Card.Title class="text-lg">Contexto de Configuración</Card.Title>
<Card.Description
>Selecciona el contexto para editar sus valores por defecto.</Card.Description
>
</Card.Header>
<Card.Content class="flex gap-6 py-2">
<div class="space-y-2">
<Label class="text-xs uppercase text-muted-foreground font-bold tracking-wider">Tipo de Operación</Label>
<Select type="single" value={selectedOperationType} onValueChange={handleOperationTypeChange}>
<SelectTrigger class="w-[200px] h-10 bg-background">
{operationTypes.find((t: any) => t.value === selectedOperationType)?.label ||
'Seleccionar...'}
</SelectTrigger>
<SelectContent>
{#each operationTypes as type}
<SelectItem value={type.value}>{type.label}</SelectItem>
{/each}
</SelectContent>
</Select>
</div>
<div class="space-y-2">
<Label class="text-xs uppercase text-muted-foreground font-bold tracking-wider">Tipo de Factura</Label>
<Select type="single" value={selectedInvoiceType} onValueChange={handleInvoiceTypeChange}>
<SelectTrigger class="w-[300px] h-10 bg-background">
{@const type = data.invoiceTypes.find((t: any) => t.key === selectedInvoiceType)}
{type ? `${type.key} - ${type.description}` : 'Seleccionar...'}
</SelectTrigger>
<SelectContent class="max-h-[300px]">
{#each data.invoiceTypes as type}
<SelectItem value={type.key}>{type.key} - {type.description}</SelectItem>
{/each}
</SelectContent>
</Select>
</div>
</Card.Content>
</Card.Root>
{#if selectedInvoiceType && selectedOperationType}
{#if isLoading}
<div class="flex justify-center py-24">
<div class="flex flex-col items-center gap-4">
<LoaderCircle class="animate-spin h-10 w-10 text-primary" />
<p class="text-sm text-muted-foreground animate-pulse">Cargando configuración...</p>
</div>
</div>
{:else}
<div class="grid gap-6">
<!-- Top Fields (Header) -->
<div class="bg-background rounded-xl border-2 shadow-sm p-6">
<div class="flex items-center gap-2 mb-6 border-b pb-4">
<div class="p-1.5 bg-primary/10 rounded-md">
<FileText class="w-5 h-5 text-primary" />
</div>
<h3 class="text-lg font-bold">Encabezado Predeterminado</h3>
</div>
<InvoiceTopFields
{invoice}
bind:formData={InvoiceTopFieldsFormData}
invoiceTypes={data.invoiceTypes || []}
pedimentos={data.pedimentos || []}
defaultOperationType={selectedOperationType}
defaultInvoiceType={selectedInvoiceType}
{invoiceType}
isSettings={true}
/>
</div>
<div class="space-y-4">
<Tabs.Content value="general">
<GeneralTabForm
{invoice}
bind:formData={generalFormData}
invoiceTypes={data.invoiceTypes || []}
customsBrokers={data.customsBrokers || []}
clients={data.clients || []}
providers={data.providers || []}
currencyTypes={data.currencyTypes || []}
transportTypes={data.transportTypes || []}
transporters={data.transporters || []}
vehicles={data.vehicles || []}
drivers={data.drivers || []}
trailers={data.trailers || []}
customsSections={data.customsSections || []}
codePedimentoRegimens={data.codePedimentoRegimens || []}
operationType={operationTypeNumeric}
{invoiceType}
exchangeRate={0}
isSettings={true}
/>
</Tabs.Content>
<Tabs.Content value="observations">
<ObservationsTabForm
{invoice}
bind:formData={observationFormData}
bind:exists={observationExists}
seals={[]}
incoterms={data.incoterms || []}
enclosure={[]}
operationType={operationTypeNumeric}
{invoiceType}
isSettings={true}
/>
</Tabs.Content>
<Tabs.Content value="items">
<div class="p-12 border-2 border-dashed rounded-xl bg-muted/20 text-center flex flex-col items-center gap-4">
<div class="p-4 bg-muted rounded-full">
<DollarSign class="w-8 h-8 text-muted-foreground opacity-50" />
</div>
<div class="max-w-md">
<h4 class="font-bold text-lg">Configuración de Partidas</h4>
<p class="text-sm text-muted-foreground mt-1">
La configuración predeterminada de partidas es limitada desde esta sección. Los valores se heredarán de los maestros de productos cuando sea posible.
</p>
</div>
</div>
</Tabs.Content>
<Tabs.Content value="others">
<OthersTabForm
{invoice}
bind:formData={othersFormData}
bind:exists={othersExists}
transportModes={data.transportModes || []}
operationType={operationTypeNumeric}
{invoiceType}
isSettings={true}
/>
</Tabs.Content>
<Tabs.Content value="continuation">
<div class="space-y-6">
{#if invoiceType !== 'MEX'}
<div class="bg-background rounded-xl border p-6">
<h4 class="text-sm font-semibold uppercase text-muted-foreground mb-4">Captura de Valores por Defecto</h4>
<ContinuationTabForm
{invoice}
bind:formData={continuationFormData}
bind:exists={continuationExists}
operationType={operationTypeNumeric}
{invoiceType}
isSettings={true}
/>
</div>
{/if}
</div>
</Tabs.Content>
<Tabs.Content value="ssimp">
<div class="space-y-6">
<div class="bg-background rounded-xl border p-6">
<h4 class="text-sm font-semibold uppercase text-muted-foreground mb-4">
{selectedOperationType === 'exp'
? `Parámetros de Exportación ${data.invoiceTypes?.find((t: any) => t.key === invoiceType)?.description || invoiceType}`
: invoiceType === 'DEF'
? 'Parámetros Adicionales SSisDef'
: invoiceType === 'MEX'
? 'Parámetros Adicionales SSICM'
: 'Parámetros Adicionales SSimp'}
</h4>
{#if selectedOperationType === 'exp'}
<SscrSettingsForm bind:formData={ssimpFormData} />
{:else if invoiceType === 'DEF'}
<SsisdefSettingsForm bind:formData={ssimpFormData} />
{:else if invoiceType === 'MEX'}
<SsicmSettingsForm bind:formData={ssimpFormData} drivers={data.drivers || []} />
{:else}
<SsimpSettingsForm bind:formData={ssimpFormData} />
{/if}
</div>
</div>
</Tabs.Content>
</div>
</div>
{/if}
{:else}
<Save class="mr-2 h-4 w-4" />
Guardar Configuración
<div
class="flex flex-col items-center justify-center border-2 border-dashed rounded-xl p-24 text-muted-foreground bg-muted/10 mt-12"
>
<div class="p-6 bg-muted rounded-full mb-6">
<FileText class="h-16 w-16 opacity-20" />
</div>
<h3 class="text-xl font-bold text-foreground">Sin Contexto de Edición</h3>
<p class="max-w-xs text-center mt-2">
Selecciona un tipo de operación y factura para comenzar a editar los valores globales por defecto.
</p>
</div>
{/if}
</Button>
</div>
</div>
</div>
<!-- Sticky Footer -->
<div
class="fixed bottom-0 left-0 right-0 bg-background/95 backdrop-blur border-t shadow-lg z-[10] transition-all duration-300 md:ml-[calc(var(--sidebar-width))] group-has-data-[state=collapsed]/sidebar-wrapper:md:ml-[calc(var(--sidebar-width-icon))]"
>
<div class="container mx-auto max-w-[1400px] space-y-4 p-4">
<!-- Tabs Navigation (Only shown if context selected) -->
{#if selectedInvoiceType && selectedOperationType}
<div class="w-full overflow-x-auto pb-2">
<Tabs.List class="inline-flex md:grid md:w-full md:grid-cols-6 bg-muted rounded-md p-1 h-auto flex-wrap">
<Tabs.Trigger value="general" class="whitespace-nowrap">
<FileText size={16} class="mr-2" />
General
</Tabs.Trigger>
<Tabs.Trigger value="observations" class="whitespace-nowrap">
<Eye size={16} class="mr-2" />
Observaciones
</Tabs.Trigger>
<Tabs.Trigger value="items" class="whitespace-nowrap">
<DollarSign size={16} class="mr-2" />
Partidas
</Tabs.Trigger>
<Tabs.Trigger value="others" class="whitespace-nowrap">
<Truck size={16} class="mr-2" />
Otros
</Tabs.Trigger>
<Tabs.Trigger value="continuation" class="whitespace-nowrap">
<Package size={16} class="mr-2" />
Cont.
</Tabs.Trigger>
<Tabs.Trigger value="ssimp" class="whitespace-nowrap">
<Package size={16} class="mr-2" />
Continuación
</Tabs.Trigger>
</Tabs.List>
</div>
{/if}
<div class="flex justify-end gap-3">
<Button variant="outline" onclick={resetForms} disabled={isSaving || !selectedInvoiceType}>
Restablecer
</Button>
<Button onclick={handleSaveSettings} disabled={isSaving || !selectedInvoiceType}>
{#if isSaving}
<LoaderCircle class="mr-2 h-4 w-4 animate-spin" />
Guardando...
{:else}
<Save class="mr-2 h-4 w-4" />
Guardar Configuración
{/if}
</Button>
</div>
</div>
</div>
</Tabs.Root>

View File

@@ -1,35 +1,23 @@
<script lang="ts">
import { appSettingsApi } from '$lib/api/dashboard/a76/app-settings';
import { toast } from 'svelte-sonner';
import {
Settings2, Save, RefreshCw, Layers,
Database, Globe, Search, Info, HelpCircle,
ArrowRight
} from 'lucide-svelte';
import { fade, slide, fly } from 'svelte/transition';
import { authStore } from '$lib/auth';
import { Settings2, Save, RefreshCw } from 'lucide-svelte';
import { companyStore } from '$lib/stores/company.svelte';
// Componentes UI
import * as Card from '$lib/components/ui/card';
import { Button } from '$lib/components/ui/button';
import { Input } from '$lib/components/ui/input';
import { Label } from '$lib/components/ui/label';
// Custom Components
import SettingHierarchyBadge from '$lib/components/dashboard/settings/SettingHierarchyBadge.svelte';
import SsisGenTabsForm from '$lib/components/dashboard/settings/SsisGenTabsForm.svelte';
import { currentUser } from '$lib/auth';
let tenantIdVal = $derived(companyStore.activeCompany?.tenant_id || 0);
let companyIdVal = $derived(companyStore.activeCompany?.id || 0);
let level = $state<'global' | 'tenant' | 'company'>('company');
let activeCategory = $state('ssisgen');
let resolvedSettings = $state<any>(null);
let loading = $state(true); // Start as true to show loading initially
let loading = $state(true);
let saving = $state(false);
// Form internal state tracking
@@ -37,13 +25,12 @@
// Load when company changes or on mount
$effect(() => {
const companyId = companyIdVal; // Track dependency
const tenantId = tenantIdVal; // Track dependency
const companyId = companyIdVal;
const tenantId = tenantIdVal;
if (companyId && tenantId) {
handleResolve();
} else {
// If no company selected, still show loading state until we have context
loading = true;
resolvedSettings = null;
}
@@ -101,66 +88,53 @@
<title>Configuración General | Anexo 76</title>
</svelte:head>
<div class="flex flex-col h-[calc(100vh-64px)] overflow-hidden bg-[#050505] text-white">
<!-- Main Header -->
<header class="h-20 shrink-0 px-8 border-b border-white/5 bg-black/40 backdrop-blur-md flex items-center justify-between z-10">
<div class="flex items-center gap-4">
<div class="p-2.5 bg-primary/20 rounded-xl border border-primary/20 shadow-lg shadow-primary/5">
<Settings2 class="w-6 h-6 text-primary" />
</div>
<div class="flex flex-col">
<h1 class="text-xl font-bold tracking-tight">
Configuraciones Generales
</h1>
<div class="container mx-auto py-6 pb-32">
<div class="mb-6 flex items-center justify-between">
<div>
<h1 class="text-2xl font-bold tracking-tight">Configuraciones Generales</h1>
<p class="text-muted-foreground">
Configura los parámetros del sistema (SSisGen).
</p>
</div>
</div>
{#if loading && !resolvedSettings}
<div class="flex flex-col items-center justify-center py-12 gap-4">
<RefreshCw class="w-8 h-8 animate-spin text-primary" />
<p class="text-muted-foreground">Cargando configuraciones...</p>
</div>
{:else}
<div class="grid gap-6">
<div class="bg-background rounded-lg border p-4">
<SsisGenTabsForm
currentData={currentFormData}
onUpdate={handleFormUpdate}
/>
</div>
</div>
{/if}
</div>
<div class="flex items-center gap-4">
<!-- Sticky Footer -->
<div class="fixed bottom-0 left-0 right-0 bg-background/95 backdrop-blur border-t shadow-lg z-10 p-4 transition-all duration-300 group-has-data-[state=collapsed]/sidebar-wrapper:ml-[calc(var(--sidebar-width-icon))] ml-[calc(var(--sidebar-width))]">
<div class="container mx-auto max-w-[1400px] flex justify-end gap-3 pointer-events-none">
<div class="pointer-events-auto flex items-center gap-4">
{#if loading}
<div class="flex items-center gap-2 text-xs text-white/40 bg-white/5 px-3 py-1.5 rounded-lg border border-white/5">
<RefreshCw class="w-3 h-3 animate-spin" />
<div class="text-sm text-muted-foreground flex items-center gap-2">
<RefreshCw class="w-4 h-4 animate-spin" />
Cargando...
</div>
{/if}
<Button variant="default" onclick={handleSave} disabled={saving || loading} class="h-11 px-6 bg-primary hover:bg-primary/90 text-white shadow-xl shadow-primary/20 font-bold">
<Button onclick={handleSave} disabled={saving || loading}>
{#if saving}
<RefreshCw class="w-4 h-4 mr-2 animate-spin" />
<RefreshCw class="mr-2 h-4 w-4 animate-spin" />
Guardando...
{:else}
<Save class="w-4 h-4 mr-2" />
Guardar Cambios
<Save class="mr-2 h-4 w-4" />
Guardar Configuración
{/if}
</Button>
</div>
</header>
<!-- Workspace Area -->
<main class="flex-1 overflow-hidden p-6 bg-gradient-to-b from-black/20 to-transparent">
<div class="h-full flex flex-col max-w-[1600px] mx-auto w-full relative">
<!-- Form Background Glow -->
<div class="absolute -top-[10%] -left-[10%] w-[40%] h-[40%] bg-primary/5 blur-[120px] rounded-full pointer-events-none"></div>
<div class="absolute -bottom-[10%] -right-[10%] w-[40%] h-[40%] bg-purple-500/5 blur-[120px] rounded-full pointer-events-none"></div>
{#if loading && !resolvedSettings}
<div class="flex-1 flex flex-col items-center justify-center gap-4">
<div class="p-4 bg-white/5 rounded-2xl border border-white/10">
<RefreshCw class="w-10 h-10 animate-spin text-primary" />
</div>
<p class="text-xs font-bold uppercase tracking-[0.2em] text-white/20">Inicializando Parámetros</p>
</div>
{:else}
<div class="flex-1 h-full shadow-2xl">
<SsisGenTabsForm
currentData={currentFormData}
onUpdate={handleFormUpdate}
/>
</div>
{/if}
</div>
</main>
</div>
</div>
<style>
:global(body) { overflow: hidden; }
</style>