60 lines
1.9 KiB
TypeScript
60 lines
1.9 KiB
TypeScript
|
|
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,
|
||
|
|
};
|
||
|
|
};
|
||
|
|
}
|