From ae1d7f0c5897cda2e1654c4b12929d842db4e73a Mon Sep 17 00:00:00 2001 From: Kevin_Ramirez Date: Wed, 14 Jan 2026 12:47:01 -0600 Subject: [PATCH] Se mejoro el disenio de agentes y clientes-proveedores --- docker-compose.yml | 85 ++- .../lib/api/dashboard/a76/customs-brokers.ts | 39 +- .../modales/country-selector-dialog.svelte | 36 +- .../dashboard/goods/parts/partForm.svelte | 620 ++++++++++-------- .../clients_and_providers/+page.svelte | 533 +++++++++------ .../edit/[[id]]/+page.svelte | 212 +++--- .../dashboard/customs_brokers/+page.svelte | 521 ++++++++------- .../customs_brokers/edit/[[id]]/+page.svelte | 344 +++++----- 8 files changed, 1362 insertions(+), 1028 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index c3425493..c26575a5 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -17,7 +17,7 @@ services: - backend-net restart: unless-stopped healthcheck: - test: ["CMD-SHELL", "pg_isready -U postgres -d anexo76_core || exit 1"] + test: [ "CMD-SHELL", "pg_isready -U postgres -d anexo76_core || exit 1" ] interval: 5s timeout: 3s retries: 10 @@ -54,7 +54,7 @@ services: - backend-net restart: unless-stopped healthcheck: - test: ["CMD-SHELL", "pg_isready -U postgres -d keycloak || exit 1"] + test: [ "CMD-SHELL", "pg_isready -U postgres -d keycloak || exit 1" ] interval: 5s timeout: 3s retries: 10 @@ -97,7 +97,7 @@ services: KC_HOSTNAME_PATH: /kcauth KC_LOG_LEVEL: INFO JAVA_OPTS_APPEND: "-Xms256m -Xmx512m -XX:MetaspaceSize=96M -XX:MaxMetaspaceSize=256m -Djava.net.preferIPv4Stack=true" - command: + command: - start-dev - --http-relative-path=/kcauth - --db=postgres @@ -122,7 +122,19 @@ services: - backend-net restart: unless-stopped healthcheck: - test: ["CMD-SHELL", "exec 3<>/dev/tcp/127.0.0.1/9000; echo -e 'GET /kcauth/health/ready HTTP/1.1\r\nhost: 127.0.0.1\r\nConnection: close\r\n\r\n' >&3; grep -q 'HTTP/1.1 200' <&3 || exit 1"] + test: + [ + "CMD-SHELL", + "exec 3<>/dev/tcp/127.0.0.1/9000; echo -e 'GET /kcauth/health/ready HTTP/1.1\r + + host: 127.0.0.1\r + + Connection: close\r + + \r + + ' >&3; grep -q 'HTTP/1.1 200' <&3 || exit 1" + ] interval: 10s timeout: 5s retries: 30 @@ -178,10 +190,10 @@ services: - backend-net - frontend-net restart: unless-stopped - entrypoint: ["/entrypoint.sh"] - command: ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000", "--reload", "--log-level", "info"] + entrypoint: [ "/entrypoint.sh" ] + command: [ "uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000", "--reload", "--log-level", "info" ] healthcheck: - test: ["CMD-SHELL", "curl -f http://localhost:8000/api/health || exit 1"] + test: [ "CMD-SHELL", "curl -f http://localhost:8000/api/health || exit 1" ] interval: 15s timeout: 5s retries: 5 @@ -223,7 +235,7 @@ services: depends_on: backend: condition: service_healthy - entrypoint: ["/frontend-entrypoint.sh"] + entrypoint: [ "/frontend-entrypoint.sh" ] volumes: - ./frontend:/app - frontend_node_modules:/app/node_modules @@ -232,9 +244,9 @@ services: - frontend-net - auth-net restart: unless-stopped - command: ["pnpm", "run", "dev", "--", "--host", "0.0.0.0"] + command: [ "pnpm", "run", "dev", "--", "--host", "0.0.0.0" ] healthcheck: - test: ["CMD-SHELL", "wget --no-verbose --tries=1 --spider http://localhost:5173/ || exit 1"] + test: [ "CMD-SHELL", "wget --no-verbose --tries=1 --spider http://localhost:5173/ || exit 1" ] interval: 15s timeout: 5s retries: 5 @@ -250,40 +262,27 @@ services: memory: 1G reservations: memory: 512M -# celery + # celery celery_worker: - build: ./backend - container_name: a76_worker - command: celery -A core.celery_app worker --loglevel=info - environment: - - VALKEY_URL=redis://valkey:6379/0 - depends_on: - - backend - - valkey - networks: - - backend-net - - valkey: - image: valkey/valkey:7.2 - container_name: a76_valkey - restart: always - ports: - - "6379:6379" - networks: - - backend-net + build: ./backend + container_name: a76_worker + command: celery -A core.celery_app worker --loglevel=info + environment: + - VALKEY_URL=redis://valkey:6379/0 + depends_on: + - backend + - valkey + networks: + - backend-net - flower: - image: mher/flower - container_name: a76_flower - command: celery -A core.celery_app flower - ports: - - "5555:5555" - environment: - - CELERY_BROKER_URL=redis://valkey:6379/0 - depends_on: - - valkey - networks: - - backend-net + valkey: + image: valkey/valkey:7.2 + container_name: a76_valkey + restart: always + ports: + - "6379:6379" + networks: + - backend-net volumes: postgres_app_data: @@ -312,4 +311,4 @@ networks: driver: bridge ipam: config: - - subnet: 172.22.0.0/16 \ No newline at end of file + - subnet: 172.22.0.0/16 diff --git a/frontend/src/lib/api/dashboard/a76/customs-brokers.ts b/frontend/src/lib/api/dashboard/a76/customs-brokers.ts index a3faa96e..f90c3404 100644 --- a/frontend/src/lib/api/dashboard/a76/customs-brokers.ts +++ b/frontend/src/lib/api/dashboard/a76/customs-brokers.ts @@ -2,6 +2,7 @@ import { api } from '$lib/api'; import type { ApiResponse } from '$lib/api'; export interface CustomsBroker { + id: number; type?: string | null; broker_key: string; name?: string | null; @@ -19,28 +20,8 @@ export interface CustomsBroker { license: string; company?: string | null; contact?: string | null; - tenant_id: string; + tenant_id?: string; company_id: string; - id: number; - type?: string | null; - broker_key: string; - name?: string | null; - address?: string | null; - postal_code?: string | null; - city?: string | null; - state?: string | null; - phone?: string | null; - fax?: string | null; - email?: string | null; - country?: string | null; - tax_id?: string | null; - personal_id?: string | null; - position?: string | null; - license: string; - company?: string | null; - contact?: string | null; - tenant_id: string; - company_id: string; } export interface CustomsBrokerVU { @@ -112,7 +93,7 @@ export const customsBrokersApi = { get: (brokerKey: string, companyId: string) => { return api.get(`/v1/a76/customs-brokers/${brokerKey}?company_id=${companyId}`); }, - + create: (data: CreateCustomsBrokerData, companyId: string) => { return api.post(`/v1/a76/customs-brokers/?company_id=${companyId}`, data); }, @@ -124,20 +105,6 @@ export const customsBrokersApi = { delete: (brokerKey: string, companyId: string) => { return api.delete(`/v1/a76/customs-brokers/${brokerKey}?company_id=${companyId}`); }, - /** - * Elimina un agente aduanal - */ - delete: (brokerKey: string, companyId: string) => { - return api.delete(`/v1/a76/customs-brokers/${brokerKey}/?company_id=${companyId}`); - }, - - /** - * Actualiza la información de un agente aduanal - */ - update: (brokerKey: string, data: CreateCustomsBrokerData) => { - const companyId = data.company_id; - return api.put(`/v1/a76/customs-brokers/${brokerKey}/?company_id=${companyId}`, data); - }, updateVU: (brokerKey: string, data: CustomsBrokerVU, companyId: string) => { return api.put(`/v1/a76/customs-broker-vu/${brokerKey}?company_id=${companyId}`, data); diff --git a/frontend/src/lib/components/dashboard/goods/modales/country-selector-dialog.svelte b/frontend/src/lib/components/dashboard/goods/modales/country-selector-dialog.svelte index 0eb36ab2..27cea07f 100644 --- a/frontend/src/lib/components/dashboard/goods/modales/country-selector-dialog.svelte +++ b/frontend/src/lib/components/dashboard/goods/modales/country-selector-dialog.svelte @@ -33,22 +33,50 @@ // Cargar datos al abrir $effect(() => { - if (open && !loaded) { + if (open) { loadCountries(); } }); async function loadCountries() { loading = true; + console.log("Cargando países..."); try { const response = await countriesApi.list(1, 300); + console.log("Respuesta países FULL:", response); - if (response.data?.items) { + // Caso 1: Estructura esperada { data: { items: [...] } } + if (response.data?.items && Array.isArray(response.data.items)) { items = response.data.items; loaded = true; - } else { - console.warn("No se encontraron países:", response); + } + // Caso 2: El backend devuelve el array directamente en data { data: [...] } + else if (Array.isArray(response.data)) { + items = response.data; + loaded = true; } + // Caso 3: La respuesta en sí es el array (poco probable con el wrapper actual pero posible si algo falla antes) + else if (Array.isArray(response)) { + items = response; + loaded = true; + } + // Caso 4: data es el objeto paginado pero sin la propiedad items correcta o vacía + else if (response.data && typeof response.data === 'object') { + // Intentar buscar alguna propiedad que sea array + const possibleArray = Object.values(response.data).find(val => Array.isArray(val)); + if (possibleArray) { + items = possibleArray as Country[]; + loaded = true; + } else { + console.warn("Estructura de datos no reconocida en countriesApi.list:", response.data); + } + } + else { + console.warn("No se encontraron países o formato incorrecto:", response); + } + + console.log(`Países cargados: ${items.length}`); + } catch (e) { console.error("Error cargando países:", e); } finally { diff --git a/frontend/src/lib/components/dashboard/goods/parts/partForm.svelte b/frontend/src/lib/components/dashboard/goods/parts/partForm.svelte index 185623d6..f88b9461 100644 --- a/frontend/src/lib/components/dashboard/goods/parts/partForm.svelte +++ b/frontend/src/lib/components/dashboard/goods/parts/partForm.svelte @@ -17,7 +17,7 @@ import { ArrowLeft, LoaderCircle, Save, Package, DollarSign, FileText, Settings, Image as ImageIcon, FolderSearch, - UserCheck, CheckCircle2, XCircle, Tag, Layers, Scale, Info, Briefcase, ShieldCheck + UserCheck, CheckCircle2, XCircle, Tag, Layers, Scale, Info, Briefcase, ShieldCheck, Globe } from 'lucide-svelte'; // Stores & APIs @@ -141,7 +141,6 @@ alternate_unit_measure: d.inv_data?.alternate_uom || '', part_photo: d.part_photo || '', is_active: d.is_active ?? true, - // Cargar datos FA si existen sector: d.fa_data?.sector || '', fraction_type: d.fa_data?.fraction_type || '' }; @@ -193,7 +192,7 @@ function handleUOMSelect(item: any) { formData.unit_of_measure = item.code; } function handleAltUOMSelect(item: any) { formData.alternate_unit_measure = item.code; } function handleCurrencySelect(currency: any) { - formData.currency_type = ''; // Catálogo no usa currency_type + formData.currency_type = ''; formData.currency_key = currency.currency_type_code; selectedCurrencyName = currency.currency_type_code; } @@ -210,52 +209,35 @@ loading = true; try { - // Construimos el payload. let commonData: any = { ...formData }; - - // Si currency_key está vacío o es el default, ponerlo en null if (!commonData.currency_key || commonData.currency_key === 'USD') { commonData.currency_key = null; } - if (formType === 'fa') { - // Crear fa_data con los campos específicos de FA commonData.fa_data = { sector: formData.sector, fraction_type: formData.fraction_type, origin_country: formData.origin_country }; - // IMPORTANTE: Eliminar estos campos del nivel raíz para evitar duplicados delete commonData.sector; delete commonData.fraction_type; delete commonData.origin_country; } - // DEBUG: Ver qué se está enviando - console.log('Payload que se enviará:', JSON.stringify(commonData, null, 2)); - console.log('client_id:', formData.client_id); - console.log('selectedClientName:', selectedClientName); - if (isEdit && partId) { await partsApi.update(partId, commonData, activeCompanyId); } else { const result = await partsApi.create({ ...commonData, company_id: activeCompanyId }, activeCompanyId); - console.log('Resultado de creación:', result); - if (result.error) { - console.error('Error del backend:', result.error); - error = result.error; - return; - } + if (result.error) { error = result.error; return; } } goto('/dashboard/goods/parts'); } catch (e: any) { - console.error('Error completo:', e); error = e.message || 'Error al guardar'; } finally { loading = false; } } -
+
@@ -267,8 +249,8 @@ {isEdit ? "Editar" : "Nueva"}
-

- {formType === 'fa' ? 'Activo Fijo' : 'Inventario'} +

+ {formType === 'fa' ? 'Gestión de Activo Fijo' : 'Gestión de Inventario'}

@@ -276,7 +258,7 @@ {#if error} -
+
⚠️ {error}
{/if} @@ -285,101 +267,114 @@ {#if formType === 'fa'}
{ e.preventDefault(); handleSubmit(); }} class="space-y-6"> - +
- - + -
-
+
+
- +
+ + +
-
- +
+
- showClientModal = true} class="cursor-pointer" placeholder="Seleccione..."/> - +
+ + showClientModal = true} class="pl-9 cursor-pointer hover:bg-muted/50 transition-colors" placeholder="Seleccione un cliente..."/> +
+
-
-
- -