diff --git a/backend/api/v1/modules/a76/clients_and_providers/dto.py b/backend/api/v1/modules/a76/clients_and_providers/dto.py index 624c99f1..292d9e41 100644 --- a/backend/api/v1/modules/a76/clients_and_providers/dto.py +++ b/backend/api/v1/modules/a76/clients_and_providers/dto.py @@ -46,7 +46,7 @@ class ClientProviderProgramsDTO(BaseModel): program_number: Optional[str] = Field( None, max_length=40, description="Program number" ) - prosec: Optional[int] = Field(None, description="PROSEC") + prosec: Optional[str] = Field(None, max_length=8, description="PROSEC") prosec_authorization: Optional[str] = Field( None, max_length=20, description="PROSEC authorization" ) diff --git a/backend/api/v1/modules/a76/clients_and_providers/models.py b/backend/api/v1/modules/a76/clients_and_providers/models.py index 4cf08fe0..db5544ca 100644 --- a/backend/api/v1/modules/a76/clients_and_providers/models.py +++ b/backend/api/v1/modules/a76/clients_and_providers/models.py @@ -136,7 +136,7 @@ class ClientProviderPrograms(Base, TenantScopedMixin, TimestampMixin): # Program information program: Mapped[Optional[str]] = mapped_column(String(7)) program_number: Mapped[Optional[str]] = mapped_column(String(40)) - prosec: Mapped[Optional[int]] = mapped_column(SmallInteger) + prosec: Mapped[Optional[str]] = mapped_column(String(8)) prosec_authorization: Mapped[Optional[str]] = mapped_column(String(20)) secon_auth_date: Mapped[Optional[int]] = mapped_column(Integer) manufacturer_id: Mapped[Optional[str]] = mapped_column(String(25)) diff --git a/frontend/src/lib/components/dashboard/shared/modals/sector-selector-dialog.svelte b/frontend/src/lib/components/dashboard/shared/modals/sector-selector-dialog.svelte new file mode 100644 index 00000000..dffe17af --- /dev/null +++ b/frontend/src/lib/components/dashboard/shared/modals/sector-selector-dialog.svelte @@ -0,0 +1,226 @@ + + + + + + Seleccionar Sector PROSEC + + Seleccione el sector del catálogo. Escrolea para ver más. + + + + + + + + + + {#if loading && items.length === 0} + + + Cargando catálogo... + + {:else if items.length === 0} + + No se encontraron sectores. + + {:else} + + + + Clave + Descripción + Autorizado + + + + {#each items as item} + handleSelect(item)} + > + + + + + {item.key} + + + + + {item.description} + + + + {item.authorized ? 'Sí' : 'No'} + + + + {/each} + + + + + {#if loadingMore} + + {/if} + + {/if} + + + + + {items.length} de {totalItems} registros + + (open = false)}>Cancelar + + + diff --git a/frontend/src/lib/components/dashboard/shared/modals/state-selector-dialog.svelte b/frontend/src/lib/components/dashboard/shared/modals/state-selector-dialog.svelte new file mode 100644 index 00000000..eb6f9c4c --- /dev/null +++ b/frontend/src/lib/components/dashboard/shared/modals/state-selector-dialog.svelte @@ -0,0 +1,224 @@ + + + + + + Seleccionar Estado + + Seleccione el estado del catálogo. Escrolea para ver más. + + + + + + + + + + {#if loading && items.length === 0} + + + Cargando catálogo... + + {:else if items.length === 0} + + No se encontraron estados. + + {:else} + + + + Clave M3 + Descripción + MEX + + + + {#each items as item} + handleSelect(item)} + > + + + + + {item.m3_key} + + + + + {item.description} + + + {item.mex_key || '-'} + + + {/each} + + + + + {#if loadingMore} + + {/if} + + {/if} + + + + + {items.length} de {totalItems} registros + + (open = false)}>Cancelar + + + diff --git a/frontend/src/routes/dashboard/clients_and_providers/edit/[[id]]/+page.svelte b/frontend/src/routes/dashboard/clients_and_providers/edit/[[id]]/+page.svelte index 8f5bbad8..991a2507 100644 --- a/frontend/src/routes/dashboard/clients_and_providers/edit/[[id]]/+page.svelte +++ b/frontend/src/routes/dashboard/clients_and_providers/edit/[[id]]/+page.svelte @@ -22,10 +22,29 @@ FileText, Settings, User, - Trash2 + Trash2, + Search, + Globe, + MapPin as MapPinIcon, + Factory, + Calendar, + Hash, + ShieldCheck, + Award, + Fingerprint, + Briefcase } from 'lucide-svelte'; import { toast } from 'svelte-sonner'; + // Componentes Compartidos (Modales) + import CountrySelectorDialog from '$lib/components/dashboard/goods/modales/country-selector-dialog.svelte'; + import StateSelectorDialog from '$lib/components/dashboard/shared/modals/state-selector-dialog.svelte'; + import SectorSelectorDialog from '$lib/components/dashboard/shared/modals/sector-selector-dialog.svelte'; + + import { type Country } from '$lib/api/dashboard/reference_data/countries'; + import { type State } from '$lib/api/dashboard/reference_data/states'; + import { type Sector } from '$lib/api/dashboard/reference_data/sectors'; + // API & Stores import { clientsProvidersApi } from '$lib/api/dashboard/a76/clients-providers'; import { companyStore } from '$lib/stores/company.svelte'; @@ -73,17 +92,30 @@ program: '', program_number: '', authorization_date_str: '', // String para input date - prosec: 0, + prosec: '', manufacturer_id: '', tax_id: '', ctpat_svi: '', - is_certified_company: '0' + is_certified_company: false }); let formData = $state(getEmptyForm()); let loading = $state(false); let error = $state(null); + // --- ESTADO PARA MODALES --- + let countryModalOpen = $state(false); + let stateModalOpen = $state(false); + let sectorModalOpen = $state(false); + + const scaiiPrograms = [ + { value: 'IMMEX', label: 'IMMEX' }, + { value: 'PROSEC', label: 'PROSEC' }, + { value: 'ALTEX', label: 'ALTEX' }, + { value: 'ECEX', label: 'ECEX' }, + { value: 'DRAWBACK', label: 'DRAWBACK' } + ]; + // --- UTILIDADES --- const intDateToString = (d?: number | null) => d @@ -138,11 +170,11 @@ program: prog.program || '', program_number: prog.program_number || '', authorization_date_str: intDateToString(prog.secon_auth_date), - prosec: prog.prosec || 0, + prosec: prog.prosec ? String(prog.prosec) : '', manufacturer_id: prog.manufacturer_id || '', tax_id: prog.tax_id || '', ctpat_svi: prog.ctpat_svi || '', - is_certified_company: prog.is_certified_company || '0' + is_certified_company: prog.is_certified_company === '1' }; } } catch (e: any) { @@ -202,11 +234,11 @@ program: clean(formData.program), program_number: clean(formData.program_number), secon_auth_date: stringDateToInt(formData.authorization_date_str), - prosec: Number(formData.prosec) || null, + prosec: clean(formData.prosec), manufacturer_id: clean(formData.manufacturer_id), tax_id: clean(formData.tax_id), ctpat_svi: clean(formData.ctpat_svi), - is_certified_company: clean(formData.is_certified_company) + is_certified_company: formData.is_certified_company ? '1' : '0' } }; @@ -470,17 +502,44 @@ Estado - + + + (stateModalOpen = true)} + disabled={loading} + title="Buscar Estado" + > + + + País (ISO) - + + + (countryModalOpen = true)} + disabled={loading} + title="Buscar País" + > + + + @@ -509,77 +568,160 @@ >Información sobre IMMEX, PROSEC y otras certificaciones. - - - - Programa - + + + + + + Programas de Fomento - - Número de Programa - + + + + + + Programa + + (formData.program = v)} + disabled={loading} + > + + {formData.program || 'Selecciona un programa'} + + + {#each scaiiPrograms as prog} + + {prog.label} + + {/each} + + + + + + + Número de Programa + + + + + + + Fecha Autorización + + + + + + + PROSEC (Sector) + + + + (sectorModalOpen = true)} + disabled={loading} + title="Buscar Sector" + > + + + + - - - Fecha Autorización - + + + + + Identificación Industrial - - Tax ID (Extranjero) - - - - Manufacturer ID - + + + + + + Tax ID (Extranjero) + + + + + + + Manufacturer ID (MID) + + + - - - C-TPAT / SVI - + + + + + Certificaciones y Seguridad - - PROSEC (Sector) - + + + + + + C-TPAT / SVI + + + + + + + Empresa Certificada + + Indica si cuenta con certificación de empresa + + + @@ -670,3 +812,24 @@ + + + (formData.country = country.m3_key)} +/> + + { + formData.state = state.description; + if (state.m3_key && !formData.country) { + formData.country = state.m3_key; + } + }} +/> + + (formData.prosec = sector.key)} +/>
Cargando catálogo...
No se encontraron sectores.
No se encontraron estados.
+ Indica si cuenta con certificación de empresa +