feat(api): add Units of Measure API client with CRUD operations
- Implemented interfaces for UnitOfMeasure, UnitOfMeasureListResponse, CreateUnitOfMeasureData, and UpdateUnitOfMeasureData. - Added API methods for listing, retrieving, creating, updating, and deleting units of measure. - Included pagination support for the list method.
This commit is contained in:
101
frontend/src/lib/api/dashboard/a76/units_of_measure.ts
Normal file
101
frontend/src/lib/api/dashboard/a76/units_of_measure.ts
Normal file
@@ -0,0 +1,101 @@
|
||||
/**
|
||||
* API Client para Units of Measure
|
||||
* Gestiona las operaciones CRUD para unidades de medida
|
||||
*/
|
||||
import { api } from '$lib/api';
|
||||
|
||||
export interface UnitOfMeasure {
|
||||
id: number;
|
||||
code: string;
|
||||
description: string | null;
|
||||
description_en: string | null;
|
||||
customs_code: string | null;
|
||||
american_code: string | null;
|
||||
ace_code: string | null;
|
||||
oma_code: string | null;
|
||||
}
|
||||
|
||||
export interface UnitOfMeasureListResponse {
|
||||
items: UnitOfMeasure[];
|
||||
total: number;
|
||||
page: number;
|
||||
page_size: number;
|
||||
}
|
||||
|
||||
export interface CreateUnitOfMeasureData {
|
||||
code: string;
|
||||
description?: string | null;
|
||||
description_en?: string | null;
|
||||
customs_code?: string | null;
|
||||
american_code?: string | null;
|
||||
ace_code?: string | null;
|
||||
oma_code?: string | null;
|
||||
}
|
||||
|
||||
export interface UpdateUnitOfMeasureData {
|
||||
code?: string;
|
||||
description?: string | null;
|
||||
description_en?: string | null;
|
||||
customs_code?: string | null;
|
||||
american_code?: string | null;
|
||||
ace_code?: string | null;
|
||||
oma_code?: string | null;
|
||||
}
|
||||
|
||||
/**
|
||||
* API para Units of Measure
|
||||
*/
|
||||
export const unitsOfMeasureApi = {
|
||||
/**
|
||||
* Lista todas las unidades de medida con paginación
|
||||
* @param companyId - ID de la compañía
|
||||
* @param page - Número de página (por defecto 1)
|
||||
* @param pageSize - Tamaño de página (por defecto 50)
|
||||
*/
|
||||
list: (companyId: number, page = 1, pageSize = 50) => {
|
||||
const params = new URLSearchParams({
|
||||
company_id: companyId.toString(),
|
||||
page: page.toString(),
|
||||
page_size: pageSize.toString()
|
||||
});
|
||||
return api.get<UnitOfMeasureListResponse>(
|
||||
`/v1/a76/units-of-measure?${params.toString()}`
|
||||
);
|
||||
},
|
||||
|
||||
/**
|
||||
* Obtiene una unidad de medida por ID
|
||||
* @param companyId - ID de la compañía
|
||||
* @param id - ID de la unidad de medida
|
||||
*/
|
||||
get: (companyId: number, id: number) =>
|
||||
api.get<UnitOfMeasure>(`/v1/a76/units-of-measure/${id}?company_id=${companyId}`),
|
||||
|
||||
/**
|
||||
* Crea una nueva unidad de medida
|
||||
* @param companyId - ID de la compañía
|
||||
* @param data - Datos de la unidad de medida a crear
|
||||
*/
|
||||
create: (companyId: number, data: CreateUnitOfMeasureData) =>
|
||||
api.post<UnitOfMeasure>(`/v1/a76/units-of-measure?company_id=${companyId}`, data),
|
||||
|
||||
/**
|
||||
* Actualiza una unidad de medida existente
|
||||
* @param companyId - ID de la compañía
|
||||
* @param id - ID de la unidad de medida a actualizar
|
||||
* @param data - Datos a actualizar
|
||||
*/
|
||||
update: (companyId: number, id: number, data: UpdateUnitOfMeasureData) =>
|
||||
api.put<UnitOfMeasure>(
|
||||
`/v1/a76/units-of-measure/${id}?company_id=${companyId}`,
|
||||
data
|
||||
),
|
||||
|
||||
/**
|
||||
* Elimina una unidad de medida
|
||||
* @param companyId - ID de la compañía
|
||||
* @param id - ID de la unidad de medida a eliminar
|
||||
*/
|
||||
delete: (companyId: number, id: number) =>
|
||||
api.delete(`/v1/a76/units-of-measure/${id}?company_id=${companyId}`)
|
||||
};
|
||||
@@ -48,7 +48,7 @@ export const materialTypesApi = {
|
||||
params.append('type', type);
|
||||
}
|
||||
return api.get<MaterialTypeListResponse>(
|
||||
`/v1/public/refrence_data/material-types?${params.toString()}`
|
||||
`/v1/public/refrence_data/material-types/?${params.toString()}`
|
||||
);
|
||||
},
|
||||
|
||||
@@ -56,14 +56,14 @@ export const materialTypesApi = {
|
||||
* Obtiene un tipo de material por key
|
||||
* @param key - Clave del tipo de material
|
||||
*/
|
||||
get: (key: string) => api.get<MaterialType>(`/v1/public/refrence_data/material-types/${key}`),
|
||||
get: (key: string) => api.get<MaterialType>(`/v1/public/refrence_data/material-types/${key}/`),
|
||||
|
||||
/**
|
||||
* Crea un nuevo tipo de material
|
||||
* @param data - Datos del tipo de material a crear
|
||||
*/
|
||||
create: (data: CreateMaterialTypeData) =>
|
||||
api.post<MaterialType>('/v1/public/refrence_data/material-types', data),
|
||||
api.post<MaterialType>('/v1/public/refrence_data/material-types/', data),
|
||||
|
||||
/**
|
||||
* Actualiza un tipo de material existente
|
||||
@@ -71,11 +71,11 @@ export const materialTypesApi = {
|
||||
* @param data - Datos a actualizar
|
||||
*/
|
||||
update: (key: string, data: UpdateMaterialTypeData) =>
|
||||
api.put<MaterialType>(`/v1/public/refrence_data/material-types/${key}`, data),
|
||||
api.put<MaterialType>(`/v1/public/refrence_data/material-types/${key}/`, data),
|
||||
|
||||
/**
|
||||
* Elimina un tipo de material
|
||||
* @param key - Clave del tipo de material a eliminar
|
||||
*/
|
||||
delete: (key: string) => api.delete(`/v1/public/refrence_data/material-types/${key}`)
|
||||
delete: (key: string) => api.delete(`/v1/public/refrence_data/material-types/${key}/`)
|
||||
};
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
import * as Select from "$lib/components/ui/select";
|
||||
import { classesApi, type A76Class, type A76ClassCreate, type A76ClassUpdate } from "$lib/api/dashboard/a76/classes";
|
||||
import { materialTypesApi, type MaterialType } from "$lib/api/dashboard/refrence_data/material_types";
|
||||
import { unitsOfMeasureApi, type UnitOfMeasure } from "$lib/api/dashboard/a76/units_of_measure";
|
||||
import { clientsProvidersApi, type ClientProvider } from "$lib/api/dashboard/a76/clients-providers";
|
||||
import { companyStore } from "$lib/stores/company.svelte";
|
||||
import { onMount } from 'svelte';
|
||||
@@ -43,6 +44,8 @@
|
||||
let error = $state<string | null>(null);
|
||||
let materialTypes = $state<MaterialType[]>([]);
|
||||
let loadingMaterialTypes = $state(false);
|
||||
let unitsOfMeasure = $state<UnitOfMeasure[]>([]);
|
||||
let loadingUnitsOfMeasure = $state(false);
|
||||
let clients = $state<ClientProvider[]>([]);
|
||||
let loadingClients = $state(false);
|
||||
|
||||
@@ -51,15 +54,15 @@
|
||||
let selectedMaterialValue = $state<string>('');
|
||||
let selectedPhysicalReviewValue = $state<number>(0);
|
||||
|
||||
// Cargar tipos de materiales y clientes al montar
|
||||
// Cargar tipos de materiales, unidades de medida y clientes al montar
|
||||
onMount(async () => {
|
||||
const companyId = companyStore.activeCompany?.id;
|
||||
if (!companyId) return;
|
||||
|
||||
// Cargar tipos de materiales
|
||||
// Cargar tipos de materiales (solo ACTIVO FIJO)
|
||||
loadingMaterialTypes = true;
|
||||
try {
|
||||
const response = await materialTypesApi.list(1, 100);
|
||||
const response = await materialTypesApi.list(1, 100, 'ACTIVO FIJO');
|
||||
if (response.data) {
|
||||
materialTypes = response.data.items;
|
||||
}
|
||||
@@ -69,6 +72,19 @@
|
||||
loadingMaterialTypes = false;
|
||||
}
|
||||
|
||||
// Cargar unidades de medida
|
||||
loadingUnitsOfMeasure = true;
|
||||
try {
|
||||
const response = await unitsOfMeasureApi.list(companyId, 1, 100);
|
||||
if (response.data) {
|
||||
unitsOfMeasure = response.data.items;
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('Error loading units of measure:', e);
|
||||
} finally {
|
||||
loadingUnitsOfMeasure = false;
|
||||
}
|
||||
|
||||
// Cargar clientes
|
||||
loadingClients = true;
|
||||
try {
|
||||
@@ -216,31 +232,9 @@
|
||||
}
|
||||
}
|
||||
|
||||
// Opciones de unidades de medida (puedes expandir esto)
|
||||
const unitOptions = [
|
||||
{ value: 'KG', label: 'Kilogramos (KG)' },
|
||||
{ value: 'LB', label: 'Libras (LB)' },
|
||||
{ value: 'MT', label: 'Metros (MT)' },
|
||||
{ value: 'PZ', label: 'Piezas (PZ)' },
|
||||
{ value: 'LT', label: 'Litros (LT)' },
|
||||
{ value: 'M3', label: 'Metros Cúbicos (M3)' },
|
||||
{ value: 'TON', label: 'Toneladas (TON)' }
|
||||
];
|
||||
|
||||
// Funciones para obtener valores seleccionados
|
||||
function getSelectedMaterialType() {
|
||||
if (!formData.material_key) return null;
|
||||
const found = materialTypes.find(mt => mt.key === formData.material_key);
|
||||
return found ? { value: found.key, label: `${found.key} - ${found.description}` } : null;
|
||||
}
|
||||
|
||||
function getSelectedUnit() {
|
||||
return unitOptions.find(opt => opt.value === formData.unit_of_measure) || unitOptions[0];
|
||||
}
|
||||
|
||||
function getSelectedPhysicalReview() {
|
||||
return { value: formData.physical_review, label: formData.physical_review === 1 ? 'Sí' : 'No' };
|
||||
}
|
||||
</script>
|
||||
|
||||
<Dialog.Root bind:open onOpenChange={handleOpenChange}>
|
||||
@@ -409,18 +403,34 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Unidad de Medida -->
|
||||
<!-- Unidad de Medida Comercial -->
|
||||
<div class="space-y-2">
|
||||
<Label for="unit_of_measure" class="required">Unidad de Medida</Label>
|
||||
<select
|
||||
bind:value={formData.unit_of_measure}
|
||||
disabled={loading}
|
||||
class="border-input bg-background selection:bg-primary dark:bg-input/30 selection:text-primary-foreground ring-offset-background placeholder:text-muted-foreground shadow-xs flex h-9 w-full min-w-0 rounded-md border px-3 py-1 text-base outline-none transition-[color,box-shadow] disabled:cursor-not-allowed disabled:opacity-50 md:text-sm focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive"
|
||||
>
|
||||
{#each unitOptions as unit}
|
||||
<option value={unit.value}>{unit.label}</option>
|
||||
{/each}
|
||||
</select>
|
||||
<Label for="unit_of_measure" class="required">U.M. Comercial</Label>
|
||||
{#if loadingUnitsOfMeasure}
|
||||
<div class="flex items-center gap-2 text-sm text-muted-foreground">
|
||||
<div class="h-4 w-4 animate-spin rounded-full border-2 border-primary border-t-transparent"></div>
|
||||
Cargando unidades de medida...
|
||||
</div>
|
||||
{:else if unitsOfMeasure.length > 0}
|
||||
<select
|
||||
bind:value={formData.unit_of_measure}
|
||||
disabled={loading}
|
||||
class="border-input bg-background selection:bg-primary dark:bg-input/30 selection:text-primary-foreground ring-offset-background placeholder:text-muted-foreground shadow-xs flex h-9 w-full min-w-0 rounded-md border px-3 py-1 text-base outline-none transition-[color,box-shadow] disabled:cursor-not-allowed disabled:opacity-50 md:text-sm focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive"
|
||||
>
|
||||
{#each unitsOfMeasure as unit}
|
||||
<option value={unit.code}>
|
||||
{unit.code}{unit.description ? ` - ${unit.description}` : ''}
|
||||
</option>
|
||||
{/each}
|
||||
</select>
|
||||
{:else}
|
||||
<Input
|
||||
id="unit_of_measure"
|
||||
bind:value={formData.unit_of_measure}
|
||||
placeholder="No hay unidades de medida disponibles"
|
||||
disabled={true}
|
||||
/>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<!-- Revisión Física -->
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
import { Folder } from 'lucide-svelte';
|
||||
import { toast } from 'svelte-sonner';
|
||||
import { materialTypesApi, type MaterialType } from '$lib/api/dashboard/refrence_data/material_types';
|
||||
import { unitsOfMeasureApi } from '$lib/api/dashboard/a76/units_of_measure';
|
||||
import { 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 } from '$lib/api/dashboard/a76/general_catalogs/depreciation-catalog';
|
||||
@@ -33,14 +34,8 @@
|
||||
claveOMA: string;
|
||||
}
|
||||
|
||||
// Datos de unidades de medida
|
||||
const unitsOfMeasureData: UnitOfMeasure[] = [
|
||||
{ code: 'BARR', description: 'BARRIL', descriptionEnglish: 'BARREL', claveMexicana: '8', claveAmericana: 'BBL', claveACE: '', claveOMA: 'BLL' },
|
||||
{ code: 'BD FT', description: 'PIE TABLA', descriptionEnglish: 'BD FEET', claveMexicana: '5', claveAmericana: 'FT', claveACE: '', claveOMA: 'BFT' },
|
||||
{ code: 'BOLS', description: 'BOLSA', descriptionEnglish: 'BAG', claveMexicana: '6', claveAmericana: 'PCS', claveACE: '', claveOMA: 'BG' },
|
||||
{ code: 'KGS', description: 'KILOGRAMOS', descriptionEnglish: 'KGS', claveMexicana: '1', claveAmericana: 'KG2', claveACE: '', claveOMA: 'KGM' },
|
||||
{ code: 'PZA', description: 'PIEZA', descriptionEnglish: 'PCS', claveMexicana: '6', claveAmericana: 'PCS', claveACE: '', claveOMA: 'C62_1' },
|
||||
];
|
||||
// Datos de unidades de medida (se cargan desde el API)
|
||||
let unitsOfMeasureData: UnitOfMeasure[] = $state([]);
|
||||
|
||||
// Estado del formulario
|
||||
let formData = $state({
|
||||
@@ -195,6 +190,28 @@
|
||||
);
|
||||
|
||||
// Funciones
|
||||
async function loadUnitsOfMeasure() {
|
||||
if (unitsOfMeasureData.length > 0) return;
|
||||
try {
|
||||
const companyId = companyStore.activeCompany?.id;
|
||||
if (!companyId) return;
|
||||
const response = await unitsOfMeasureApi.list(companyId, 1, 100);
|
||||
if (response.data) {
|
||||
unitsOfMeasureData = response.data.items.map(item => ({
|
||||
code: item.code,
|
||||
description: item.description || '',
|
||||
descriptionEnglish: item.description_en || '',
|
||||
claveMexicana: item.customs_code || '',
|
||||
claveAmericana: item.american_code || '',
|
||||
claveACE: item.ace_code || '',
|
||||
claveOMA: item.oma_code || ''
|
||||
}));
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error cargando units of measure:', error);
|
||||
}
|
||||
}
|
||||
|
||||
async function openMaterialSearch() {
|
||||
showMaterialDialog = true;
|
||||
searchMaterial = '';
|
||||
@@ -202,7 +219,7 @@
|
||||
try {
|
||||
const companyId = companyStore.activeCompany?.id;
|
||||
if (!companyId) return;
|
||||
const response = await materialTypesApi.list(1, 1000);
|
||||
const response = await materialTypesApi.list(1, 100, 'ACTIVO FIJO');
|
||||
if (response.data) {
|
||||
materialTypes = response.data.items;
|
||||
}
|
||||
@@ -222,6 +239,7 @@
|
||||
async function openUnitOfMeasureSearch() {
|
||||
showUnitDialog = true;
|
||||
searchUnit = '';
|
||||
await loadUnitsOfMeasure();
|
||||
}
|
||||
|
||||
function selectUnit(unit: UnitOfMeasure) {
|
||||
|
||||
Reference in New Issue
Block a user