feat: estructura base OpenSpec + Skills + arquitectura limpia Capacitor+Dextie
This commit is contained in:
25
packages/core/src/__tests__/cuadreRules.test.ts
Normal file
25
packages/core/src/__tests__/cuadreRules.test.ts
Normal file
@@ -0,0 +1,25 @@
|
||||
import { describe, it, expect } from 'vitest';
|
||||
import { calcularSaldoEsperadoEfectivo, calcularDescuadreEfectivo, calcularTotalVentas, validateAjusteMotivo } from '../rules/cuadreRules';
|
||||
|
||||
describe('cuadreRules', () => {
|
||||
it('calcula saldo esperado en efectivo', () => {
|
||||
expect(calcularSaldoEsperadoEfectivo(10000, 5000, 2000)).toBe(13000);
|
||||
});
|
||||
|
||||
it('calcula descuadre en efectivo', () => {
|
||||
expect(calcularDescuadreEfectivo(13000, 12500)).toBe(-500);
|
||||
});
|
||||
|
||||
it('calcula total de ventas', () => {
|
||||
expect(calcularTotalVentas(5000, 3000)).toBe(8000);
|
||||
});
|
||||
|
||||
it('lanza error si ajuste sin motivo', () => {
|
||||
expect(() => validateAjusteMotivo('')).toThrow('El ajuste debe tener un motivo obligatorio');
|
||||
expect(() => validateAjusteMotivo(' ')).toThrow('El ajuste debe tener un motivo obligatorio');
|
||||
});
|
||||
|
||||
it('acepta ajuste con motivo', () => {
|
||||
expect(() => validateAjusteMotivo('Corrección de inventario')).not.toThrow();
|
||||
});
|
||||
});
|
||||
11
packages/core/src/entities/Ajuste.ts
Normal file
11
packages/core/src/entities/Ajuste.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
export interface Ajuste {
|
||||
id: string;
|
||||
fecha: Date;
|
||||
productoId: string;
|
||||
cantidadAnterior: number;
|
||||
cantidadNueva: number;
|
||||
diferencia: number;
|
||||
motivo: string;
|
||||
modificadoPor?: string;
|
||||
createdAt: Date;
|
||||
}
|
||||
18
packages/core/src/entities/CuadreCaja.ts
Normal file
18
packages/core/src/entities/CuadreCaja.ts
Normal file
@@ -0,0 +1,18 @@
|
||||
export interface CuadreCaja {
|
||||
id: string;
|
||||
fecha: Date;
|
||||
baseInicial: number;
|
||||
totalVentasEfectivo: number;
|
||||
totalVentasQR: number;
|
||||
totalGastosEfectivo: number;
|
||||
totalGastosQR: number;
|
||||
saldoEsperadoEfectivo: number;
|
||||
saldoRealEfectivo?: number;
|
||||
descuadreEfectivo?: number;
|
||||
totalQRRegistrado?: number;
|
||||
totalQRBanco?: number;
|
||||
descuadreQR?: number;
|
||||
totalVentas: number;
|
||||
observaciones?: string;
|
||||
createdAt: Date;
|
||||
}
|
||||
8
packages/core/src/entities/Gasto.ts
Normal file
8
packages/core/src/entities/Gasto.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
export interface Gasto {
|
||||
id: string;
|
||||
fecha: Date;
|
||||
concepto: string;
|
||||
monto: number;
|
||||
formaPago?: 'EFECTIVO' | 'QR';
|
||||
createdAt: Date;
|
||||
}
|
||||
13
packages/core/src/entities/MovimientoInventario.ts
Normal file
13
packages/core/src/entities/MovimientoInventario.ts
Normal file
@@ -0,0 +1,13 @@
|
||||
export type TipoMovimiento = 'INGRESO_INICIAL' | 'INGRESO_SEMANA' | 'AJUSTE' | 'VENTA';
|
||||
|
||||
export interface MovimientoInventario {
|
||||
id: string;
|
||||
fecha: Date;
|
||||
tipo: TipoMovimiento;
|
||||
productoId: string;
|
||||
cantidad: number;
|
||||
motivo?: string;
|
||||
recibidoPor?: string;
|
||||
referenciaId?: string;
|
||||
createdAt: Date;
|
||||
}
|
||||
8
packages/core/src/entities/Producto.ts
Normal file
8
packages/core/src/entities/Producto.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
export interface Producto {
|
||||
id: string;
|
||||
productorId: string;
|
||||
nombrePresentacion: string;
|
||||
precioUnitario: number;
|
||||
activo: boolean;
|
||||
createdAt: Date;
|
||||
}
|
||||
6
packages/core/src/entities/Productor.ts
Normal file
6
packages/core/src/entities/Productor.ts
Normal file
@@ -0,0 +1,6 @@
|
||||
export interface Productor {
|
||||
id: string;
|
||||
nombre: string;
|
||||
activo: boolean;
|
||||
createdAt: Date;
|
||||
}
|
||||
20
packages/core/src/entities/Venta.ts
Normal file
20
packages/core/src/entities/Venta.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
export type FormaPago = 'EFECTIVO' | 'QR';
|
||||
|
||||
export interface VentaLinea {
|
||||
id: string;
|
||||
ventaId: string;
|
||||
productoId: string;
|
||||
cantidad: number;
|
||||
precioUnitario: number;
|
||||
subtotal: number;
|
||||
formaPago: FormaPago;
|
||||
}
|
||||
|
||||
export interface Venta {
|
||||
id: string;
|
||||
fecha: Date;
|
||||
lineas: VentaLinea[];
|
||||
subtotal: number;
|
||||
total: number;
|
||||
createdAt: Date;
|
||||
}
|
||||
7
packages/core/src/entities/index.ts
Normal file
7
packages/core/src/entities/index.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
export * from './Productor';
|
||||
export * from './Producto';
|
||||
export * from './MovimientoInventario';
|
||||
export * from './Venta';
|
||||
export * from './Gasto';
|
||||
export * from './Ajuste';
|
||||
export * from './CuadreCaja';
|
||||
2
packages/core/src/index.ts
Normal file
2
packages/core/src/index.ts
Normal file
@@ -0,0 +1,2 @@
|
||||
export * from './entities';
|
||||
export * from './rules/cuadreRules';
|
||||
25
packages/core/src/rules/cuadreRules.ts
Normal file
25
packages/core/src/rules/cuadreRules.ts
Normal file
@@ -0,0 +1,25 @@
|
||||
export function validateAjusteMotivo(motivo: string): void {
|
||||
if (!motivo || motivo.trim().length === 0) {
|
||||
throw new Error('El ajuste debe tener un motivo obligatorio');
|
||||
}
|
||||
}
|
||||
|
||||
export function calcularDescuadreEfectivo(saldoEsperado: number, saldoReal: number): number {
|
||||
return saldoReal - saldoEsperado;
|
||||
}
|
||||
|
||||
export function calcularSaldoEsperadoEfectivo(
|
||||
baseInicial: number,
|
||||
totalVentasEfectivo: number,
|
||||
totalGastosEfectivo: number
|
||||
): number {
|
||||
return baseInicial + totalVentasEfectivo - totalGastosEfectivo;
|
||||
}
|
||||
|
||||
export function calcularTotalVentas(totalVentasEfectivo: number, totalVentasQR: number): number {
|
||||
return totalVentasEfectivo + totalVentasQR;
|
||||
}
|
||||
|
||||
export function calcularDiferenciaInventario(cantidadEsperada: number, cantidadReal: number): number {
|
||||
return cantidadReal - cantidadEsperada;
|
||||
}
|
||||
Reference in New Issue
Block a user