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 +
+ +
+
+
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 +
+ +
+
+
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 @@
- +
+ + +
- +
+ + +
@@ -509,77 +568,160 @@ >Información sobre IMMEX, PROSEC y otras certificaciones. - -
-
- - + + +
+
+ + Programas de Fomento
-
- - + +
+
+ + (formData.program = v)} + disabled={loading} + > + + {formData.program || 'Selecciona un programa'} + + + {#each scaiiPrograms as prog} + + {prog.label} + + {/each} + + +
+
+ + +
+
+ + +
+
+ +
+ + +
+
-
-
- - + +
+
+ + Identificación Industrial
-
- - -
-
- - + +
+
+ + +
+
+ + +
-
-
- - + +
+
+ + Certificaciones y Seguridad
-
- - + +
+
+ + +
+
+ +
+ +

+ 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)} +/>