{#if client.client_or_provider === 'client'}
diff --git a/frontend/src/lib/components/dashboard/goods/parts/TextileProviderSelectorDialog.svelte b/frontend/src/lib/components/dashboard/goods/parts/TextileProviderSelectorDialog.svelte
index 1c8858c2..fda33ec6 100644
--- a/frontend/src/lib/components/dashboard/goods/parts/TextileProviderSelectorDialog.svelte
+++ b/frontend/src/lib/components/dashboard/goods/parts/TextileProviderSelectorDialog.svelte
@@ -29,7 +29,8 @@
(p) =>
(p.client_or_provider === 'provider' || p.client_or_provider === 'both') &&
(p.name.toLowerCase().includes(searchTerm.toLowerCase()) ||
- p.rfc.toLowerCase().includes(searchTerm.toLowerCase()) ||
+ (p.rfc ?? '').toLowerCase().includes(searchTerm.toLowerCase()) ||
+ (p.tax_id ?? '').toLowerCase().includes(searchTerm.toLowerCase()) ||
p.id.toString().includes(searchTerm))
)
);
@@ -101,7 +102,7 @@
| ID |
- RFC |
+ RFC / TAX-ID |
Nombre |
@@ -112,7 +113,7 @@
onclick={() => handleSelect(provider)}
>
{provider.id} |
-
{provider.rfc} |
+
{provider.rfc || provider.tax_id || '—'} |
diff --git a/frontend/src/lib/components/dashboard/goods/parts/create-edit-dialog.svelte b/frontend/src/lib/components/dashboard/goods/parts/create-edit-dialog.svelte
index 8ef08685..748c64aa 100644
--- a/frontend/src/lib/components/dashboard/goods/parts/create-edit-dialog.svelte
+++ b/frontend/src/lib/components/dashboard/goods/parts/create-edit-dialog.svelte
@@ -7,7 +7,7 @@
import * as Select from "$lib/components/ui/select";
import { classesApi, type A76Class, type A76ClassCreate, type A76ClassUpdate } from "$lib/api/dashboard/a76/classes";
import { materialTypesApi, type MaterialType } from "$lib/api/dashboard/reference_data/material_types";
- import { clientsProvidersApi, type ClientProviderBasic } from "$lib/api/dashboard/a76/clients-providers";
+ import { clientsProvidersApi, type ClientProvider } from "$lib/api/dashboard/a76/clients-providers";
import { companyStore } from "$lib/stores/company.svelte";
import { onMount } from 'svelte';
@@ -44,7 +44,7 @@
let error = $state(null);
let materialTypes = $state([]);
let loadingMaterialTypes = $state(false);
- let clients = $state([]);
+ let clients = $state([]);
let loadingClients = $state(false);
// Variables para controlar los selects
@@ -320,7 +320,7 @@
{#each clients as client}
{/each}
diff --git a/frontend/src/lib/components/dashboard/goods/parts/partForm.svelte b/frontend/src/lib/components/dashboard/goods/parts/partForm.svelte
index 3deb0c4a..dc71547a 100644
--- a/frontend/src/lib/components/dashboard/goods/parts/partForm.svelte
+++ b/frontend/src/lib/components/dashboard/goods/parts/partForm.svelte
@@ -846,7 +846,8 @@
}
function handleTextileProviderSelect(provider: any) {
- formData.supplier = provider.rfc;
+ // Identificador fiscal efectivo del proveedor (RFC nacional o TAX-ID extranjero)
+ formData.supplier = provider.rfc || provider.tax_id || '';
}
function handleSectorSelect(item: Sector) {
diff --git a/frontend/src/routes/dashboard/clients_and_providers/+page.svelte b/frontend/src/routes/dashboard/clients_and_providers/+page.svelte
index 5976c7c8..add0f341 100644
--- a/frontend/src/routes/dashboard/clients_and_providers/+page.svelte
+++ b/frontend/src/routes/dashboard/clients_and_providers/+page.svelte
@@ -62,6 +62,7 @@
// Filter state
let searchName = $state('');
let searchRfc = $state('');
+ let searchTaxId = $state('');
let searchType = $state($page.url.searchParams.get('type') || 'both');
let searchTimeout: ReturnType;
let hasMounted = false;
@@ -100,6 +101,7 @@
const type = searchType;
const name = searchName;
const rfc = searchRfc;
+ const taxId = searchTaxId;
if (!browser || !hasMounted) return;
clearTimeout(searchTimeout);
@@ -145,6 +147,7 @@
// Ideally backend should handle this. I will assume backend filters for now or add query params.
if (searchName) filters.name = searchName;
if (searchRfc) filters.rfc = searchRfc;
+ if (searchTaxId) filters.tax_id = searchTaxId;
const response = await clientsProvidersApi.list(companyId, pageToLoad, pageSize, filters);
@@ -193,12 +196,6 @@
goto(`/dashboard/clients_and_providers/edit/${item.id}`);
}
- function taxIdOrRfcLabel(cp: ClientProvider | null): string {
- if (!cp) return 'RFC';
- const proc = (cp.type_nat_foreign || 'N').toUpperCase();
- return proc === 'E' ? 'TAX-ID' : 'RFC';
- }
-
function handleEdit() {
if (!canEditPartner) {
toast.error('No tienes permiso para editar clientes o proveedores');
@@ -279,7 +276,7 @@
{t('Filtros', 'Filters')}
{t('Busque por nombre, RFC/TAX-ID o tipo', 'Search by name, RFC/TAX-ID or type')}
-
+
-
+
+
+
+
+
@@ -342,7 +347,8 @@
| # |
- RFC / TAX-ID |
+ RFC |
+ TAX-ID |
Nombre |
Tipo |
Estatus |
@@ -351,12 +357,12 @@
{#if isLoading && allItems.length === 0}
| {t('Cargando...', 'Loading...')} | {t('Cargando...', 'Loading...')} |
{:else if allItems.length === 0}
| {t('No se encontraron registros', 'No records found')} |
@@ -371,7 +377,8 @@
ondblclick={() => handleRowDoubleClick(item)}
>
{item.id} |
- {item.rfc} |
+ {item.rfc || '—'} |
+ {item.tax_id || '—'} |
{item.name} |
0}
- |
+ |
{#if isLoading}
{t('Cargando más registros...', 'Loading more records...')}
@@ -433,9 +440,19 @@
>
{selectedItem?.name || '---'}
-
- {taxIdOrRfcLabel(selectedItem)}:
- {selectedItem?.rfc || ''}
+
+ {#if selectedItem?.rfc}
+
+ RFC:
+ {selectedItem.rfc}
+
+ {/if}
+ {#if selectedItem?.tax_id}
+
+ TAX-ID:
+ {selectedItem.tax_id}
+
+ {/if}
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 27af838d..61d4d2bd 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
@@ -84,6 +84,7 @@
// --- ESTADO INICIAL (PLANO) ---
const getEmptyForm = () => ({
rfc: '',
+ tax_id: '',
name: '',
short_name: '',
curp: '',
@@ -162,6 +163,7 @@
// Mapear respuesta anidada -> formulario plano
formData = {
rfc: item.rfc || '',
+ tax_id: item.tax_id || '',
name: item.name || '',
short_name: item.short_name || '',
curp: item.curp || '',
@@ -217,26 +219,38 @@
toast.error(error);
return;
}
- if (!formData.rfc.trim() || !formData.name.trim()) {
- error = t('Identificador fiscal (RFC/TAX-ID) y Nombre son obligatorios', 'Tax Identifier (RFC/TAX-ID) and Name are required');
+ if (!formData.name.trim()) {
+ error = t('El Nombre es obligatorio', 'Name is required');
toast.error(error);
return;
}
const rfcVal = formData.rfc.trim();
+ const taxIdVal = formData.tax_id.trim();
const isForeign = (formData.type_nat_foreign || 'N').toUpperCase() === 'E';
- if (isForeign) {
- if (!TAX_ID_REGEX.test(rfcVal)) {
- error = 'El TAX-ID debe tener formato: 2 dígitos, guión y resto (ej. 12-3456789). Máx 30 caracteres.';
- toast.error(error);
- return;
- }
- } else {
- if (!RFC_REGEX.test(rfcVal)) {
- error = 'El RFC no tiene el formato correcto. Ejemplo: XAXX010101000.';
- toast.error(error);
- return;
- }
+
+ // Requerido según procedencia: Extranjero ⇒ TAX-ID, Nacional ⇒ RFC
+ if (isForeign && !taxIdVal) {
+ error = t('El TAX-ID es obligatorio para registros extranjeros', 'TAX-ID is required for foreign records');
+ toast.error(error);
+ return;
+ }
+ if (!isForeign && !rfcVal) {
+ error = t('El RFC es obligatorio para registros nacionales', 'RFC is required for national records');
+ toast.error(error);
+ return;
+ }
+
+ // Formato: cada identificador valida solo si tiene valor (ambos pueden coexistir)
+ if (rfcVal && !RFC_REGEX.test(rfcVal)) {
+ error = 'El RFC no tiene el formato correcto. Ejemplo: XAXX010101000.';
+ toast.error(error);
+ return;
+ }
+ if (taxIdVal && !TAX_ID_REGEX.test(taxIdVal)) {
+ error = 'El TAX-ID debe tener formato: 2 dígitos, guión y resto (ej. 12-3456789). Máx 30 caracteres.';
+ toast.error(error);
+ return;
}
loading = true;
@@ -246,6 +260,7 @@
// Reconstruir objeto anidado para el backend
const payload = {
rfc: clean(formData.rfc),
+ tax_id: clean(formData.tax_id),
name: clean(formData.name),
short_name: clean(formData.short_name),
curp: clean(formData.curp),
@@ -374,13 +389,27 @@
>
- | | |