Merge branch 'feature/api-sitar-frac-ame' into feature/company-id-lost
This commit is contained in:
@@ -805,24 +805,6 @@ export const api = {
|
||||
fetchBlob(`/v1/a76/exchange-rate/imports/${jobId}/errors/scan-csv`)
|
||||
},
|
||||
|
||||
// CSV import for Fracción Americana (us_tariff_fractions/imports)
|
||||
americanFractionImports: {
|
||||
upload: (file: File, companyId: number, uploadOptions?: CsvFormDataUploadOptions) => {
|
||||
const formData = new FormData();
|
||||
formData.append('file', file);
|
||||
return fetchApiFormDataPost(
|
||||
`/v1/a76/us-tariff-fractions/imports/upload?company_id=${companyId}`,
|
||||
formData,
|
||||
uploadOptions
|
||||
);
|
||||
},
|
||||
status: (jobId: string) => api.get(`/v1/a76/us-tariff-fractions/imports/${jobId}/status`),
|
||||
commit: (jobId: string) =>
|
||||
api.post(`/v1/a76/us-tariff-fractions/imports/${jobId}/commit`, {}),
|
||||
downloadScanErrorsCsv: (jobId: string) =>
|
||||
fetchBlob(`/v1/a76/us-tariff-fractions/imports/${jobId}/errors/scan-csv`)
|
||||
},
|
||||
|
||||
// CSV import for Pedimentos (pedimentos/imports)
|
||||
pedimentosImports: {
|
||||
upload: (
|
||||
|
||||
@@ -107,7 +107,6 @@ export interface Company {
|
||||
responsible_mother_last_name: string | null;
|
||||
responsible_rfc?: string | null;
|
||||
position?: string | null;
|
||||
has_express_line?: boolean;
|
||||
fiscal_deposit?: boolean;
|
||||
generate_barcodes_with_fiel?: boolean;
|
||||
is_service_company?: boolean;
|
||||
@@ -273,7 +272,6 @@ export interface CompanyCreate {
|
||||
responsible_mother_last_name?: string | null;
|
||||
responsible_rfc?: string | null;
|
||||
position?: string | null;
|
||||
has_express_line?: boolean;
|
||||
fiscal_deposit?: boolean;
|
||||
generate_barcodes_with_fiel?: boolean;
|
||||
is_service_company?: boolean;
|
||||
|
||||
@@ -1,37 +1,19 @@
|
||||
import { api } from '$lib/api';
|
||||
import type { ApiResponse } from '$lib/api';
|
||||
|
||||
// Interfaces
|
||||
/** List item shape returned by GET /v1/a76/us-tariff-fractions/ (SITAR-backed, read-only). */
|
||||
export interface USTariffFraction {
|
||||
id: number;
|
||||
code: string;
|
||||
prefix: string | null;
|
||||
type_code: string | null;
|
||||
ad_valorem: number | null;
|
||||
fixed_cost: number | null;
|
||||
unit_of_measure: string | null;
|
||||
description: string | null;
|
||||
created_at: string | null;
|
||||
updated_at: string | null;
|
||||
}
|
||||
|
||||
export interface USTariffFractionCreate {
|
||||
code: string;
|
||||
prefix?: string | null;
|
||||
type_code?: string | null;
|
||||
ad_valorem?: number | null;
|
||||
fixed_cost?: number | null;
|
||||
unit_of_measure?: string | null;
|
||||
description?: string | null;
|
||||
}
|
||||
|
||||
export interface USTariffFractionUpdate {
|
||||
fraction?: string | null;
|
||||
prefix?: string | null;
|
||||
type_code?: string | null;
|
||||
ad_valorem?: number | null;
|
||||
fixed_cost?: number | null;
|
||||
unit_of_measure?: string | null;
|
||||
description?: string | null;
|
||||
created_at?: string;
|
||||
updated_at?: string;
|
||||
}
|
||||
|
||||
export interface USTariffFractionListResponse {
|
||||
@@ -42,47 +24,20 @@ export interface USTariffFractionListResponse {
|
||||
pages: number;
|
||||
}
|
||||
|
||||
// API Functions
|
||||
/** Paginated list from SITAR (same data as tariff-fractions?catalog=american). */
|
||||
export async function getUSTariffFractions(
|
||||
page = 1,
|
||||
pageSize = 50,
|
||||
companyId: number,
|
||||
filters: Record<string, any> = {}
|
||||
filters: Record<string, string | number | boolean> = {}
|
||||
): Promise<ApiResponse<USTariffFractionListResponse>> {
|
||||
const queryParams = new URLSearchParams({
|
||||
page: page.toString(),
|
||||
page_size: pageSize.toString(),
|
||||
company_id: companyId.toString(),
|
||||
...filters
|
||||
...Object.fromEntries(
|
||||
Object.entries(filters).map(([k, v]) => [k, String(v)])
|
||||
)
|
||||
});
|
||||
return await api.get(`/v1/a76/us-tariff-fractions/?${queryParams.toString()}`);
|
||||
}
|
||||
|
||||
export async function getUSTariffFractionById(
|
||||
id: number,
|
||||
companyId: number
|
||||
): Promise<ApiResponse<USTariffFraction>> {
|
||||
return await api.get(`/v1/a76/us-tariff-fractions/${id}/?company_id=${companyId}`);
|
||||
}
|
||||
|
||||
export async function createUSTariffFraction(
|
||||
data: USTariffFractionCreate,
|
||||
companyId: number
|
||||
): Promise<ApiResponse<USTariffFraction>> {
|
||||
return await api.post(`/v1/a76/us-tariff-fractions/?company_id=${companyId}`, data);
|
||||
}
|
||||
|
||||
export async function updateUSTariffFraction(
|
||||
id: number,
|
||||
data: USTariffFractionUpdate,
|
||||
companyId: number
|
||||
): Promise<ApiResponse<USTariffFraction>> {
|
||||
return await api.put(`/v1/a76/us-tariff-fractions/${id}/?company_id=${companyId}`, data);
|
||||
}
|
||||
|
||||
export async function deleteUSTariffFraction(
|
||||
id: number,
|
||||
companyId: number
|
||||
): Promise<ApiResponse<void>> {
|
||||
return await api.delete(`/v1/a76/us-tariff-fractions/${id}/?company_id=${companyId}`);
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ export interface Transporter {
|
||||
ftp_password?: string;
|
||||
ftp_directory?: string;
|
||||
filler_code?: string;
|
||||
has_express_line?: boolean;
|
||||
company_id?: number | string;
|
||||
tenant_id?: number | string;
|
||||
}
|
||||
|
||||
@@ -40,7 +40,6 @@
|
||||
customs_brokers: 'Agentes aduanales',
|
||||
clients_providers: 'Clientes / proveedores',
|
||||
exchange_rates: 'Tipos de cambio',
|
||||
american_fractions: 'Fracciones arancelarias US',
|
||||
pedimentos: 'Pedimentos',
|
||||
material_classes: 'Clases de material',
|
||||
vehicles: 'Vehículos',
|
||||
|
||||
@@ -37,7 +37,6 @@
|
||||
| 'customs_brokers'
|
||||
| 'clients_providers'
|
||||
| 'exchange_rate'
|
||||
| 'us_tariff_fractions'
|
||||
| 'pedimentos'
|
||||
| 'classes'
|
||||
| 'vehicles'
|
||||
@@ -139,9 +138,6 @@
|
||||
case 'exchange_rate':
|
||||
blob = await api.exchangeRateImports.downloadScanErrorsCsv(jobId);
|
||||
break;
|
||||
case 'us_tariff_fractions':
|
||||
blob = await api.americanFractionImports.downloadScanErrorsCsv(jobId);
|
||||
break;
|
||||
case 'pedimentos':
|
||||
blob = await api.pedimentosImports.downloadScanErrorsCsv(jobId);
|
||||
break;
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
import * as Tabs from "$lib/components/ui/tabs";
|
||||
import { Switch } from "$lib/components/ui/switch";
|
||||
import { createCompany, updateCompany, type Company } from "$lib/api/dashboard/a76/general_catalogs/company";
|
||||
import { companyStore } from "$lib/stores/company.svelte";
|
||||
|
||||
let {
|
||||
open = $bindable(false),
|
||||
@@ -43,7 +44,6 @@
|
||||
|
||||
// Configuración / Operativo
|
||||
manufacturer_id: '',
|
||||
has_express_line: false,
|
||||
is_service_company: false,
|
||||
order_format_type: '',
|
||||
|
||||
@@ -76,7 +76,6 @@
|
||||
position: item.position || '',
|
||||
|
||||
manufacturer_id: item.manufacturer_id || '',
|
||||
has_express_line: item.has_express_line || false,
|
||||
is_service_company: item.is_service_company || false,
|
||||
order_format_type: item.order_format_type || '',
|
||||
|
||||
@@ -89,7 +88,7 @@
|
||||
name: '', rfc: '', curp: '', main_activity: '',
|
||||
program: '', program_number: '', prosec: 0, prosec_authorization: '',
|
||||
responsible_name: '', responsible_last_name: '', responsible_mother_last_name: '', responsible_rfc: '', position: '',
|
||||
manufacturer_id: '', has_express_line: false, is_service_company: false, order_format_type: '',
|
||||
manufacturer_id: '', is_service_company: false, order_format_type: '',
|
||||
ctpat_svi: '', trusted_exporter_number: ''
|
||||
};
|
||||
}
|
||||
@@ -124,7 +123,6 @@
|
||||
position: formData.position.trim() || null,
|
||||
|
||||
manufacturer_id: formData.manufacturer_id.trim() || null,
|
||||
has_express_line: formData.has_express_line,
|
||||
is_service_company: formData.is_service_company,
|
||||
order_format_type: formData.order_format_type.trim() || null,
|
||||
|
||||
@@ -143,6 +141,7 @@
|
||||
throw new Error(response.error);
|
||||
}
|
||||
|
||||
await companyStore.loadCompanies();
|
||||
open = false;
|
||||
if (onSuccess) onSuccess();
|
||||
} catch (e) {
|
||||
@@ -249,10 +248,6 @@
|
||||
|
||||
<Tabs.Content value="config" class="space-y-4 py-4">
|
||||
<div class="grid grid-cols-2 gap-6">
|
||||
<div class="flex items-center space-x-2">
|
||||
<Switch id="express" bind:checked={formData.has_express_line} />
|
||||
<Label for="express">Carril Exprés (OEA/NEEC)</Label>
|
||||
</div>
|
||||
<div class="flex items-center space-x-2">
|
||||
<Switch id="service" bind:checked={formData.is_service_company} />
|
||||
<Label for="service">Es Empresa de Servicios</Label>
|
||||
|
||||
@@ -14,10 +14,6 @@
|
||||
getTariffFractions,
|
||||
type TariffFraction
|
||||
} from '$lib/api/dashboard/a76/general_catalogs/tariff-fractions';
|
||||
import {
|
||||
getUSTariffFractions,
|
||||
type USTariffFraction
|
||||
} from '$lib/api/dashboard/a76/general_catalogs/us-tariff-fractions';
|
||||
import {
|
||||
getDepreciationCatalog,
|
||||
type DepreciationCatalog
|
||||
@@ -203,7 +199,7 @@
|
||||
formData.import_tariff_type = (fraction.umt ?? '') as string;
|
||||
showFractionDialog = false;
|
||||
}
|
||||
let usTariffFractions = $state<USTariffFraction[]>([]);
|
||||
let usTariffFractions = $state<TariffFraction[]>([]);
|
||||
let searchUSFraction = $state('');
|
||||
let currentUSPage = $state(1);
|
||||
let totalUSFractions = $state(0);
|
||||
@@ -392,10 +388,11 @@
|
||||
|
||||
isLoadingUSFractions = true;
|
||||
try {
|
||||
const filters = search ? { search } : {};
|
||||
const filters: Record<string, string> = { catalog: 'american' };
|
||||
if (search?.trim()) filters.search = search.trim();
|
||||
const pageSize = 100;
|
||||
|
||||
const response = await getUSTariffFractions(page, pageSize, companyId, filters);
|
||||
const response = await getTariffFractions(page, pageSize, companyId, filters);
|
||||
|
||||
if (response.data) {
|
||||
if (page === 1) {
|
||||
@@ -415,10 +412,16 @@
|
||||
}
|
||||
}
|
||||
|
||||
function selectUSFraction(fraction: USTariffFraction) {
|
||||
formData.us_fraction = fraction.code;
|
||||
formData.us_fraction_ad_valorem = fraction.ad_valorem?.toString() || '0.00';
|
||||
formData.us_fraction_fixed_rate = fraction.fixed_cost?.toString() || '0.00000000';
|
||||
function selectUSFraction(fraction: TariffFraction) {
|
||||
formData.us_fraction = fraction.code || '';
|
||||
const advRaw = fraction.adv_impo;
|
||||
let advNum = 0;
|
||||
if (advRaw != null && String(advRaw).trim() !== '') {
|
||||
const n = parseFloat(String(advRaw).replace('%', '').trim());
|
||||
if (!Number.isNaN(n)) advNum = n;
|
||||
}
|
||||
formData.us_fraction_ad_valorem = advNum ? String(advNum) : '0.00';
|
||||
formData.us_fraction_fixed_rate = '0.00000000';
|
||||
// Actualizar tarifa de exportación
|
||||
formData.export_tariff_code = fraction.code || '';
|
||||
formData.export_tariff_type = 'HTS'; // Harmonized Tariff Schedule
|
||||
@@ -1041,10 +1044,10 @@
|
||||
class="cursor-pointer border-b transition-colors hover:bg-gray-100 dark:hover:bg-gray-700"
|
||||
onclick={() => selectUSFraction(fraction)}
|
||||
>
|
||||
<td class="px-4 py-2 whitespace-nowrap">{fraction.code}</td>
|
||||
<td class="px-4 py-2 whitespace-nowrap">{fraction.prefix || ''}</td>
|
||||
<td class="px-4 py-2 whitespace-nowrap">{fraction.ad_valorem || '0.00'}</td>
|
||||
<td class="px-4 py-2 whitespace-nowrap">{fraction.fixed_cost || '0.00'}</td>
|
||||
<td class="px-4 py-2 whitespace-nowrap">{fraction.fraction || fraction.code}</td>
|
||||
<td class="px-4 py-2 whitespace-nowrap">{fraction.code || '—'}</td>
|
||||
<td class="px-4 py-2 whitespace-nowrap">{fraction.adv_impo ?? '—'}</td>
|
||||
<td class="px-4 py-2 whitespace-nowrap">{fraction.adv_expo ?? '—'}</td>
|
||||
<td class="px-4 py-2">{fraction.description || ''}</td>
|
||||
</tr>
|
||||
{:else}
|
||||
|
||||
@@ -5,7 +5,10 @@
|
||||
import * as Table from "$lib/components/ui/table";
|
||||
import { toast } from "svelte-sonner";
|
||||
import { Search, Loader2, Hash } from "lucide-svelte";
|
||||
import { getUSTariffFractions, type USTariffFraction } from "$lib/api/dashboard/a76/general_catalogs/us-tariff-fractions";
|
||||
import {
|
||||
getTariffFractions,
|
||||
type TariffFraction
|
||||
} from "$lib/api/dashboard/a76/general_catalogs/tariff-fractions";
|
||||
import { companyStore } from "$lib/stores/company.svelte";
|
||||
import { m } from '$lib/i18n/messages';
|
||||
|
||||
@@ -15,11 +18,11 @@
|
||||
onSelect
|
||||
}: {
|
||||
open: boolean,
|
||||
onSelect: (item: USTariffFraction) => void
|
||||
onSelect: (item: TariffFraction) => void
|
||||
} = $props();
|
||||
|
||||
// --- ESTADO ---
|
||||
let items = $state<USTariffFraction[]>([]);
|
||||
let items = $state<TariffFraction[]>([]);
|
||||
let loading = $state(false);
|
||||
let searchTerm = $state("");
|
||||
let loadedForCompanyId = $state<number | null>(null);
|
||||
@@ -30,8 +33,8 @@
|
||||
return (code || '').replace(/[.\s-]/g, '');
|
||||
}
|
||||
|
||||
function isEligibleAmericanFraction(item: USTariffFraction) {
|
||||
const normalizedCode = normalizeAmericanFractionCode(item.code || '');
|
||||
function isEligibleAmericanFraction(item: TariffFraction) {
|
||||
const normalizedCode = normalizeAmericanFractionCode(item.code || item.fraction || '');
|
||||
return /^\d{8}$/.test(normalizedCode) || /^\d{10}$/.test(normalizedCode);
|
||||
}
|
||||
|
||||
@@ -70,7 +73,9 @@
|
||||
|
||||
loading = true;
|
||||
try {
|
||||
const response = await getUSTariffFractions(1, 1000, companyId);
|
||||
const response = await getTariffFractions(1, 1000, companyId, {
|
||||
catalog: 'american'
|
||||
});
|
||||
|
||||
if (response.error) {
|
||||
console.error("Error al cargar fracciones americanas:", response.error);
|
||||
@@ -97,7 +102,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
function handleSelect(item: USTariffFraction) {
|
||||
function handleSelect(item: TariffFraction) {
|
||||
if (onSelect) onSelect(item);
|
||||
open = false;
|
||||
}
|
||||
@@ -150,7 +155,7 @@
|
||||
<div class="flex items-center gap-2">
|
||||
<Hash class="h-3 w-3 text-blue-500" />
|
||||
<span class="font-mono font-bold text-blue-600 dark:text-blue-400">
|
||||
{item.code}
|
||||
{item.fraction || item.code}
|
||||
</span>
|
||||
</div>
|
||||
</Table.Cell>
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
import type { Invoice } from '$lib/api/dashboard/a76/invoices';
|
||||
import PackageDialog from './package-dialog.svelte';
|
||||
import USFractionSelectorDialog from '$lib/components/dashboard/goods/modales/us-fraction-selector-dialog.svelte';
|
||||
import type { TariffFraction } from '$lib/api/dashboard/a76/general_catalogs/tariff-fractions';
|
||||
import { m } from '$lib/i18n/messages';
|
||||
|
||||
let {
|
||||
@@ -118,11 +119,12 @@
|
||||
quantities.package_description = pkg.description_es || pkg.description_en || pkg.key;
|
||||
}
|
||||
|
||||
function handleAmericanFractionSelect(fraction: any) {
|
||||
function handleAmericanFractionSelect(fraction: TariffFraction) {
|
||||
customs.american_fraction = fraction.code || '';
|
||||
(customs as any).american_fraction_description = fraction.description || '';
|
||||
if (fraction.ad_valorem !== null && fraction.ad_valorem !== undefined) {
|
||||
customs.advalorem_american = fraction.ad_valorem;
|
||||
if (fraction.adv_impo != null && String(fraction.adv_impo).trim() !== '') {
|
||||
const n = parseFloat(String(fraction.adv_impo).replace('%', '').trim());
|
||||
if (!Number.isNaN(n)) customs.advalorem_american = n;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
import * as Dialog from '$lib/components/ui/dialog';
|
||||
import { Input } from '$lib/components/ui/input';
|
||||
import { Label } from '$lib/components/ui/label';
|
||||
import { Switch } from '$lib/components/ui/switch';
|
||||
import * as Select from '$lib/components/ui/select';
|
||||
import { transportersApi, type Transporter } from '$lib/api/dashboard/a76/transporters';
|
||||
import { countriesApi, type Country } from '$lib/api/dashboard/reference_data/countries';
|
||||
@@ -45,7 +46,8 @@
|
||||
ftp_user: '',
|
||||
ftp_password: '',
|
||||
ftp_directory: '',
|
||||
filler_code: ''
|
||||
filler_code: '',
|
||||
has_express_line: false
|
||||
});
|
||||
|
||||
let loading = $state(false);
|
||||
@@ -99,7 +101,8 @@
|
||||
ftp_user: '',
|
||||
ftp_password: '',
|
||||
ftp_directory: '',
|
||||
filler_code: ''
|
||||
filler_code: '',
|
||||
has_express_line: false
|
||||
};
|
||||
}
|
||||
|
||||
@@ -110,7 +113,7 @@
|
||||
return;
|
||||
}
|
||||
if (item) {
|
||||
formData = { ...item };
|
||||
formData = { ...item, has_express_line: item.has_express_line ?? false };
|
||||
} else {
|
||||
formData = emptyTransporterForm();
|
||||
}
|
||||
@@ -284,6 +287,11 @@
|
||||
<Label for="filler_code">Código Relleno</Label>
|
||||
<Input id="filler_code" bind:value={formData.filler_code} maxlength={20} />
|
||||
</div>
|
||||
|
||||
<div class="flex items-center justify-between gap-3 rounded-lg border p-4">
|
||||
<Label for="has_express_line" class="text-sm font-medium">Carril express</Label>
|
||||
<Switch id="has_express_line" bind:checked={formData.has_express_line} />
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Dirección -->
|
||||
|
||||
@@ -318,10 +318,6 @@ export function getSidebarData(): SidebarData {
|
||||
title: m["sidebar.fractions.sitar_us"](),
|
||||
url: "/dashboard/general_catalogs/tariff-fractions/us",
|
||||
},
|
||||
{
|
||||
title: m["sidebar.fractions.american"](),
|
||||
url: "/dashboard/general_catalogs/tariff-fractions/american",
|
||||
},
|
||||
{
|
||||
title: m["sidebar.fractions.canadian"](),
|
||||
url: "/dashboard/general_catalogs/tariff-fractions/canadian",
|
||||
|
||||
@@ -8,7 +8,6 @@ import {
|
||||
Plane,
|
||||
Package,
|
||||
Briefcase,
|
||||
Globe,
|
||||
CreditCard,
|
||||
DollarSign,
|
||||
Calendar,
|
||||
@@ -227,14 +226,6 @@ export const catalogosConfig: CsvUploadItem[] = [
|
||||
templateId: 'exchange_rates',
|
||||
layoutModule: 'layouts_csv/exchange_rate'
|
||||
},
|
||||
{
|
||||
id: 'american_fractions',
|
||||
title: 'Fracc. Ame.',
|
||||
icon: Globe,
|
||||
modelTarget: 'AmericanFraction',
|
||||
templateId: 'american_fractions',
|
||||
layoutModule: 'layouts_csv/us_tariff_fractions'
|
||||
},
|
||||
{
|
||||
id: 'material_classes',
|
||||
title: 'Clases de Materiales',
|
||||
|
||||
@@ -5,7 +5,6 @@ const VALID_PROFILES: CsvImportProfile[] = [
|
||||
'customs_brokers',
|
||||
'clients_providers',
|
||||
'exchange_rates',
|
||||
'american_fractions',
|
||||
'pedimentos',
|
||||
'material_classes',
|
||||
'vehicles',
|
||||
|
||||
@@ -9,7 +9,6 @@ export type CsvImportProfile =
|
||||
| 'customs_brokers'
|
||||
| 'clients_providers'
|
||||
| 'exchange_rates'
|
||||
| 'american_fractions'
|
||||
| 'pedimentos'
|
||||
| 'material_classes'
|
||||
| 'vehicles'
|
||||
@@ -88,7 +87,6 @@ function isCsvImportProfile(p: unknown): p is CsvImportProfile {
|
||||
'customs_brokers',
|
||||
'clients_providers',
|
||||
'exchange_rates',
|
||||
'american_fractions',
|
||||
'pedimentos',
|
||||
'material_classes',
|
||||
'vehicles',
|
||||
|
||||
@@ -15,8 +15,6 @@ export function fetchCsvImportStatus(
|
||||
return api.clientProviderImports.status(jobId);
|
||||
case 'exchange_rates':
|
||||
return api.exchangeRateImports.status(jobId);
|
||||
case 'american_fractions':
|
||||
return api.americanFractionImports.status(jobId);
|
||||
case 'pedimentos':
|
||||
return api.pedimentosImports.status(jobId);
|
||||
case 'material_classes':
|
||||
|
||||
Reference in New Issue
Block a user