RF-CATALOG-004: Unidades de Medida (UoM)
Identificacion
| Campo |
Valor |
| ID |
RF-CATALOG-004 |
| Modulo |
MGN-005 Catalogs |
| Titulo |
Unidades de Medida (UoM) |
| Prioridad |
Media |
| Estado |
Draft |
| Fecha |
2025-12-05 |
Descripcion
El sistema debe permitir gestionar unidades de medida agrupadas por categorias, con factores de conversion entre unidades de la misma categoria.
Referencia Odoo:
uom.category (addons/uom/models/uom_uom.py)
uom.uom (mismo archivo)
Arquitectura
Por Tenant
A diferencia de paises y monedas, las unidades de medida son por tenant:
core_catalogs.uom_categories (tenant_id UUID NOT NULL)
core_catalogs.uom (tenant_id UUID NOT NULL)
Rationale: Cada tenant puede necesitar unidades personalizadas segun su industria.
Requisitos Funcionales
RF-CATALOG-004.1: Categorias de UoM
Las unidades se agrupan en categorias. Solo se pueden convertir unidades de la misma categoria.
| Campo |
Tipo |
Descripcion |
| id |
UUID |
Identificador unico |
| tenant_id |
FK |
Tenant propietario |
| name |
string |
Nombre de categoria |
| is_active |
boolean |
Disponible para uso |
Categorias por defecto (seed):
| Categoria |
Descripcion |
| Unit |
Unidades discretas (piezas, docenas) |
| Weight |
Peso (kg, g, lb, oz) |
| Volume |
Volumen (L, mL, gal) |
| Length |
Longitud (m, cm, ft, in) |
| Time |
Tiempo (hora, dia, semana) |
| Area |
Area (m2, ha, acre) |
RF-CATALOG-004.2: Unidades de Medida
| Campo |
Tipo |
Descripcion |
| id |
UUID |
Identificador unico |
| tenant_id |
FK |
Tenant propietario |
| category_id |
FK |
Categoria de UoM |
| name |
string |
Nombre de unidad |
| uom_type |
enum |
reference/bigger/smaller |
| factor |
decimal |
Factor de conversion |
| rounding |
decimal |
Precision de redondeo |
| is_active |
boolean |
Disponible para uso |
RF-CATALOG-004.3: Tipos de Unidad
Cada categoria tiene exactamente UNA unidad de referencia:
| Tipo |
Descripcion |
Factor |
reference |
Unidad base de la categoria |
1.0 |
bigger |
Mayor que la referencia |
< 1.0 |
smaller |
Menor que la referencia |
> 1.0 |
Ejemplo categoria "Weight":
| Unidad |
Tipo |
Factor |
Equivalencia |
| kg |
reference |
1.0 |
1 kg = 1 kg |
| g |
smaller |
1000 |
1 kg = 1000 g |
| lb |
bigger |
0.453592 |
1 lb = 0.453592 kg |
| oz |
smaller |
35.274 |
1 kg = 35.274 oz |
RF-CATALOG-004.4: Conversion de Unidades
El sistema debe proporcionar funciones de conversion:
// Convertir cantidad de una unidad a otra
convertUom(
quantity: number,
fromUom: UUID,
toUom: UUID
): number
// Redondear segun unidad
roundUom(quantity: number, uom: UUID): number
Formula de conversion:
quantity_to = quantity_from * (factor_from / factor_to)
Validacion: Solo se permite conversion entre unidades de la misma categoria.
RF-CATALOG-004.5: Constraints de Categoria
| Constraint |
Descripcion |
| Una referencia |
Exactamente 1 unidad reference por categoria |
| Factor referencia = 1 |
La unidad reference debe tener factor = 1.0 |
| Factor > 0 |
El factor de conversion debe ser positivo |
RF-CATALOG-004.6: Unidades Protegidas
Algunas unidades del seed no deben modificarse:
-- Unidades protegidas
is_protected BOOLEAN DEFAULT false
| Unidad |
Categoria |
Protegida |
Razon |
| pcs |
Unit |
Si |
Referencia universal |
| kg |
Weight |
Si |
SI standard |
| L |
Volume |
Si |
SI standard |
| m |
Length |
Si |
SI standard |
| hr |
Time |
Si |
Referencia de tiempo |
Operaciones CRUD
Listar Categorias
GET /api/v1/catalogs/uom-categories
Response:
{
"data": [
{ "id": "uuid", "name": "Unit", "uomCount": 3 },
{ "id": "uuid", "name": "Weight", "uomCount": 5 },
...
]
}
Listar Unidades por Categoria
GET /api/v1/catalogs/uom?categoryId=uuid-weight
Response:
{
"data": [
{
"id": "uuid",
"name": "kg",
"uomType": "reference",
"factor": 1.0,
"rounding": 0.001
},
{
"id": "uuid",
"name": "g",
"uomType": "smaller",
"factor": 1000,
"rounding": 1
}
]
}
Crear Unidad
POST /api/v1/catalogs/uom
{
"categoryId": "uuid-weight",
"name": "Tonelada",
"uomType": "bigger",
"factor": 0.001, // 1 ton = 0.001 kg^-1 = 1000 kg
"rounding": 0.001
}
Convertir Cantidad
GET /api/v1/catalogs/uom/convert?from=uuid-kg&to=uuid-lb&quantity=10
Response:
{
"from": { "uom": "kg", "quantity": 10 },
"to": { "uom": "lb", "quantity": 22.0462 },
"factor": 2.20462
}
Data Seed
Categoria: Unit
| Nombre |
Tipo |
Factor |
Rounding |
| pcs (Pieces) |
reference |
1 |
1 |
| dozen |
bigger |
0.0833 |
1 |
| pair |
bigger |
0.5 |
1 |
Categoria: Weight
| Nombre |
Tipo |
Factor |
Rounding |
| kg |
reference |
1 |
0.001 |
| g |
smaller |
1000 |
1 |
| lb |
bigger |
0.453592 |
0.01 |
| oz |
smaller |
35.274 |
0.01 |
| ton |
bigger |
0.001 |
0.001 |
Categoria: Volume
| Nombre |
Tipo |
Factor |
Rounding |
| L |
reference |
1 |
0.001 |
| mL |
smaller |
1000 |
1 |
| gal (US) |
bigger |
0.264172 |
0.001 |
| m3 |
bigger |
0.001 |
0.001 |
Categoria: Length
| Nombre |
Tipo |
Factor |
Rounding |
| m |
reference |
1 |
0.001 |
| cm |
smaller |
100 |
1 |
| ft |
bigger |
0.3048 |
0.01 |
| in |
smaller |
39.3701 |
0.1 |
Categoria: Time
| Nombre |
Tipo |
Factor |
Rounding |
| hour |
reference |
1 |
0.01 |
| day |
bigger |
0.0417 |
0.01 |
| week |
bigger |
0.00595 |
0.01 |
Reglas de Negocio
| ID |
Regla |
Severidad |
| BR-001 |
Una unidad reference por categoria |
Error |
| BR-002 |
Reference factor = 1.0 |
Error |
| BR-003 |
Factor > 0 |
Error |
| BR-004 |
Solo convertir misma categoria |
Error |
| BR-005 |
No eliminar unidad con productos |
Error |
| BR-006 |
No modificar unidades protegidas |
Error |
Casos de Prueba
| ID |
Escenario |
Resultado Esperado |
| TC-001 |
Crear categoria nueva |
Categoria creada |
| TC-002 |
Crear unidad reference |
Factor = 1.0 validado |
| TC-003 |
Crear segunda reference |
Error: ya existe |
| TC-004 |
Convertir kg a lb |
10 kg = 22.0462 lb |
| TC-005 |
Convertir kg a L (diferente categoria) |
Error |
| TC-006 |
Redondear 10.12345 kg (rounding=0.001) |
10.123 |
| TC-007 |
Eliminar unidad con productos |
Error |
Criterios de Aceptacion
Notas Tecnicas
Funcion de Conversion SQL
CREATE OR REPLACE FUNCTION core_catalogs.convert_uom(
p_quantity DECIMAL,
p_from_uom UUID,
p_to_uom UUID
) RETURNS DECIMAL AS $$
DECLARE
v_from_factor DECIMAL;
v_to_factor DECIMAL;
v_from_category UUID;
v_to_category UUID;
BEGIN
-- Obtener datos de origen
SELECT factor, category_id INTO v_from_factor, v_from_category
FROM core_catalogs.uom WHERE id = p_from_uom;
-- Obtener datos de destino
SELECT factor, category_id INTO v_to_factor, v_to_category
FROM core_catalogs.uom WHERE id = p_to_uom;
-- Validar misma categoria
IF v_from_category != v_to_category THEN
RAISE EXCEPTION 'Cannot convert between different UoM categories';
END IF;
-- Convertir
RETURN p_quantity * (v_from_factor / v_to_factor);
END;
$$ LANGUAGE plpgsql STABLE;
Historial
| Version |
Fecha |
Autor |
Cambios |
| 1.0 |
2025-12-05 |
System |
Creacion inicial |