Merge branch 'development' of https://git.aduanasoft.com/ADUANASOFT/anexo76 into feature/tablas_nuevas_partes

This commit is contained in:
2026-03-18 11:03:26 -05:00
142 changed files with 10823 additions and 4453 deletions

View File

@@ -25,7 +25,6 @@ export interface ClientProviderPrograms {
secon_auth_date?: number | null; // YYYYMMDD
prosec?: number | null;
manufacturer_id?: string | null;
tax_id?: string | null;
ctpat_svi?: string | null;
is_certified_company?: string | null;
}
@@ -45,8 +44,6 @@ export interface ClientProvider {
responsible?: string | null;
position?: string | null;
// Booleanos (Coincidiendo con la BD)
is_national_provider?: boolean | null;
is_active?: boolean;
// Relaciones Anidadas

View File

@@ -35,6 +35,33 @@ export interface IdentifierListResponse {
pages: number;
}
export interface IdentifierDetail {
id: number;
invoice_consecutive: number | null;
part_line: number | null;
identifier_code: string | null;
module: string | null;
complement1: string | null;
complement2: string | null;
complement3: string | null;
item_line_id: number | null;
company_id: number;
tenant_id: number;
}
export interface IdentifierDetailCreate {
invoice_consecutive?: number | null;
part_line?: number | null;
identifier_code?: string | null;
module?: string | null;
complement1?: string | null;
complement2?: string | null;
complement3?: string | null;
item_line_id?: number | null;
}
export interface IdentifierDetailUpdate extends Partial<IdentifierDetailCreate> { }
export async function getIdentifiers(
page = 1,
pageSize = 50,
@@ -71,4 +98,29 @@ export async function deleteIdentifier(
companyId: number
): Promise<ApiResponse<void>> {
return await api.delete(`/v1/a76/identifiers/${id}/?company_id=${companyId}`);
}
/**
* API for Identifier Details
*/
export async function createIdentifierDetail(
data: IdentifierDetailCreate,
companyId: number
): Promise<ApiResponse<IdentifierDetail>> {
return await api.post(`/v1/a76/identifiers/details/?company_id=${companyId}`, data);
}
export async function updateIdentifierDetail(
id: number,
data: IdentifierDetailUpdate,
companyId: number
): Promise<ApiResponse<IdentifierDetail>> {
return await api.put(`/v1/a76/identifiers/details/${id}/?company_id=${companyId}`, data);
}
export async function deleteIdentifierDetail(
id: number,
companyId: number
): Promise<ApiResponse<void>> {
return await api.delete(`/v1/a76/identifiers/details/${id}/?company_id=${companyId}`);
}

View File

@@ -76,6 +76,7 @@ export async function updateUnitConversion(
}
export async function deleteUnitConversion(id: number, companyId: number): Promise<void> {
const response = await api.delete(`/v1/a76/unit-conversions/${id}/?company_id=${companyId}`);
// Backend DELETE route is defined without trailing slash: /unit-conversions/{id}
const response = await api.delete(`/v1/a76/unit-conversions/${id}?company_id=${companyId}`);
if (response.error) throw new Error(response.error);
}

View File

@@ -88,6 +88,10 @@ export interface LineReferences {
serie_id?: number;
}
import type {
IdentifierDetail
} from './general_catalogs/identifiers';
export interface Serie {
id?: number;
line_item_id?: number;
@@ -98,6 +102,9 @@ export interface Serie {
brand?: string;
expo_brad?: string;
number_id?: string;
import_invoice?: string;
import_line?: number;
image_path?: string;
}
export interface FaLineItem {
@@ -127,7 +134,7 @@ export interface FaLineItem {
subitem_number?: number;
// Special flags
download?: boolean;
discharge?: boolean;
own_equipment?: boolean;
omit_annex31?: boolean;
@@ -207,6 +214,7 @@ export interface Item {
reference?: LineReferences;
fa_data?: FaLineItem; // Fixed Asset specific data
series?: Serie[]; // Series data (multiple per line)
identifiers?: IdentifierDetail[]; // Identifiers for this line
}
export interface ItemListResponse {
@@ -291,5 +299,52 @@ export const itemsApi = {
company_id: companyId.toString()
});
return api.delete(`/v1/a76/items/${itemId}/?${params.toString()}`);
},
/**
* Lista las líneas de una factura de importación con su saldo disponible.
* Solo las líneas con has_balance = true tienen mercancía disponible para descarga.
*
* @param invoiceId - ID de la factura de importación
* @param companyId - ID de la empresa
* @param asOfDate - Fecha corte opcional (ISO: "YYYY-MM-DD").
* Pasa la fecha de la factura de exportación para que
* los consumos futuros no se descuenten del saldo.
*/
listByInvoiceWithBalance: (
invoiceId: number,
companyId: number,
asOfDate?: string
) => {
const params = new URLSearchParams({ company_id: companyId.toString() });
if (asOfDate) params.append('as_of_date', asOfDate);
return api.get<ImportLineWithBalance[]>(
`/v1/a76/items/invoice/${invoiceId}/items-with-balance?${params.toString()}`
);
}
};
export interface ImportLineWithBalance {
id: number;
line_number: number;
// Invoice info
invoice_number?: string;
invoice_date?: string;
invoice_status?: string;
// Part / class
part_number?: string;
class_code?: string;
description_spanish?: string;
unit_of_measure_code?: string;
// Quantities
quantity?: number;
quantity_returned_temp?: number;
quantity_returned?: number;
// Balance
available_balance: number;
has_balance: boolean;
// FA / subitem
is_subitem?: boolean;
contains_subitems?: boolean;
subitem_count?: number;
}

View File

@@ -1,11 +1,14 @@
import { api } from '$lib/api';
import type { ApiResponse } from '$lib/api';
export interface Sector {
id: number;
key: string;
description: string;
authorized: boolean;
company_id: number;
tenant_id: number;
created_at?: string;
updated_at?: string;
}
export interface SectorListResponse {
@@ -18,18 +21,20 @@ export interface SectorListResponse {
export async function getSectors(
page = 1,
pageSize = 50,
companyId: number,
search?: string
): Promise<SectorListResponse> {
const params = new URLSearchParams({
page: page.toString(),
page_size: pageSize.toString()
page_size: pageSize.toString(),
company_id: companyId.toString()
});
if (search) {
params.append('search', search);
params.append('key', search);
}
const response = await api.get<SectorListResponse>(`/v1/public/reference_data/sectors/?${params.toString()}`);
const response = await api.get<SectorListResponse>(`/v1/a76/sectors/?${params.toString()}`);
if (!response.data) throw new Error('Error fetching sectors');
return response.data;
}

View File

@@ -1,13 +1,17 @@
/**
* API Client para Sectors
* Gestiona las operaciones CRUD para los sectores
* API Client para Sectors (a76 — tenant-scoped)
*/
import { api } from '$lib/api';
export interface Sector {
id: number;
key: string;
description: string;
authorized: number;
authorized: boolean;
company_id: number;
tenant_id: number;
created_at?: string;
updated_at?: string;
}
export interface SectorListResponse {
@@ -20,60 +24,45 @@ export interface SectorListResponse {
export interface CreateSectorData {
key: string;
description: string;
authorized: number;
authorized: boolean;
}
export interface UpdateSectorData {
key?: string;
description?: string;
authorized?: number;
authorized?: boolean;
}
/**
* API para Sectors
*/
export const sectorsApi = {
/**
* Lista todos los sectores con paginación
* @param page - Número de página (por defecto 1)
* @param pageSize - Tamaño de página (por defecto 50)
*/
list: (page = 1, pageSize = 50) =>
api.get<SectorListResponse>(
// CORREGIDO: Slash antes del '?'
`/v1/public/reference_data/sectors/?page=${page}&page_size=${pageSize}`
),
list: (page = 1, pageSize = 50, companyId: number, search?: string) => {
const params = new URLSearchParams({
page: page.toString(),
page_size: pageSize.toString(),
company_id: companyId.toString()
});
if (search) params.append('key', search);
return api.get<SectorListResponse>(`/v1/a76/sectors/?${params.toString()}`);
},
/**
* Obtiene un sector por key
* @param key - Clave del sector
*/
get: (key: string) =>
// CORREGIDO: Slash final
api.get<Sector>(`/v1/public/reference_data/sectors/${key}/`),
get: (id: number, companyId: number) =>
api.get<Sector>(`/v1/a76/sectors/${id}/?company_id=${companyId}`),
/**
* Crea un nuevo sector
* @param data - Datos del sector a crear
*/
create: (data: CreateSectorData) =>
// CORREGIDO: Slash final
api.post<Sector>('/v1/public/reference_data/sectors/', data),
getByKey: (key: string, companyId: number) => {
const params = new URLSearchParams({
page: '1',
page_size: '1',
company_id: companyId.toString(),
key
});
return api.get<SectorListResponse>(`/v1/a76/sectors/?${params.toString()}`);
},
/**
* Actualiza un sector existente
* @param key - Clave del sector a actualizar
* @param data - Datos a actualizar
*/
update: (key: string, data: UpdateSectorData) =>
// CORREGIDO: Slash final después de la variable
api.put<Sector>(`/v1/public/reference_data/sectors/${key}/`, data),
create: (data: CreateSectorData, companyId: number) =>
api.post<Sector>(`/v1/a76/sectors/?company_id=${companyId}`, data),
/**
* Elimina un sector
* @param key - Clave del sector a eliminar
*/
delete: (key: string) =>
// CORREGIDO: Slash final después de la variable
api.delete(`/v1/public/reference_data/sectors/${key}/`)
};
update: (id: number, data: UpdateSectorData, companyId: number) =>
api.put<Sector>(`/v1/a76/sectors/${id}/?company_id=${companyId}`, data),
delete: (id: number, companyId: number) =>
api.delete(`/v1/a76/sectors/${id}/?company_id=${companyId}`)
};