Uecko_ERP/modules/customer-invoices/src/web/hooks/use-calculate-item-amounts.ts

60 lines
1.9 KiB
TypeScript
Raw Normal View History

2025-10-06 17:40:37 +00:00
import { spainTaxCatalogProvider } from "@erp/core";
import { useMoney, usePercentage, useQuantity } from "@erp/core/hooks";
import { useMemo } from "react";
import { CustomerInvoiceItemFormData } from "../schemas";
/**
* Recalcula todos los importes de una línea usando los hooks de escala.
*/
export function useCalculateItemAmounts() {
const { multiply, percentage: moneyPct, sum } = useMoney();
const { toNumber: qtyToNumber } = useQuantity();
const { toNumber: pctToNumber } = usePercentage();
const taxCatalog = useMemo(() => spainTaxCatalogProvider, []);
return (item: CustomerInvoiceItemFormData): CustomerInvoiceItemFormData => {
const qty = qtyToNumber(item.quantity);
const subtotal = multiply(item.unit_amount, qty);
const discountPct = pctToNumber(item.discount_percentage);
const discountAmount =
discountPct > 0 ? moneyPct(subtotal, discountPct) : { ...subtotal, value: "0" };
const base = sum([
subtotal,
{ ...discountAmount, value: (-Number(discountAmount.value)).toString() },
]);
// Impuestos (cada uno es porcentaje sobre la base)
const taxesBreakdown =
item.tax_codes?.map((tax_code) => {
const maybeTax = taxCatalog.findByCode(tax_code);
if (maybeTax.isNone()) {
throw Error(`Código de impuesto no encontrado en el catálogo: "${tax_code}"`);
}
const tax = maybeTax.unwrap()!;
const percentage = pctToNumber({ value: tax.value, scale: tax.scale });
return {
label: tax.name,
percentage,
amount: moneyPct(base, percentage),
};
}) ?? [];
const taxes = sum(taxesBreakdown.map((t) => t.amount));
const total = sum([base, taxes]);
return {
...item,
subtotal_amount: subtotal,
discount_amount: discountAmount,
taxable_amount: base,
taxes_amount: taxes,
total_amount: total,
};
};
}