Facturas de cliente

This commit is contained in:
David Arranz 2025-10-07 10:17:35 +02:00
parent d4a4ab7a31
commit f35b7b098a
4 changed files with 68 additions and 47 deletions

View File

@ -5,7 +5,8 @@
"duplicate_row": "Duplicate",
"insert_row_above": "Insert row above",
"insert_row_below": "Insert row below",
"remove_row": "Remove"
"remove_row": "Remove",
"actions": "Actions"
},
"catalog": {
"status": {
@ -110,7 +111,7 @@
"placeholder": "Description of the invoice",
"description": "General description of the invoice"
},
"subtotal_price": {
"subtotal_amount": {
"label": "Subtotal",
"placeholder": "",
"desc": "Invoice subtotal"
@ -120,12 +121,12 @@
"placeholder": "",
"desc": "Percentage discount"
},
"discount_price": {
"discount_amount": {
"label": "Discount price",
"placeholder": "",
"desc": "Percentage discount price"
},
"total_price": {
"total_amount": {
"label": "Total price",
"placeholder": "",
"desc": "Invoice total price"
@ -135,7 +136,7 @@
"placeholder": "Additional notes about the invoice",
"description": "Additional notes that can be included in the invoice"
},
"items": {
"item": {
"quantity": {
"label": "Quantity",
"placeholder": "",
@ -146,40 +147,40 @@
"placeholder": "",
"description": ""
},
"unit_price": {
"unit_amount": {
"label": "Unit price",
"placeholder": "",
"description": "Item unit price"
},
"subtotal_price": {
"subtotal_amount": {
"label": "Subtotal",
"placeholder": "",
"description": ""
},
"discount": {
"discount_percentage": {
"label": "Dto (%)",
"placeholder": "",
"description": "Percentage discount"
},
"discount_price": {
"discount_amount": {
"label": "Discount price",
"placeholder": "",
"desc": "Percentage discount price"
"description": "Percentage discount price"
},
"taxes": {
"tax_codes": {
"label": "Taxes",
"placeholder": "",
"desc": "Taxes"
"description": "Taxes"
},
"taxes_price": {
"taxes_amount": {
"label": "Taxes price",
"placeholder": "",
"desc": "Percentage taxes price"
"description": "Percentage taxes price"
},
"total_price": {
"label": "Total price",
"total_amount": {
"label": "Total",
"placeholder": "",
"description": "Total price with percentage discount"
"description": "Invoice line total"
}
}
},
@ -189,6 +190,15 @@
"placeholder": "Select taxes",
"description": "Select the taxes to apply to the invoice items",
"invalid_tax_selection": "Invalid tax selection. Please select a valid tax."
},
"hover_card_totals_summary": {
"label": "Breakdown of the amount",
"fields": {
"subtotal_amount": "Subtotal",
"discount_percentage": "Discount",
"taxable_amount": "Taxable base",
"total_amount": "Total"
}
}
}
}

View File

@ -5,7 +5,8 @@
"duplicate_row": "Duplicar",
"insert_row_above": "Insertar fila arriba",
"insert_row_below": "Insertar fila abajo",
"remove_row": "Eliminar"
"remove_row": "Eliminar",
"actions": "Acciones"
},
"catalog": {
"status": {
@ -102,7 +103,7 @@
"placeholder": "Descripción de la factura",
"description": "Descripción general de la factura"
},
"subtotal_price": {
"subtotal_amount": {
"label": "Subtotal",
"placeholder": "",
"desc": "Subtotal de la factura"
@ -112,12 +113,12 @@
"placeholder": "",
"desc": "Porcentaje de descuento"
},
"discount_price": {
"discount_amount": {
"label": "Importe del descuento",
"placeholder": "",
"desc": "Importe del descuento porcentual"
},
"total_price": {
"total_amount": {
"label": "Precio total",
"placeholder": "",
"desc": "Precio total de la factura"
@ -127,7 +128,7 @@
"placeholder": "Notas adicionales sobre la factura",
"description": "Notas adicionales que se pueden incluir en la factura"
},
"items": {
"item": {
"quantity": {
"label": "Cantidad",
"placeholder": "",
@ -138,37 +139,37 @@
"placeholder": "",
"description": ""
},
"unit_price": {
"unit_amount": {
"label": "Precio unitario",
"placeholder": "",
"description": "Precio unitario del producto"
},
"subtotal_price": {
"subtotal_amount": {
"label": "Subtotal",
"placeholder": "",
"description": ""
},
"discount": {
"discount_percentage": {
"label": "Dto (%)",
"placeholder": "",
"description": "Porcentaje de descuento"
},
"discount_price": {
"discount_amount": {
"label": "Importe del descuento",
"placeholder": "",
"desc": "Importe del descuento porcentual"
"description": "Importe del descuento porcentual"
},
"taxes": {
"tax_codes": {
"label": "Impuestos",
"placeholder": "",
"desc": "Impuestos"
"description": "Impuestos"
},
"taxes_price": {
"taxes_amount": {
"label": "Importe impuestos",
"placeholder": "",
"desc": "Importe porcentual de los impuestos"
"description": "Importe porcentual de los impuestos"
},
"total_price": {
"total_amount": {
"label": "Precio total",
"placeholder": "",
"description": "Precio total con descuento porcentual"
@ -181,6 +182,15 @@
"placeholder": "Selecciona impuestos",
"description": "Selecciona los impuestos a aplicar a los artículos de la factura",
"invalid_tax_selection": "Selección de impuestos no válida. Por favor, selecciona un impuesto válido."
},
"hover_card_totals_summary": {
"label": "Desglose del importe",
"fields": {
"subtotal_amount": "Subtotal",
"discount_percentage": "Descuento",
"taxable_amount": "Importe base",
"total_amount": "Total"
}
}
}
}

View File

@ -5,6 +5,7 @@ import {
} from "@repo/shadcn-ui/components";
import { PropsWithChildren } from 'react';
import { useInvoiceItemSummary } from '../../../hooks';
import { useTranslation } from "../../../i18n";
import { CustomerInvoiceItemFormData } from '../../../schemas';
@ -17,22 +18,23 @@ export const HoverCardTotalsSummary = ({
item,
children,
}: HoverCardTotalsSummaryProps) => {
const { format } = useMoney()
const summary = useInvoiceItemSummary(item)
const { t } = useTranslation();
const { format } = useMoney();
const summary = useInvoiceItemSummary(item);
const SummaryBlock = () => (
<div className="space-y-2">
<h4 className="text-sm font-semibold mb-3">Desglose del importe</h4>
<h4 className="text-sm font-semibold mb-3">{t("components.hover_card_totals_summary.label")}</h4>
<div className="flex justify-between text-sm">
<span className="text-muted-foreground">Subtotal:</span>
<span className="text-muted-foreground">{t("components.hover_card_totals_summary.fields.subtotal_amount")}:</span>
<span className="font-mono">{format(summary.subtotal)}</span>
</div>
{Number(item.discount_percentage?.value ?? 0) > 0 && (
<div className="flex justify-between text-sm">
<span className="text-muted-foreground">
Descuento ({item.discount_percentage.value ?? 0}%):
{t("components.hover_card_totals_summary.fields.discount_percentage")} ({item.discount_percentage.value ?? 0}%):
</span>
<span className="font-mono text-destructive">
-{format(summary.discountAmount)}
@ -41,7 +43,7 @@ export const HoverCardTotalsSummary = ({
)}
<div className="flex justify-between text-sm border-t pt-2">
<span className="text-muted-foreground">Base imponible:</span>
<span className="text-muted-foreground">{t("components.hover_card_totals_summary.fields.taxable_amount")}:</span>
<span className="font-mono font-medium">
{format(summary.baseAmount)}
</span>
@ -55,7 +57,7 @@ export const HoverCardTotalsSummary = ({
))}
<div className="flex justify-between text-sm border-t pt-2 font-semibold">
<span>Total:</span>
<span>{t("components.hover_card_totals_summary.fields.total_amount")}:</span>
<span className="font-mono">{format(summary.total)}</span>
</div>
</div>

View File

@ -105,12 +105,13 @@ export const TableView = ({ items, actions }: TableViewProps) => {
<TableHeader className="sticky top-0 z-20 bg-background shadow-sm">
<TableRow className="bg-muted/30 text-xs text-muted-foreground">
<TableHead className="w-10 text-center">#</TableHead>
<TableHead>Descripción</TableHead>
<TableHead className="text-right w-24">Cantidad</TableHead>
<TableHead className="text-right w-32">Precio Unit.</TableHead>
<TableHead className="text-right w-24">% Desc.</TableHead>
<TableHead className="text-right w-32">Total</TableHead>
<TableHead className="w-44 text-center">Acciones</TableHead>
<TableHead>{t("form_fields.item.description.label")}</TableHead>
<TableHead className="text-right w-24">{t("form_fields.item.quantity.label")}</TableHead>
<TableHead className="text-right w-32">{t("form_fields.item.unit_amount.label")}</TableHead>
<TableHead className="text-right w-24">{t("form_fields.item.discount_percentage.label")}</TableHead>
<TableHead className="text-right w-32">{t("form_fields.item.tax_codes.label")}</TableHead>
<TableHead className="text-right w-32">{t("form_fields.item.total_amount.label")}</TableHead>
<TableHead className="w-44 text-center">{t("common.actions")}</TableHead>
</TableRow>
</TableHeader>
@ -212,9 +213,7 @@ export const TableView = ({ items, actions }: TableViewProps) => {
control={control}
name={`item.${i}.tax_codes`}
required
label={t("form_fields.item.tax_codes.label")}
placeholder={t("form_fields.item.tax_codes.placeholder")}
description={t("form_fields.item.tax_codes.description")}
/>
</TableCell>