diff --git a/backend/alembic/versions/b2c3d4e5f6a7_drop_client_id_from_parts.py b/backend/alembic/versions/b2c3d4e5f6a7_drop_client_id_from_parts.py new file mode 100644 index 00000000..172e2e19 --- /dev/null +++ b/backend/alembic/versions/b2c3d4e5f6a7_drop_client_id_from_parts.py @@ -0,0 +1,28 @@ +"""drop client_id column from parts + +Revision ID: b2c3d4e5f6a7 +Revises: a1b2c3d4e5f6 +Create Date: 2026-04-28 11:50:00.000000 +""" + +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision = "b2c3d4e5f6a7" +down_revision = "a1b2c3d4e5f6" +branch_labels = None +depends_on = None + + +def upgrade() -> None: + op.drop_column("parts", "client_id", schema="a76") + + +def downgrade() -> None: + op.add_column( + "parts", + sa.Column("client_id", sa.Integer(), nullable=True), + schema="a76", + ) diff --git a/backend/api/v1/modules/a76/layouts_csv/parts/tasks.py b/backend/api/v1/modules/a76/layouts_csv/parts/tasks.py index 6c4cf830..1589e61c 100644 --- a/backend/api/v1/modules/a76/layouts_csv/parts/tasks.py +++ b/backend/api/v1/modules/a76/layouts_csv/parts/tasks.py @@ -325,7 +325,6 @@ def insert_valid_rows(self, job_id: str): new_part = Part( tenant_id=tenant_id, company_id=company_id, - client_id=company_id, **data, ) session.add(new_part) diff --git a/backend/api/v1/modules/a76/parts/dto.py b/backend/api/v1/modules/a76/parts/dto.py index a6815a01..9320e585 100644 --- a/backend/api/v1/modules/a76/parts/dto.py +++ b/backend/api/v1/modules/a76/parts/dto.py @@ -145,7 +145,6 @@ class InvDataDTO(BaseModel): class PartBase(BaseModel): - client_id: Optional[int] = None part_number: str = Field(..., max_length=70) commercial_part_number: Optional[str] = None @@ -186,7 +185,6 @@ class PartCreateDTO(PartBase): # --- ACTUALIZACIÓN --- class PartUpdateDTO(PartBase): - client_id: Optional[int] = None part_number: Optional[str] = None # Todo opcional para PATCH pass diff --git a/backend/api/v1/modules/a76/parts/models.py b/backend/api/v1/modules/a76/parts/models.py index 27ba357f..0f1e8c03 100644 --- a/backend/api/v1/modules/a76/parts/models.py +++ b/backend/api/v1/modules/a76/parts/models.py @@ -68,7 +68,6 @@ class Part(Base, TenantScopedMixin, TimestampMixin): ) id: Mapped[int] = mapped_column(Integer, primary_key=True) - client_id: Mapped[Optional[int]] = mapped_column(Integer, nullable=True) part_number: Mapped[str] = mapped_column(String(70)) commercial_part_number: Mapped[Optional[str]] = mapped_column(String(70)) diff --git a/frontend/src/lib/api/dashboard/a76/parts.ts b/frontend/src/lib/api/dashboard/a76/parts.ts index a0ef2c4f..5c4ab8a6 100644 --- a/frontend/src/lib/api/dashboard/a76/parts.ts +++ b/frontend/src/lib/api/dashboard/a76/parts.ts @@ -92,7 +92,6 @@ export interface Part { id: number; tenant_id: number; company_id: number; - client_id: number; // Identificación part_number: string; diff --git a/frontend/src/lib/components/dashboard/goods/parts/partForm.svelte b/frontend/src/lib/components/dashboard/goods/parts/partForm.svelte index 3c55e2c0..5cb464ad 100644 --- a/frontend/src/lib/components/dashboard/goods/parts/partForm.svelte +++ b/frontend/src/lib/components/dashboard/goods/parts/partForm.svelte @@ -26,7 +26,6 @@ Settings, Image as ImageIcon, FolderSearch, - UserCheck, CheckCircle2, XCircle, Tag, @@ -53,7 +52,6 @@ // Stores & APIs import { companyStore } from '$lib/stores/company.svelte'; import { partsApi } from '$lib/api/dashboard/a76/parts'; - import { clientsProvidersApi } from '$lib/api/dashboard/a76/clients-providers'; import { classesApi } from '$lib/api/dashboard/a76/classes'; import { materialTypesApi } from '$lib/api/dashboard/a76/material-types'; import { countriesApi } from '$lib/api/dashboard/reference_data/countries'; @@ -187,8 +185,6 @@ let showNonDischargeDialog = $state(false); // Descripciones Visuales - let selectedClientName = $state(''); - let selectedClientStatus = $state(true); let selectedClassDesc = $state(''); let selectedCurrencyName = $state(''); let selectedCountryName = $state(''); @@ -406,7 +402,6 @@ // Estado Formulario let formData = $state({ id: 0, - client_id: 0, part_number: '', assigned_client: '', description_spanish: '', @@ -525,7 +520,6 @@ const d = response.data; formData = { id: d.id, - client_id: d.client_id, part_number: d.part_number, description_spanish: d.description_spanish || '', description_english: d.description_english || '', @@ -648,7 +642,6 @@ if (d.currency_key === 'MXN') formData.currency_type = 'NA'; else formData.currency_type = 'EX'; - if (d.client_id) await fetchClientName(d.client_id, companyId); if (d.part_class) await fetchClassDesc(d.part_class, companyId); if (d.inv_data?.material_type) await fetchMaterialName(d.inv_data.material_type); await fetchSectorDesc(formData.sector); @@ -674,19 +667,6 @@ }); // --- HELPERS VISUALES --- - async function fetchClientName(clientId: number, companyId: number) { - try { - const res = await clientsProvidersApi.get(clientId, companyId); - const clientData = (res as any).data || res; - if (clientData) { - selectedClientName = clientData.name; - selectedClientStatus = clientData.is_active ?? true; - } - } catch (e) { - console.error('Error visual cliente', e); - } - } - async function fetchClassDesc(code: string, companyId: number) { try { const res = await classesApi.list({ company_id: companyId, class_code: code }); @@ -745,20 +725,6 @@ if (modalContext === 'non_discharge') { tempNonDischargeItem.client_id = client.id; tempNonDischargeItem.name = client.name; - } else { - formData.client_id = client.id; - selectedClientName = client.name; - selectedClientStatus = client.is_active ?? true; - - // Cambio reactivo: Si estamos en SCAI y seleccionamos un cliente, - // asumimos que el usuario quiere convertirlo a SCAF (Activo Fijo). - if (formType === 'inv') { - formType = 'fa'; - toast.info('Cambio de sistema detectado', { - description: - 'Se ha cambiado automáticamente a SCAF (Activo Fijo) al seleccionar un cliente.' - }); - } } modalContext = 'main'; } @@ -937,10 +903,6 @@ error = 'No hay una compañía activa seleccionada'; return; } - if (!formData.client_id && formType !== 'inv') { - error = 'Debe seleccionar un Cliente'; - return; - } if (!formData.unit_of_measure) { error = 'Debe seleccionar una Unidad de Medida'; return; @@ -973,9 +935,6 @@ commonData.scrap_export_fraction = normalizeMexTariffDigitsStored( commonData.scrap_export_fraction ); - if (commonData.client_id === 0) { - commonData.client_id = null; - } if (!commonData.currency_key || commonData.currency_key === 'USD') { commonData.currency_key = null; } @@ -1186,7 +1145,7 @@ class="animate-in fade-in space-y-8 pt-6 duration-300" >
-
+
@@ -1202,36 +1161,6 @@ />
-
- -
-
- - (showClientModal = true)} - onkeydown={(event) => - openOnEnterOrSpace(event, () => (showClientModal = true))} - tabindex="0" - class="cursor-pointer pl-9 transition-colors hover:bg-muted/50" - placeholder="Seleccione un cliente..." - /> -
- -
-
@@ -1666,7 +1595,7 @@ >
-
+
-
- -
-
- - (showClientModal = true)} - onkeydown={(event) => - openOnEnterOrSpace(event, () => (showClientModal = true))} - tabindex="0" - class="cursor-pointer pl-9 transition-colors hover:bg-muted/50" - placeholder="Asignar cliente..." - /> -
- -
-

