import { zodResolver } from "@hookform/resolvers/zod"; import { useFieldArray, useForm } from "react-hook-form"; import * as z from "zod"; import { ClientSelector } from "@erp/customers/components"; import { DatePickerField } from "@repo/rdx-ui/components"; import { Button, Calendar, Card, CardContent, CardDescription, CardHeader, CardTitle, Form, FormControl, FormField, FormItem, FormLabel, FormMessage, Input, Label, Popover, PopoverContent, PopoverTrigger, Select, SelectContent, SelectItem, SelectTrigger, SelectValue, Separator, Textarea, } from "@repo/shadcn-ui/components"; import { format } from "date-fns"; import { es } from "date-fns/locale"; import { CalendarIcon, PlusIcon, Save, Trash2Icon, X } from "lucide-react"; import { useTranslation } from "react-i18next"; import { CustomerInvoiceItemsCardEditor } from "../../components/items"; import { MODULE_NAME } from "../../manifest"; import { CustomerInvoiceData } from "./customer-invoice.schema"; import { formatCurrency } from "./utils"; const invoiceSchema = z.object({ id: z.string(), invoice_status: z.string(), invoice_number: z.string().min(1, "Número de factura requerido"), invoice_series: z.string().min(1, "Serie requerida"), issue_date: z.string(), operation_date: z.string(), language_code: z.string(), currency: z.string(), customer_id: z.string().min(1, "ID de cliente requerido"), items: z .array( z.object({ id_article: z.string(), description: z.string(), quantity: z.object({ amount: z.number().nullable(), scale: z.number(), }), unit_price: z.object({ amount: z.number().nullable(), scale: z.number(), currency_code: z.string(), }), subtotal_price: z.object({ amount: z.number().nullable(), scale: z.number(), currency_code: z.string(), }), discount: z.object({ amount: z.number().min(0).max(100).nullable(), scale: z.number(), }), discount_price: z.object({ amount: z.number().nullable(), scale: z.number(), currency_code: z.string(), }), total_price: z.object({ amount: z.number().nullable(), scale: z.number(), currency_code: z.string(), }), }) ) .min(1, "Al menos un item es requerido"), subtotal_price: z.object({ amount: z.number().nullable(), scale: z.number(), currency_code: z.string(), }), discount: z.object({ amount: z.number().nullable(), scale: z.number(), }), discount_price: z.object({ amount: z.number().nullable(), scale: z.number(), currency_code: z.string(), }), before_tax_price: z.object({ amount: z.number().nullable(), scale: z.number(), currency_code: z.string(), }), tax: z.object({ amount: z.number().nullable(), scale: z.number(), }), tax_price: z.object({ amount: z.number().nullable(), scale: z.number(), currency_code: z.string(), }), total_price: z.object({ amount: z.number().nullable(), scale: z.number(), currency_code: z.string(), }), metadata: z.object({ entity: z.string(), }), }); const defaultInvoiceData: CustomerInvoiceData = { id: "", invoice_status: "draft", invoice_number: "1", invoice_series: "A", issue_date: "2025-04-30T00:00:00.000Z", operation_date: "2025-04-30T00:00:00.000Z", language_code: "ES", currency: "EUR", customer_id: "", items: [ { description: "", quantity: { amount: 100, scale: 2, }, unit_price: { amount: 100, scale: 2, currency_code: "EUR", }, subtotal_price: { amount: 100, scale: 2, currency_code: "EUR", }, discount: { amount: 0, scale: 2, }, discount_price: { amount: 0, scale: 2, currency_code: "EUR", }, total_price: { amount: 100, scale: 2, currency_code: "EUR", }, }, ], subtotal_price: { amount: 0, scale: 2, currency_code: "EUR", }, discount: { amount: 0, scale: 0, }, discount_price: { amount: 0, scale: 0, currency_code: "EUR", }, before_tax_price: { amount: 0, scale: 2, currency_code: "EUR", }, tax: { amount: 2100, scale: 2, }, tax_price: { amount: 0, scale: 2, currency_code: "EUR", }, total_price: { amount: 0, scale: 2, currency_code: "EUR", }, }; interface InvoiceFormProps { initialData?: CustomerInvoiceData; isPending?: boolean; /** * Callback function to handle form submission. * @param data - The invoice data submitted by the form. */ onSubmit?: (data: CustomerInvoiceData) => void; } export const CustomerInvoiceEditForm = ({ initialData = defaultInvoiceData, onSubmit, isPending, }: InvoiceFormProps) => { const { t } = useTranslation(MODULE_NAME); const form = useForm({ resolver: zodResolver(invoiceSchema), defaultValues: initialData, }); const { fields, append, remove } = useFieldArray({ control: form.control, name: "items", }); const watchedItems = form.watch("items"); const watchedTaxRate = form.watch("tax.amount"); const addItem = () => { append({ id_article: "", description: "", quantity: { amount: 100, scale: 2 }, unit_price: { amount: 0, scale: 2, currency_code: form.getValues("currency") }, subtotal_price: { amount: 0, scale: 2, currency_code: form.getValues("currency") }, discount: { amount: 0, scale: 2 }, discount_price: { amount: 0, scale: 2, currency_code: form.getValues("currency") }, total_price: { amount: 0, scale: 2, currency_code: form.getValues("currency") }, }); }; const handleSubmit = (data: CustomerInvoiceData) => { console.log("Datos del formulario:", data); onSubmit?.(data); }; const handleError = (errors: any) => { console.error("Errores en el formulario:", errors); // Aquí puedes manejar los errores, por ejemplo, mostrar un mensaje al usuario }; const handleCancel = () => { form.reset(initialData); }; return (
{/* Cliente */} Cliente ( ID Cliente )} /> {/* Información básica */} Información Básica Detalles generales de la factura ( {t("form_fields.invoice_number.label")} )} /> ( Serie )} /> {/*Items */} {/* Items */}
Artículos Lista de productos o servicios facturados
{fields.map((field, index) => (

Item {index + 1}

{fields.length > 1 && ( )}
( Código Artículo )} /> ( Descripción