Uecko_ERP/modules/customer-invoices/src/web/components/editor/invoice-totals.tsx
2025-11-09 12:05:33 +01:00

146 lines
5.3 KiB
TypeScript

import { formatCurrency } from "@erp/core";
import {
FieldDescription,
FieldGroup,
FieldLegend,
FieldSet,
Separator,
} from "@repo/shadcn-ui/components";
import { cn } from "@repo/shadcn-ui/lib/utils";
import { ReceiptIcon } from "lucide-react";
import { ComponentProps } from "react";
import { useFormContext, useWatch } from "react-hook-form";
import { useInvoiceContext } from "../../context";
import { useTranslation } from "../../i18n";
import { InvoiceFormData } from "../../schemas";
import { PercentageInputField } from "./items/percentage-input-field";
export const InvoiceTotals = (props: ComponentProps<"fieldset">) => {
const { t } = useTranslation();
const { control, getValues } = useFormContext<InvoiceFormData>();
const { currency_code, language_code, readOnly, taxCatalog } = useInvoiceContext();
const displayTaxes = useWatch({
control,
name: "taxes",
defaultValue: [],
});
const subtotal_amount = useWatch({
control,
name: "subtotal_amount",
defaultValue: 0,
});
return (
<FieldSet {...props}>
<FieldLegend className='hidden'>
<ReceiptIcon className='size-6 text-muted-foreground' />
{t("form_groups.totals.title")}
</FieldLegend>
<FieldDescription className='hidden'>{t("form_groups.totals.description")}</FieldDescription>
<FieldGroup className='grid grid-cols-1 border rounded-lg bg-muted/10 p-4 gap-4'>
<div className='space-y-1.5'>
{/* Sección: Subtotal y Descuentos */}
<div className='flex justify-between text-sm'>
<span className='text-muted-foreground'>Subtotal sin descuento</span>
<span className='font-medium tabular-nums text-muted-foreground'>
{formatCurrency(subtotal_amount, 2, currency_code, language_code)}
</span>
</div>
<div className='flex justify-between text-sm'>
<div className='flex items-center gap-3'>
<span className='text-muted-foreground'>Descuento global</span>
<PercentageInputField
control={control}
name={"discount_percentage"}
readOnly={readOnly}
inputId={"header-discount-percentage"}
showSuffix={true}
className={cn(
"w-20 text-right tabular-nums bg-background",
"border-input border text-sm shadow-xs"
)}
/>
</div>
<span className='font-medium text-destructive tabular-nums'>
-{formatCurrency(getValues("discount_amount"), 2, currency_code, language_code)}
</span>
</div>
{/* Sección: Base Imponible */}
<div className='flex justify-between text-sm'>
<span className='text-foreground'>Base imponible</span>
<span className='font-medium tabular-nums'>
{formatCurrency(getValues("taxable_amount"), 2, currency_code, language_code)}
</span>
</div>
</div>
<Separator />
{/* Sección: Impuestos */}
<div className='space-y-1.5'>
<h3 className='text-xs font-semibold text-muted-foreground uppercase tracking-wide'>
Impuestos y retenciones
</h3>
{taxCatalog.groups().map((group) => {
// Filtra impuestos de ese grupo
const taxesInGroup = displayTaxes?.filter((item) => {
const tax = taxCatalog.findByCode(item.tax_code).match(
(t) => t,
() => undefined
);
return tax?.group === group;
});
// Si el grupo no tiene impuestos, no renderiza nada
if (taxesInGroup?.length === 0) return null;
return (
<div key={`tax-group-${group}`} className='space-y-1.5 leading-3'>
{taxesInGroup?.map((item) => {
const tax = taxCatalog.findByCode(item.tax_code).match(
(t) => t,
() => undefined
);
return (
<div
key={`${group}:${item.tax_code}`}
className='flex items-center justify-between text-sm'
>
<span className='text-muted-foreground text-sm'>{tax?.name}</span>
<span className='font-medium tabular-nums text-sm text-muted-foreground'>
{formatCurrency(item.taxes_amount, 2, currency_code, language_code)}
</span>
</div>
);
})}
</div>
);
})}
<div className='flex justify-between text-sm mt-3'>
<span className='text-foreground'>Total de impuestos</span>
<span className='font-medium tabular-nums'>
{formatCurrency(getValues("taxes_amount"), 2, currency_code, language_code)}
</span>
</div>
</div>
<Separator />
<div className='flex justify-between text-sm '>
<span className='font-bold text-foreground'>Total de la factura</span>
<span className='font-bold tabular-nums'>
{formatCurrency(getValues("total_amount"), 2, currency_code, language_code)}
</span>
</div>
</FieldGroup>
</FieldSet>
);
};