feat: Update API endpoints to ensure trailing slashes and adjust data types in models

This commit is contained in:
AlexeerCT
2026-01-02 13:35:01 -06:00
parent e554c4fca3
commit 104014d0fa
10 changed files with 46 additions and 54 deletions

View File

@@ -388,7 +388,7 @@ class TenantCRUDRoutes(
update_schema = self.update_schema
@self.router.put(
f"/{{{self.id_name}}}",
f"/{{{self.id_name}}}/",
response_model=self.response_schema,
summary=f"Update {self.resource_name}",
description=f"Update an existing {self.resource_name} by {self.id_name}",

View File

@@ -24,7 +24,7 @@ class PedimentoDatesBase(BaseModel):
class PedimentoDatesCreate(BaseModel):
"""Schema for creating a new Pedimento Dates - pedimento_id and tenant_id are set by backend"""
entry_date: Optional[datetime] = Field(None, description="Entry date")
entry_date: datetime = Field(..., description="Entry date")
pedimento_date: Optional[datetime] = Field(None, description="Pedimento date")
payment_date: datetime = Field(..., description="Payment date")
rectification_payment_date: Optional[datetime] = Field(None, description="Rectification payment date")

View File

@@ -1,13 +1,12 @@
from typing import TYPE_CHECKING
from typing import TYPE_CHECKING, Optional
from api.v1.common.base_models import TenantScopedMixin, TimestampMixin
from core.database import Base
from sqlalchemy import (
Boolean,
ForeignKeyConstraint,
Integer,
PrimaryKeyConstraint,
SmallInteger,
String,
UniqueConstraint,
)
from sqlalchemy.orm import Mapped, mapped_column, relationship
@@ -38,12 +37,12 @@ class PedimentoConfigAdditional(Base, TenantScopedMixin, TimestampMixin):
id: Mapped[int] = mapped_column(Integer)
pedimento_id: Mapped[int] = mapped_column(Integer, nullable=False)
add_po_identifier: Mapped[int] = mapped_column(SmallInteger)
do_not_exempt_norms_complement_x: Mapped[int] = mapped_column(SmallInteger)
manual_pedimento_year: Mapped[str] = mapped_column(String(2))
enable_import_invoice_recipient: Mapped[int] = mapped_column(SmallInteger)
send_502_validation_file_for_consolidated: Mapped[int] = mapped_column(SmallInteger)
add_remove_norms: Mapped[int] = mapped_column(SmallInteger)
add_po_identifier: Mapped[bool] = mapped_column(Boolean)
do_not_exempt_norms_complement_x: Mapped[bool] = mapped_column(Boolean)
manual_pedimento_year: Mapped[Optional[int]] = mapped_column(Integer)
enable_import_invoice_recipient: Mapped[bool] = mapped_column(Boolean)
send_502_validation_file_for_consolidated: Mapped[bool] = mapped_column(Boolean)
add_remove_norms: Mapped[bool] = mapped_column(Boolean)
pedimento: Mapped["Pedimentos"] = relationship(
"Pedimentos", back_populates="pedimento_config_additional"

View File

@@ -3,6 +3,7 @@ from typing import TYPE_CHECKING
from api.v1.common.base_models import TenantScopedMixin, TimestampMixin
from core.database import Base
from sqlalchemy import (
Boolean,
ForeignKeyConstraint,
Integer,
PrimaryKeyConstraint,
@@ -37,12 +38,12 @@ class PedimentoConfigSurcharges(Base, TenantScopedMixin, TimestampMixin):
id: Mapped[int] = mapped_column(Integer)
pedimento_id: Mapped[int] = mapped_column(Integer, nullable=False)
surcharge_igi: Mapped[int] = mapped_column(SmallInteger)
surcharge_dta: Mapped[int] = mapped_column(SmallInteger)
surcharge_vat: Mapped[int] = mapped_column(SmallInteger)
surcharge_isan: Mapped[int] = mapped_column(SmallInteger)
surcharge_ieps: Mapped[int] = mapped_column(SmallInteger)
surcharge_cc: Mapped[int] = mapped_column(SmallInteger)
surcharge_igi: Mapped[bool] = mapped_column(Boolean)
surcharge_dta: Mapped[bool] = mapped_column(Boolean)
surcharge_vat: Mapped[bool] = mapped_column(Boolean)
surcharge_isan: Mapped[bool] = mapped_column(Boolean)
surcharge_ieps: Mapped[bool] = mapped_column(Boolean)
surcharge_cc: Mapped[bool] = mapped_column(Boolean)
pedimento: Mapped["Pedimentos"] = relationship(
"Pedimentos", back_populates="pedimento_config_surcharges"

View File

@@ -110,7 +110,7 @@ export const clientsProvidersApi = {
}
return api.get<ClientProviderListResponse>(
`/v1/a76/clients-providers?${params.toString()}`
`/v1/a76/clients-providers/?${params.toString()}`
);
},
@@ -138,7 +138,7 @@ export const clientsProvidersApi = {
* @param data - Datos del cliente/proveedor a crear
*/
create: (companyId: number, data: CreateClientProviderData) =>
api.post<ClientProvider>(`/v1/a76/clients-providers?company_id=${companyId}`, data),
api.post<ClientProvider>(`/v1/a76/clients-providers/?company_id=${companyId}`, data),
/**
* Actualiza un cliente/proveedor existente
@@ -156,7 +156,7 @@ export const clientsProvidersApi = {
*/
toggleStatus: (id: number, companyId: number) =>
api.put<ClientProvider>(
`/v1/a76/clients-providers/${id}/toggle-status?company_id=${companyId}`,
`/v1/a76/clients-providers/${id}/toggle-status/?company_id=${companyId}`,
{}
),

View File

@@ -89,7 +89,7 @@ export const customsBrokersApi = {
* Lista todos los agentes aduanales
*/
list: (companyId: string) => {
return api.get<CustomsBroker[]>(`/v1/a76/customs-brokers?company_id=${companyId}`);
return api.get<CustomsBroker[]>(`/v1/a76/customs-brokers/?company_id=${companyId}`);
},
/**
@@ -104,7 +104,7 @@ export const customsBrokersApi = {
*/
create: (data: CreateCustomsBrokerData) => {
const companyId = data.company_id;
return api.post<CustomsBroker>(`/v1/a76/customs-brokers?company_id=${companyId}`, data);
return api.post<CustomsBroker>(`/v1/a76/customs-brokers/?company_id=${companyId}`, data);
},
/**

View File

@@ -76,7 +76,7 @@ export const itemsApi = {
const params = new URLSearchParams({
company_id: companyId.toString()
});
return api.get<ItemListResponse>(`/v1/a76/items/invoice/${invoiceId}/items?${params.toString()}`);
return api.get<ItemListResponse>(`/v1/a76/items/invoice/${invoiceId}/items/?${params.toString()}`);
},
/**
@@ -86,7 +86,7 @@ export const itemsApi = {
const params = new URLSearchParams({
company_id: companyId.toString()
});
return api.get<Item>(`/v1/a76/items/${itemId}?${params.toString()}`);
return api.get<Item>(`/v1/a76/items/${itemId}/?${params.toString()}`);
},
/**
@@ -106,7 +106,7 @@ export const itemsApi = {
const params = new URLSearchParams({
company_id: companyId.toString()
});
return api.put<Item>(`/v1/a76/items/${itemId}?${params.toString()}`, data);
return api.put<Item>(`/v1/a76/items/${itemId}/?${params.toString()}`, data);
},
/**
@@ -116,6 +116,6 @@ export const itemsApi = {
const params = new URLSearchParams({
company_id: companyId.toString()
});
return api.delete(`/v1/a76/items/${itemId}?${params.toString()}`);
return api.delete(`/v1/a76/items/${itemId}/?${params.toString()}`);
}
};

View File

@@ -276,7 +276,7 @@ export const pedimentosApi = {
* @param companyId - ID de la compañía (por defecto 1)
*/
list: (page = 1, pageSize = 50, filters?: PedimentoFilters, companyId = 1) => {
let url = `/v1/a76/pedimentos?company_id=${companyId}&page=${page}&page_size=${pageSize}`;
let url = `/v1/a76/pedimentos/?company_id=${companyId}&page=${page}&page_size=${pageSize}`;
if (filters?.status) {
url += `&status=${encodeURIComponent(filters.status)}`;
@@ -296,7 +296,7 @@ export const pedimentosApi = {
* @param id - ID del pedimento
* @param companyId - ID de la compañía (por defecto 1)
*/
get: (id: number, companyId = 1) => api.get<Pedimento>(`/v1/a76/pedimentos/${id}?company_id=${companyId}`),
get: (id: number, companyId = 1) => api.get<Pedimento>(`/v1/a76/pedimentos/${id}/?company_id=${companyId}`),
/**
* Crea un nuevo pedimento
@@ -304,7 +304,7 @@ export const pedimentosApi = {
* @param companyId - ID de la compañía (por defecto 1)
*/
create: (data: CreatePedimentoData, companyId = 1) =>
api.post<Pedimento>(`/v1/a76/pedimentos?company_id=${companyId}`, data),
api.post<Pedimento>(`/v1/a76/pedimentos/?company_id=${companyId}`, data),
/**
* Actualiza un pedimento existente
@@ -313,12 +313,12 @@ export const pedimentosApi = {
* @param companyId - ID de la compañía (por defecto 1)
*/
update: (id: number, data: UpdatePedimentoData, companyId = 1) =>
api.put<Pedimento>(`/v1/a76/pedimentos/${id}?company_id=${companyId}`, data),
api.put<Pedimento>(`/v1/a76/pedimentos/${id}/?company_id=${companyId}`, data),
/**
* Elimina un pedimento
* @param id - ID del pedimento a eliminar
* @param companyId - ID de la compañía (por defecto 1)
*/
delete: (id: number, companyId = 1) => api.delete(`/v1/a76/pedimentos/${id}?company_id=${companyId}`)
delete: (id: number, companyId = 1) => api.delete(`/v1/a76/pedimentos/${id}/?company_id=${companyId}`)
};

View File

@@ -1,4 +1,5 @@
<script lang="ts">
import { onMount } from 'svelte';
import * as Card from '$lib/components/ui/card';
import { Input } from '$lib/components/ui/input';
import { Label } from '$lib/components/ui/label';
@@ -66,6 +67,10 @@
{ value: 2, label: 'Importación' },
];
// Track previous values to detect changes
let previousPedimentoCode = $state('');
let previousOperationType = $state<number | null>(null);
// Opciones filtradas para Régimen y Tipo de Operación basadas en las selecciones actuales
// NOTA: La Clave NO se filtra, siempre muestra todas las opciones
@@ -104,11 +109,7 @@
return operationOptions.filter(opt => validTypes.has(opt.value));
}
return operationOptions;
});
// Track previous values to detect changes
let previousPedimentoCode = $state(formData?.pedimento_code || '');
let previousOperationType = $state(formData?.operation_type ?? null);
});
// Reactive synchronization between Clave, Régimen, and Tipo de Operación
// REGLA: La Clave es el campo principal y NUNCA se modifica automáticamente
@@ -204,10 +205,8 @@
});
// Obtener el año actual (últimos 2 dígitos)
const currentYear = String(new Date().getFullYear()).slice(-2);
// Obtener fecha y hora actual para captura
const now = new Date();
const currentYear = String(now.getFullYear()).slice(-2);
const currentDate = now.toISOString().substring(0, 10); // YYYY-MM-DD
const currentTime = now.toTimeString().substring(0, 5); // HH:MM
@@ -250,16 +249,12 @@
});
// Obtener automáticamente el tipo de cambio cuando cambie la fecha de entrada
$effect(() => {
if (formData && formData.entry_date && companyStore.activeCompany) {
console.log('🔍 [TIPO CAMBIO] Buscando para fecha:', formData.entry_date, 'Company ID:', companyStore.activeCompany.id);
onMount(() => {
if (formData && formData.entry_date && companyStore.activeCompany) {
getExchangeRateByDate(formData.entry_date, companyStore.activeCompany.id)
.then(usdRate => {
console.log('✅ [TIPO CAMBIO] Respuesta recibida:', usdRate);
.then(usdRate => {
if (usdRate && formData) {
formData.exchange_rate = usdRate.value;
console.log('✅ [TIPO CAMBIO] Actualizado a:', usdRate.value);
formData.exchange_rate = usdRate.value;
} else {
console.warn('⚠️ [TIPO CAMBIO] No encontrado para fecha:', formData.entry_date);
}
@@ -267,9 +262,7 @@
.catch(err => {
console.error('❌ [TIPO CAMBIO] Error:', err);
});
} else {
console.log('⏭️ [TIPO CAMBIO] Saltado - formData:', !!formData, 'entry_date:', formData?.entry_date, 'company:', !!companyStore.activeCompany);
}
}
});
const statusOptions = [
@@ -750,7 +743,7 @@
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
<!-- Fecha de Entrada -->
<div class="space-y-2">
<Label for="entry_date">Fecha de Entrada</Label>
<Label for="entry_date">Fecha de Entrada <span class="text-red-500">*</span></Label>
<Input
id="entry_date"
type="date"
@@ -800,7 +793,7 @@
<!-- Fecha de Pago -->
<div class="space-y-2">
<Label for="payment_date">Fecha de Pago</Label>
<Label for="payment_date">Fecha de Pago <span class="text-red-500">*</span></Label>
<Input
id="payment_date"
type="date"

View File

@@ -434,8 +434,7 @@
update_dta: otrosDatosFormData.actualizar_dta || false,
update_cc: otrosDatosFormData.actualizar_cc || false,
update_ieps: otrosDatosFormData.actualizar_ieps || false
};
console.log('📤 Enviando pedimento_config_updates:', payload.pedimento_config_updates);
};
}
}