Merge remote-tracking branch 'origin/development' into feature/Invoice-movements

# Conflicts:
#	backend/api/v1/modules/a76/reports/importacion/facturas/usa/service.py
#	backend/core/celery_app.py
#	frontend/src/lib/api/dashboard/a76/general_catalogs/company.ts
This commit is contained in:
Galindo97
2026-02-20 10:09:19 -06:00
127 changed files with 17010 additions and 9437 deletions

View File

@@ -219,7 +219,27 @@ export interface Company {
cfdi_xml_save_path?: string | null;
cfdi_app_path?: string | null;
cfdi_pac_app_path?: string | null;
// Digital Certificates (Flattened)
fiel_cer?: string | null;
fiel_key?: string | null;
fiel_pass?: string | null;
fiel_access?: string | null;
fiel_cer_exp?: number | null;
fiel_key_exp?: number | null;
cfdi_cert_cer?: string | null;
cfdi_cert_key?: string | null;
cfdi_cert_pass?: string | null;
cfdi_cert_access?: string | null;
cfdi_cert_cer_exp?: number | null;
cfdi_cert_key_exp?: number | null;
cancel_cer?: string | null;
cancel_key?: string | null;
cancel_pass?: string | null;
cancel_access?: string | null;
cancel_cer_exp?: number | null;
cancel_key_exp?: number | null;
// Submodelos
addresses?: CompanyAddress[];
certification?: CompanyCertification | null;
digital_certificates?: CompanyDigitalCertificate[];
@@ -274,31 +294,139 @@ export interface CompanyCreate {
order_format_type?: string | null;
ctpat_svi?: string | null;
trusted_exporter_number?: string | null;
logo?: string | null;
previous_code?: number | null;
client_name?: string | null;
subassembly_mode?: string | null;
inter_db_name?: string | null;
prevalidator_key?: string | null;
seventh_amendment?: boolean;
// Digital Certificates
fiel_cer?: string | null;
fiel_key?: string | null;
fiel_pass?: string | null;
fiel_access?: string | null;
fiel_cer_exp?: number | null;
fiel_key_exp?: number | null;
cfdi_cert_cer?: string | null;
cfdi_cert_key?: string | null;
cfdi_cert_pass?: string | null;
cfdi_cert_access?: string | null;
cfdi_cert_cer_exp?: number | null;
cfdi_cert_key_exp?: number | null;
cancel_cer?: string | null;
cancel_key?: string | null;
cancel_pass?: string | null;
cancel_access?: string | null;
cancel_cer_exp?: number | null;
cancel_key_exp?: number | null;
// Sectores
sector1?: string | null;
sector2?: string | null;
sector3?: string | null;
// Flags técnicos
active_labels?: number | null;
active_fractions?: number | null;
activate_caat?: number | null;
trans_interface?: number | null;
american_costs?: number | null;
scaf_readonly?: number | null;
parts_replacement?: number | null;
activate_facmexame?: number | null;
part_reference?: number | null;
international_firm?: number | null;
// Configuraciones
ftp_key?: string | null;
sifra_path?: string | null;
version_type?: string | null;
sql_language?: string | null;
balance_operation_mode?: string | null;
// Campos de certificación
is_certified_company?: string | null;
certified_company_registration?: string | null;
certified_company_start_date?: number | null;
certified_company_end_date?: number | null;
annex31_certification_date?: number | null;
annex31_certification_number?: string | null;
annex31_modality?: string | null;
annex31_company_type?: string | null;
annex31_renewal_date?: number | null;
annex31_final_certification_date?: number | null;
is_oea_company?: number | null;
neec_company?: number | null;
// Campos de dirección principal
main_street?: string | null;
main_exterior_number?: string | null;
main_interior_number?: string | null;
main_postal_code?: string | null;
main_neighborhood?: string | null;
main_city?: string | null;
main_municipality?: string | null;
main_state?: string | null;
main_country?: string | null;
main_phone?: string | null;
main_fax?: string | null;
main_email?: string | null;
// Campos de dirección industrial 1
ind1_street?: string | null;
ind1_exterior_number?: string | null;
ind1_interior_number?: string | null;
ind1_postal_code?: string | null;
ind1_neighborhood?: string | null;
ind1_city?: string | null;
ind1_municipality?: string | null;
ind1_state?: string | null;
ind1_country?: string | null;
ind1_phone?: string | null;
ind1_fax?: string | null;
ind1_email?: string | null;
// Campos de dirección industrial 2
ind2_street?: string | null;
ind2_exterior_number?: string | null;
ind2_interior_number?: string | null;
ind2_postal_code?: string | null;
ind2_neighborhood?: string | null;
ind2_city?: string | null;
ind2_municipality?: string | null;
ind2_state?: string | null;
ind2_country?: string | null;
ind2_phone?: string | null;
ind2_fax?: string | null;
ind2_email?: string | null;
// Campos de prevalidador
prev_customs?: string | null;
prev_key?: string | null;
prev_patent?: string | null;
prev_description?: string | null;
// Campos de ventanilla única
vu_webservice_user?: string | null;
vu_webservice_password?: string | null;
vu_email?: string | null;
vu_figure_type?: string | null;
vu_central_path?: string | null;
vu_xml_files_path?: string | null;
vu_query_rfc?: string | null;
vu_validation_rfc?: string | null;
vu_configuration_source?: string | null;
vu_measurement_units?: string | null;
// Campos de agente aduanal electrónico
ea_input_folder?: string | null;
ea_output_folder?: string | null;
ea_send_mask?: string | null;
ea_response_mask?: string | null;
ea_response_extension?: string | null;
ea_counter_start?: number | null;
ea_counter_end?: number | null;
ea_counter_next?: number | null;
// Campos de CFDI
cfdi_xml_save_path?: string | null;
cfdi_app_path?: string | null;
cfdi_pac_app_path?: string | null;
}
export interface CompanyUpdate {
name?: string | null;
rfc?: string | null;
curp?: string | null;
main_activity?: string | null;
program?: string | null;
program_number?: string | null;
prosec?: number | null;
prosec_authorization?: string | null;
manufacturer_id?: string | null;
broker_company?: string | null;
responsible?: string | null;
responsible_name?: string | null;
responsible_last_name?: string | null;
responsible_mother_last_name?: string | null;
responsible_rfc?: string | null;
position?: string | null;
has_express_line?: boolean;
is_service_company?: boolean;
order_format_type?: string | null;
ctpat_svi?: string | null;
trusted_exporter_number?: string | null;
}
export interface CompanyUpdate extends CompanyCreate { }
export interface CompanyListResponse {
items: Company[];
@@ -370,10 +498,9 @@ export async function uploadCompanyLogo(id: number, file: File): Promise<ApiResp
};
}
export async function uploadCompanyCertificate(id: number, type: string, file: File, password?: string): Promise<ApiResponse<{ message: string; file_path: string }>> {
export async function uploadCompanyCertificate(id: number, type: string, file: File, password?: string): Promise<ApiResponse<{ message: string; file_path: string; certificate_type: string; company_id: number }>> {
const formData = new FormData();
formData.append('file', file);
formData.append('type', type);
if (password) {
formData.append('password', password);
}
@@ -381,7 +508,7 @@ export async function uploadCompanyCertificate(id: number, type: string, file: F
const token = localStorage.getItem('access_token');
const API_BASE_URL = (import.meta.env.VITE_API_URL || '').replace(/\/+$/, '');
const response = await fetch(`${API_BASE_URL}/v1/a76/company/${id}/upload-certificate`, {
const response = await fetch(`${API_BASE_URL}/v1/a76/company/${id}/upload-certificate?certificate_type=${type}`, {
method: 'POST',
headers: {
'Authorization': `Bearer ${token}`,

View File

@@ -0,0 +1,103 @@
import { api } from '$lib/api';
import type { ApiResponse } from '$lib/api';
export interface HistoricalFraction {
id: number;
historical_fraction: string | null;
unit_of_measure_code: string | null;
country: string | null;
fraction_type: string | null;
sector: string | null;
import_tax_rate: number | null;
export_tax_rate: number | null;
publication_date: string | null;
is_immex: boolean | null;
normal_temporality: boolean | null;
services_temporality: boolean | null;
certified_temporality: boolean | null;
by_log: boolean | null;
end_date: string | null;
}
export interface HistoricalFractionCreate {
historical_fraction: string;
unit_of_measure_code?: string | null;
country?: string | null;
fraction_type?: string | null;
sector?: string | null;
import_tax_rate?: number | null;
export_tax_rate?: number | null;
publication_date?: string | null;
is_immex?: boolean | null;
normal_temporality?: boolean | null;
services_temporality?: boolean | null;
certified_temporality?: boolean | null;
by_log?: boolean | null;
end_date?: string | null;
}
export interface HistoricalFractionUpdate {
historical_fraction?: string;
unit_of_measure_code?: string | null;
country?: string | null;
fraction_type?: string | null;
sector?: string | null;
import_tax_rate?: number | null;
export_tax_rate?: number | null;
publication_date?: string | null;
is_immex?: boolean | null;
normal_temporality?: boolean | null;
services_temporality?: boolean | null;
certified_temporality?: boolean | null;
by_log?: boolean | null;
end_date?: string | null;
}
export interface HistoricalFractionList {
items: HistoricalFraction[];
total: number;
page: number;
page_size: number;
pages: number;
}
export async function getHistoricalFractions(
companyId: number,
historicalFraction?: string,
page = 1,
pageSize = 50
): Promise<HistoricalFractionList> {
const params = new URLSearchParams({
company_id: companyId.toString(),
page: page.toString(),
page_size: pageSize.toString()
});
if (historicalFraction) params.append('historical_fraction', historicalFraction);
const response = await api.get<HistoricalFractionList>(`/v1/a76/fractions/historical-tariff-fractions/?${params.toString()}`);
if (!response.data) throw new Error('Error fetching historical fractions');
return response.data;
}
export async function createHistoricalFraction(
companyId: number,
data: HistoricalFractionCreate
): Promise<ApiResponse<HistoricalFraction>> {
return await api.post(`/v1/a76/fractions/historical-tariff-fractions/?company_id=${companyId}`, data);
}
export async function updateHistoricalFraction(
companyId: number,
id: number,
data: HistoricalFractionUpdate
): Promise<ApiResponse<HistoricalFraction>> {
return await api.put(`/v1/a76/fractions/historical-tariff-fractions/${id}/?company_id=${companyId}`, data);
}
export async function deleteHistoricalFraction(
companyId: number,
id: number
): Promise<ApiResponse<void>> {
return await api.delete(`/v1/a76/fractions/historical-tariff-fractions/${id}/?company_id=${companyId}`);
}

View File

@@ -69,22 +69,33 @@ export async function getTariffFractionById(
export async function createTariffFraction(
data: TariffFractionCreate,
companyId: number
companyId: number,
catalog = 'mex'
): Promise<ApiResponse<TariffFraction>> {
return await api.post(`/v1/a76/tariff-fractions/?company_id=${companyId}`, data);
return await api.post(
`/v1/a76/tariff-fractions/?company_id=${companyId}&catalog=${catalog}`,
data
);
}
export async function updateTariffFraction(
id: number,
data: TariffFractionUpdate,
companyId: number
companyId: number,
catalog = 'mex'
): Promise<ApiResponse<TariffFraction>> {
return await api.put(`/v1/a76/tariff-fractions/${id}/?company_id=${companyId}`, data);
return await api.put(
`/v1/a76/tariff-fractions/${id}/?company_id=${companyId}&catalog=${catalog}`,
data
);
}
export async function deleteTariffFraction(
id: number,
companyId: number
companyId: number,
catalog = 'mex'
): Promise<ApiResponse<void>> {
return await api.delete(`/v1/a76/tariff-fractions/${id}/?company_id=${companyId}`);
return await api.delete(
`/v1/a76/tariff-fractions/${id}/?company_id=${companyId}&catalog=${catalog}`
);
}

View File

@@ -17,7 +17,11 @@ export interface LineCustoms {
origin_country?: string;
destination_country?: string;
advalorem?: string;
advalorem_american?: number; // Backend: Decimal
advalorem_numeric?: number;
advalorem_american?: number;
advalorem_tlcan?: number;
rate?: string;
depreciation_rate?: number;
sector?: string;
}
@@ -31,11 +35,13 @@ export interface LineFinancials {
unit_cost_commercial_usd?: number;
// Values
value_mc?: number;
value_usd?: number;
value_mxn?: number;
value_returned_usd?: number;
value_returned_mxn?: number;
customs_value_usd?: number;
customs_value_mxn?: number;
}
export interface LineQuantities {
@@ -105,8 +111,7 @@ export interface FaLineItem {
// Subitems
is_subitem?: boolean;
contains_subitems?: boolean;
includes_subitems?: boolean;
contains_subitems?: boolean;
subitem_number?: number;
// Special flags
@@ -119,9 +124,9 @@ export interface FaLineItem {
updated_at?: string;
}
export interface LineItem {
id?: number;
item_id?: number;
export interface Item {
id?: number;
invoice_id: number;
line_number: number;
// Identification
@@ -159,20 +164,7 @@ export interface LineItem {
class_description?: string;
// Computed field from unit_of_measure_info relation
unit_of_measure_code?: string;
// Nested relations (Singular names to match backend Pydantic models)
customs?: LineCustoms;
financial?: LineFinancials;
quantity?: LineQuantities;
description?: LineDescriptions;
reference?: LineReferences;
fa_data?: FaLineItem; // Fixed Asset specific data
}
export interface Item {
id?: number;
invoice_id: number;
unit_of_measure_code?: string;
reference_number?: string;
order?: string;
guide_number?: string;
@@ -182,8 +174,14 @@ export interface Item {
location?: string;
created_at?: string;
updated_at?: string;
lines?: LineItem[];
// Nested relations (Singular names to match backend Pydantic models)
customs?: LineCustoms;
financial?: LineFinancials;
quantity?: LineQuantities;
description?: LineDescriptions;
reference?: LineReferences;
fa_data?: FaLineItem; // Fixed Asset specific data
}
export interface ItemListResponse {
@@ -193,28 +191,11 @@ export interface ItemListResponse {
limit: number;
}
export interface CreateItemData {
export interface CreateItemData extends Omit<Item, 'id' | 'created_at' | 'updated_at'> {
invoice_id: number;
reference_number?: string;
order?: string;
guide_number?: string;
depreciation_date?: number;
rectification?: number;
warehouse?: string;
location?: string;
lines?: LineItem[];
}
export interface UpdateItemData {
reference_number?: string;
order?: string;
guide_number?: string;
depreciation_date?: number;
rectification?: boolean;
warehouse?: string;
location?: string;
lines?: LineItem[];
}
export interface UpdateItemData extends Partial<Omit<Item, 'id' | 'invoice_id' | 'created_at' | 'updated_at'>> {}
/**
* API para Items

View File

@@ -0,0 +1,95 @@
const BASE_URL = import.meta.env.VITE_API_URL || '';
export const reportsTransmissionApi = {
triggerGeneration: async (request: any) => {
const endpoint = `${BASE_URL}/v1/a76/reports/exportacion/transmission/generate`;
const token = localStorage.getItem('access_token');
const response = await fetch(endpoint, {
method: 'POST',
headers: {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json'
},
body: JSON.stringify(request)
});
if (!response.ok) throw new Error('Error al iniciar la generación del archivo de transmisión');
return await response.json();
},
getTaskStatus: async (taskId: string) => {
const endpoint = `${BASE_URL}/v1/a76/reports/exportacion/transmission/tasks/${taskId}`;
const token = localStorage.getItem('access_token');
const response = await fetch(endpoint, {
method: 'GET',
headers: { 'Authorization': `Bearer ${token}` }
});
if (!response.ok) throw new Error('Error al consultar estado de la transmisión');
return await response.json();
},
triggerTemporalGeneration: async (request: any) => {
const endpoint = `${BASE_URL}/v1/a76/reports/importacion/transmission/temporal/generate`;
const token = localStorage.getItem('access_token');
const response = await fetch(endpoint, {
method: 'POST',
headers: {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json'
},
body: JSON.stringify(request)
});
if (!response.ok) throw new Error('Error al iniciar la generación temporal');
return await response.json();
},
getTemporalTaskStatus: async (taskId: string) => {
const endpoint = `${BASE_URL}/v1/a76/reports/importacion/transmission/temporal/tasks/${taskId}`;
const token = localStorage.getItem('access_token');
const response = await fetch(endpoint, {
method: 'GET',
headers: { 'Authorization': `Bearer ${token}` }
});
if (!response.ok) throw new Error('Error al consultar estado de la transmisión temporal');
return await response.json();
},
triggerDefinitiveGeneration: async (request: any) => {
const endpoint = `${BASE_URL}/v1/a76/reports/importacion/transmission/definitive/generate`;
const token = localStorage.getItem('access_token');
const response = await fetch(endpoint, {
method: 'POST',
headers: {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json'
},
body: JSON.stringify(request)
});
if (!response.ok) throw new Error('Error al iniciar la generación definitiva');
return await response.json();
},
getDefinitiveTaskStatus: async (taskId: string) => {
const endpoint = `${BASE_URL}/v1/a76/reports/importacion/transmission/definitive/tasks/${taskId}`;
const token = localStorage.getItem('access_token');
const response = await fetch(endpoint, {
method: 'GET',
headers: { 'Authorization': `Bearer ${token}` }
});
if (!response.ok) throw new Error('Error al consultar estado de la transmisión definitiva');
return await response.json();
}
};

View File

@@ -0,0 +1,77 @@
import { api } from '$lib/api';
export interface CanadianFraction {
id: number;
fraction: string;
ad_valorem: number | null;
unit_of_measure: string | null;
country_code: string;
description: string | null;
created_at: string;
updated_at: string;
}
export interface CanadianFractionList {
items: CanadianFraction[];
total: number;
page: number;
page_size: number;
pages: number;
}
export interface CanadianFractionCreate {
fraction: string;
ad_valorem?: number;
unit_of_measure?: string;
country_code: string;
description?: string;
}
export interface CanadianFractionUpdate {
fraction?: string;
ad_valorem?: number;
unit_of_measure?: string;
country_code?: string;
description?: string;
}
const BASE_URL = '/v1/a76/fractions/canadian-tariff-fractions/';
export async function getCanadianFractions(
companyId: number,
page = 1,
pageSize = 50,
search?: string
): Promise<CanadianFractionList> {
const params = new URLSearchParams({
company_id: companyId.toString(),
page: page.toString(),
page_size: pageSize.toString()
});
if (search) params.append('search', search);
const response = await api.get<CanadianFractionList>(`${BASE_URL}?${params.toString()}`);
if (!response.data) throw new Error('Error fetching Canadian fractions');
return response.data;
}
export async function createCanadianFraction(companyId: number, data: CanadianFractionCreate): Promise<CanadianFraction> {
const params = new URLSearchParams({ company_id: companyId.toString() });
const response = await api.post<CanadianFraction>(`${BASE_URL}?${params.toString()}`, data);
if (!response.data) throw new Error('Error creating Canadian fraction');
return response.data;
}
export async function updateCanadianFraction(companyId: number, id: number, data: CanadianFractionUpdate): Promise<CanadianFraction> {
const params = new URLSearchParams({ company_id: companyId.toString() });
const response = await api.put<CanadianFraction>(`${BASE_URL}${id}?${params.toString()}`, data);
if (!response.data) throw new Error('Error updating Canadian fraction');
return response.data;
}
export async function deleteCanadianFraction(companyId: number, id: number): Promise<void> {
const params = new URLSearchParams({ company_id: companyId.toString() });
await api.delete(`${BASE_URL}${id}?${params.toString()}`);
}

View File

@@ -0,0 +1,35 @@
import { api } from '$lib/api';
import type { ApiResponse } from '$lib/api';
export interface Sector {
key: string;
description: string;
authorized: boolean;
}
export interface SectorListResponse {
items: Sector[];
total: number;
page: number;
page_size: number;
}
export async function getSectors(
page = 1,
pageSize = 50,
search?: string
): Promise<SectorListResponse> {
const params = new URLSearchParams({
page: page.toString(),
page_size: pageSize.toString()
});
if (search) {
params.append('search', search);
}
const response = await api.get<SectorListResponse>(`/v1/public/reference_data/sectors/?${params.toString()}`);
if (!response.data) throw new Error('Error fetching sectors');
return response.data;
}