- * Al asignar un cliente, se cambiará automáticamente a modo SCAF. -

-
diff --git a/frontend/src/routes/dashboard/goods/parts/+page.svelte b/frontend/src/routes/dashboard/goods/parts/+page.svelte index 075d76f1..01066b15 100644 --- a/frontend/src/routes/dashboard/goods/parts/+page.svelte +++ b/frontend/src/routes/dashboard/goods/parts/+page.svelte @@ -5,7 +5,6 @@ import { Plus, RefreshCw, Package } from 'lucide-svelte'; import { toast } from 'svelte-sonner'; import { partsApi, type Part } from '$lib/api/dashboard/a76/parts'; - import { clientsProvidersApi } from '$lib/api/dashboard/a76/clients-providers'; import { companyStore } from '$lib/stores/company.svelte'; import { useShortcuts } from '$lib/hooks/use-shortcuts'; import { goto } from '$app/navigation'; @@ -18,12 +17,10 @@ // Estado de la lista de partes let parts = $state([]); - let clientsMap = $state>({}); // Mapa ID -> Nombre let selectedPart = $state(null); let isLoading = $state(false); let searchPartNumber = $state(''); let searchDescription = $state(''); - let searchClient = $state(''); let searchClass = $state(''); let sorting = $state([ { id: 'updated_at', desc: true } @@ -39,7 +36,6 @@ const canCreate = $derived(userHasPermission($currentUser, 'goods_parts.create')); const canEdit = $derived(userHasPermission($currentUser, 'goods_parts.edit')); const canDelete = $derived(userHasPermission($currentUser, 'goods_parts.delete')); - const canViewClients = $derived(userHasPermission($currentUser, 'clients_providers.view')); const isError = $derived(!canView || status >= 400 || error); @@ -52,14 +48,9 @@ !searchDescription || (p.description_spanish?.toLowerCase().includes(searchDescription.toLowerCase()) ?? false) || (p.description_english?.toLowerCase().includes(searchDescription.toLowerCase()) ?? false); - const clientName = clientsMap[p.client_id] || ''; - const matchesClient = - !searchClient || - (p.client_id?.toString().includes(searchClient) ?? false) || - clientName.toLowerCase().includes(searchClient.toLowerCase()); const matchesClass = !searchClass || (p.part_class?.toLowerCase().includes(searchClass.toLowerCase()) ?? false); - return matchesPartNumber && matchesDescription && matchesClient && matchesClass; + return matchesPartNumber && matchesDescription && matchesClass; }) ); @@ -94,27 +85,7 @@ async function loadData() { if (!canView) return; - await Promise.all([loadParts(), loadClients()]); - } - - async function loadClients() { - if (!canViewClients) return; - const companyId = companyStore.activeCompany?.id; - if (!companyId) return; - - try { - const response = await clientsProvidersApi.list(companyId, 1, 1000); - const data = (response as any).data || response; - const items = data.items || []; - - const map: Record = {}; - items.forEach((c: any) => { - map[c.id] = c.name; - }); - clientsMap = map; - } catch (e) { - console.error('Error cargando clientes:', e); - } + await loadParts(); } async function loadParts() { @@ -233,7 +204,7 @@ Filtra las partes por diferentes criterios (los filtros se aplican automáticamente)
-
+
-
- - -
@@ -343,16 +310,7 @@
-
-
- -
- - {clientsMap[selectedPart.client_id] || 'Sin cliente'} -
-
+
{selectedPart.part_class || '-'}