diff --git a/modules/customer-invoices/src/common/locales/en.json b/modules/customer-invoices/src/common/locales/en.json index cb4049ae..412b46cf 100644 --- a/modules/customer-invoices/src/common/locales/en.json +++ b/modules/customer-invoices/src/common/locales/en.json @@ -67,6 +67,37 @@ "placeholder": "Select a date", "description": "Invoice operation date" }, + "subtotal_price": { + "label": "Subtotal", + "placeholder": "", + "desc": "Invoice subtotal" + }, + "discount": { + "label": "Discount (%)", + "placeholder": "", + "desc": "Percentage discount" + }, + "discount_price": { + "label": "Discount price", + "placeholder": "", + "desc": "Percentage discount price" + }, + "tax": { + "label": "Tax (%)", + "placeholder": "", + "desc": "Percentage Tax" + }, + "tax_price": { + "label": "Tax price", + "placeholder": "", + "desc": "Percentage tax price" + }, + "total_price": { + "label": "Total price", + "placeholder": "", + "desc": "Invoice total price" + }, + "items": { "quantity": { "label": "Quantity", diff --git a/modules/customer-invoices/src/common/locales/es.json b/modules/customer-invoices/src/common/locales/es.json index ccee68b8..d88abafd 100644 --- a/modules/customer-invoices/src/common/locales/es.json +++ b/modules/customer-invoices/src/common/locales/es.json @@ -67,6 +67,36 @@ "placeholder": "Seleccionar una fecha", "description": "Fecha de intervención de los trabajos" }, + "subtotal_price": { + "label": "Subtotal", + "placeholder": "", + "description": "" + }, + "discount": { + "label": "Dto (%)", + "placeholder": "", + "description": "Porcentaje de descuento" + }, + "discount_price": { + "label": "Imp. descuento", + "placeholder": "", + "desc": "Importe del descuento" + }, + "tax": { + "label": "IVA (%)", + "placeholder": "", + "desc": "Porcentaje de IVA" + }, + "tax_price": { + "label": "Imp. IVA", + "placeholder": "", + "desc": "Importe del IVA" + }, + "total_price": { + "label": "Imp. total", + "placeholder": "", + "description": "Importe total con el descuento ya aplicado" + }, "items": { "quantity": { "label": "Cantidad", diff --git a/modules/customer-invoices/src/web/components/customer-invoice-prices-card.tsx b/modules/customer-invoices/src/web/components/customer-invoice-prices-card.tsx new file mode 100644 index 00000000..4620e29a --- /dev/null +++ b/modules/customer-invoices/src/web/components/customer-invoice-prices-card.tsx @@ -0,0 +1,88 @@ +import { + Card, + CardContent, + CardDescription, + CardHeader, + CardTitle, + Separator, +} from "@repo/shadcn-ui/components"; +import { useFormContext } from "react-hook-form"; +import { useTranslation } from "../i18n"; +import { formatCurrency } from "../pages/create/utils"; + +export const CustomerInvoicePricesCard = () => { + const { t } = useTranslation(); + const { register, formState, control, watch } = useFormContext(); + + /*const pricesWatch = useWatch({ control, name: ["subtotal_price", "discount", "tax"] }); + + const totals = calculateQuoteTotals(pricesWatch); + + const subtotal_price = formatNumber(totals.subtotalPrice); + const discount_price = formatNumber(totals.discountPrice); + const tax_price = formatNumber(totals.taxesPrice); + const total_price = formatNumber(totals.totalPrice);*/ + + const currency_symbol = watch("currency"); + + return ( + + + Impuestos y Totales + Configuración de impuestos y resumen de totales + + + +
+
+ + {t("form_fields.subtotal_price.label")} + + + {formatCurrency(watch("subtotal_price.amount"), 2, watch("currency"))} + +
+
+ +
+
+ {t("form_fields.discount.label")} +
+
+ + {t("form_fields.discount_price.label")} + + + {"-"} {formatCurrency(watch("discount_price.amount"), 2, watch("currency"))} + +
+
+ +
+
+ {t("form_fields.tax.label")} +
+
+ + {t("form_fields.tax_price.label")} + + + {formatCurrency(watch("tax_price.amount"), 2, watch("currency"))} + +
+
{" "} + +
+
+ + {t("form_fields.total_price.label")} + + + {formatCurrency(watch("total_price.amount"), 2, watch("currency"))} + +
+
+
+
+ ); +}; diff --git a/modules/customer-invoices/src/web/components/customer-invoices-list-grid.tsx b/modules/customer-invoices/src/web/components/customer-invoices-list-grid.tsx index 313c0dc3..93636dd2 100644 --- a/modules/customer-invoices/src/web/components/customer-invoices-list-grid.tsx +++ b/modules/customer-invoices/src/web/components/customer-invoices-list-grid.tsx @@ -12,6 +12,7 @@ import { formatDate, formatMoney } from "@erp/core/client"; // Core CSS import { AgGridReact } from "ag-grid-react"; import { useCustomerInvoicesQuery } from "../hooks"; +import { useTranslation } from "../i18n"; import { CustomerInvoiceStatusBadge } from "./customer-invoice-status-badge"; // Create new GridExample component diff --git a/modules/customer-invoices/src/web/components/index.tsx b/modules/customer-invoices/src/web/components/index.tsx index 0b064b0d..039b784e 100644 --- a/modules/customer-invoices/src/web/components/index.tsx +++ b/modules/customer-invoices/src/web/components/index.tsx @@ -1,3 +1,4 @@ +export * from "./customer-invoice-prices-card"; export * from "./customer-invoice-status-badge"; export * from "./customer-invoices-layout"; export * from "./customer-invoices-list-grid"; diff --git a/modules/customer-invoices/src/web/pages/create/customer-invoice-edit-form.tsx b/modules/customer-invoices/src/web/pages/create/customer-invoice-edit-form.tsx index e6934ab2..78b65bdf 100644 --- a/modules/customer-invoices/src/web/pages/create/customer-invoice-edit-form.tsx +++ b/modules/customer-invoices/src/web/pages/create/customer-invoice-edit-form.tsx @@ -35,6 +35,7 @@ import { import { format } from "date-fns"; import { es } from "date-fns/locale"; import { CalendarIcon, PlusIcon, Save, Trash2Icon, X } from "lucide-react"; +import { CustomerInvoicePricesCard } from "../../components"; import { CustomerInvoiceItemsCardEditor } from "../../components/items"; import { useTranslation } from "../../i18n"; import { CustomerInvoiceData } from "./customer-invoice.schema"; @@ -464,6 +465,9 @@ export const CustomerInvoiceEditForm = ({ ))} + + + {/* Configuración de Impuestos */} diff --git a/packages/rdx-ui/src/components/form/DatePickerInputField.tsx b/packages/rdx-ui/src/components/form/DatePickerInputField.tsx index eb152d3a..655c6bfc 100644 --- a/packages/rdx-ui/src/components/form/DatePickerInputField.tsx +++ b/packages/rdx-ui/src/components/form/DatePickerInputField.tsx @@ -9,7 +9,7 @@ import { PopoverContent, PopoverTrigger, } from "@repo/shadcn-ui/components"; -import { CalendarIcon, LockIcon } from "lucide-react"; +import { CalendarIcon, LockIcon, XIcon } from "lucide-react"; import { cn } from "@repo/shadcn-ui/lib/utils"; import { format, isValid, parse } from "date-fns"; @@ -60,16 +60,23 @@ export function DatePickerInputField({ const handleInputChange = (value: string) => { setInputValue(value); - setInputError(null); // Reset error on typing + setInputError(null); }; const validateAndSetDate = () => { - const parsed = parse(inputValue, parseDateFormat, new Date()); + const trimmed = inputValue.trim(); + if (!trimmed) { + field.onChange(undefined); + setInputError(null); + return; + } + + const parsed = parse(trimmed, parseDateFormat, new Date()); if (isValid(parsed)) { field.onChange(parsed.toISOString()); setInputError(null); } else { - setInputError(t("common.invalid_date") || "Fecha no válida"); + setInputError(t("common.invalidDate") || "Fecha no válida"); } }; @@ -106,11 +113,25 @@ export function DatePickerInputField({ )} placeholder={placeholder} /> -
+
+ {!isReadOnly && !required && inputValue && ( + + )} {isReadOnly ? ( - + ) : ( - + )}
@@ -128,6 +149,9 @@ export function DatePickerInputField({ field.onChange(iso); setInputValue(formatDateFn(iso)); setInputError(null); + } else { + field.onChange(undefined); + setInputValue(""); } }} initialFocus @@ -136,15 +160,22 @@ export function DatePickerInputField({ )} -

- {inputError || description || "\u00A0"} -

+ {isReadOnly && ( +

+ {t("common.readOnly") || "Solo lectura"} +

+ )} + + {(inputError || description) && ( +

+ {inputError || description} +

+ )} diff --git a/packages/rdx-ui/src/components/loading-overlay/loading-overlay.tsx b/packages/rdx-ui/src/components/loading-overlay/loading-overlay.tsx index 259425c6..ad9fd038 100644 --- a/packages/rdx-ui/src/components/loading-overlay/loading-overlay.tsx +++ b/packages/rdx-ui/src/components/loading-overlay/loading-overlay.tsx @@ -1,5 +1,5 @@ +import { useTranslation } from "@repo/rdx-ui/locales/i18n.ts"; import { JSX } from "react"; -import { useTranslation } from "react-i18next"; import { LoadingIndicator } from "./loading-indicator.tsx"; export type LoadingOverlayProps = {