Todos los parametros de SCAI montadas y con su sistema CRUD
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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">
|
||||
|
||||
@@ -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>('');
|
||||
|
||||
@@ -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('');
|
||||
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user