Facturas de cliente
This commit is contained in:
parent
ef8a20d296
commit
27a5e30d37
@ -39,7 +39,7 @@ export function AmountInputField<T extends FieldValues>({
|
|||||||
<FormControl>
|
<FormControl>
|
||||||
<AmountInput
|
<AmountInput
|
||||||
id={inputId}
|
id={inputId}
|
||||||
value={field.value}
|
value={field.value ?? ""}
|
||||||
onChange={field.onChange}
|
onChange={field.onChange}
|
||||||
{...inputProps}
|
{...inputProps}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@ -5,8 +5,8 @@ import { InputEmptyMode, InputReadOnlyMode } from './quantity-input';
|
|||||||
|
|
||||||
|
|
||||||
export type AmountInputProps = {
|
export type AmountInputProps = {
|
||||||
value: number | "" | string; // "" → no mostrar nada; string puede venir con separadores
|
value: number | string; // "" → no mostrar nada; string puede venir con separadores
|
||||||
onChange: (next: number | "") => void;
|
onChange: (next: number | string) => void;
|
||||||
readOnly?: boolean;
|
readOnly?: boolean;
|
||||||
readOnlyMode?: InputReadOnlyMode; // default "textlike-input"
|
readOnlyMode?: InputReadOnlyMode; // default "textlike-input"
|
||||||
id?: string;
|
id?: string;
|
||||||
|
|||||||
@ -28,25 +28,27 @@ export function QuantityInputField<TFormValues extends FieldValues>({
|
|||||||
<FormField
|
<FormField
|
||||||
control={control}
|
control={control}
|
||||||
name={name}
|
name={name}
|
||||||
render={({ field }) => (
|
render={({ field }) => {
|
||||||
<FormItem>
|
const { value, onChange } = field;
|
||||||
|
console.log(value);
|
||||||
|
return <FormItem>
|
||||||
{label ? (
|
{label ? (
|
||||||
<FormLabel htmlFor={inputId}>
|
<FormLabel htmlFor={inputId}>
|
||||||
{label} {required ? <span aria-hidden="true">*</span> : null}
|
{label} {required ? <span aria-hidden='true'>*</span> : null}
|
||||||
</FormLabel>
|
</FormLabel>
|
||||||
) : null}
|
) : null}
|
||||||
<FormControl>
|
<FormControl>
|
||||||
<QuantityInput
|
<QuantityInput
|
||||||
id={inputId}
|
id={inputId}
|
||||||
value={field.value}
|
value={value}
|
||||||
onChange={field.onChange}
|
onChange={onChange}
|
||||||
{...inputProps}
|
{...inputProps}
|
||||||
/>
|
/>
|
||||||
</FormControl>
|
</FormControl>
|
||||||
{description ? <FormDescription>{description}</FormDescription> : null}
|
{description ? <FormDescription>{description}</FormDescription> : null}
|
||||||
<FormMessage />
|
<FormMessage />
|
||||||
</FormItem>
|
</FormItem>
|
||||||
)}
|
}}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -110,9 +110,12 @@ export function useInvoiceAutoRecalc(
|
|||||||
|
|
||||||
// Suscripción reactiva a cambios del formulario
|
// Suscripción reactiva a cambios del formulario
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
|
console.log("recalculo algo?");
|
||||||
|
|
||||||
if (!isDirty || isLoading || isSubmitting) return;
|
if (!isDirty || isLoading || isSubmitting) return;
|
||||||
|
|
||||||
const subscription = watch(async (formData, { name, type }) => {
|
const subscription = watch((formData, { name, type }) => {
|
||||||
|
console.log(name, type);
|
||||||
const items = (formData?.items || []) as InvoiceItemFormData[];
|
const items = (formData?.items || []) as InvoiceItemFormData[];
|
||||||
|
|
||||||
if (items.length === 0) return;
|
if (items.length === 0) return;
|
||||||
@ -126,7 +129,7 @@ export function useInvoiceAutoRecalc(
|
|||||||
setInvoiceTotals(form, invoiceTotals);
|
setInvoiceTotals(form, invoiceTotals);
|
||||||
|
|
||||||
// 3) valida una vez (opcional)
|
// 3) valida una vez (opcional)
|
||||||
await trigger([
|
trigger([
|
||||||
"subtotal_amount",
|
"subtotal_amount",
|
||||||
"discount_amount",
|
"discount_amount",
|
||||||
"taxable_amount",
|
"taxable_amount",
|
||||||
@ -137,19 +140,25 @@ export function useInvoiceAutoRecalc(
|
|||||||
|
|
||||||
// 2. Cambio puntual de una línea
|
// 2. Cambio puntual de una línea
|
||||||
if (name?.startsWith("items.") && type === "change") {
|
if (name?.startsWith("items.") && type === "change") {
|
||||||
|
console.log("2. items!");
|
||||||
|
|
||||||
const index = Number(name.split(".")[1]);
|
const index = Number(name.split(".")[1]);
|
||||||
const field = name.split(".")[2];
|
const field = name.split(".")[2];
|
||||||
|
|
||||||
if (["quantity", "unit_amount", "discount_percentage", "tax_codes"].includes(field)) {
|
if (["quantity", "unit_amount", "discount_percentage", "tax_codes"].includes(field)) {
|
||||||
|
console.log("2.1. recalculo items!");
|
||||||
const item = items[index] as InvoiceItemFormData;
|
const item = items[index] as InvoiceItemFormData;
|
||||||
const prevTotals = itemCache.current.get(index);
|
const prevTotals = itemCache.current.get(index);
|
||||||
const newTotals = calculateItemTotals(item);
|
const newTotals = calculateItemTotals(item);
|
||||||
|
|
||||||
|
console.log(prevTotals, newTotals);
|
||||||
|
|
||||||
// Si no hay cambios en los totales, no tocamos nada
|
// Si no hay cambios en los totales, no tocamos nada
|
||||||
const itemHasChanges =
|
const itemHasChanges =
|
||||||
prevTotals && JSON.stringify(prevTotals) !== JSON.stringify(newTotals);
|
prevTotals || JSON.stringify(prevTotals) !== JSON.stringify(newTotals);
|
||||||
|
|
||||||
if (!itemHasChanges) {
|
if (!itemHasChanges) {
|
||||||
|
console.log("No hay cambios, me voy!!!");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -173,7 +182,7 @@ export function useInvoiceAutoRecalc(
|
|||||||
setInvoiceTotals(form, invoiceTotals);
|
setInvoiceTotals(form, invoiceTotals);
|
||||||
|
|
||||||
// 3) valida una vez (opcional)
|
// 3) valida una vez (opcional)
|
||||||
await trigger([
|
trigger([
|
||||||
"items",
|
"items",
|
||||||
"subtotal_amount",
|
"subtotal_amount",
|
||||||
"discount_amount",
|
"discount_amount",
|
||||||
@ -188,10 +197,15 @@ export function useInvoiceAutoRecalc(
|
|||||||
return () => subscription.unsubscribe();
|
return () => subscription.unsubscribe();
|
||||||
}, [
|
}, [
|
||||||
watch,
|
watch,
|
||||||
|
trigger,
|
||||||
setValue,
|
setValue,
|
||||||
getValues,
|
getValues,
|
||||||
|
isDirty,
|
||||||
isLoading,
|
isLoading,
|
||||||
isSubmitting,
|
isSubmitting,
|
||||||
|
itemCache,
|
||||||
|
setInvoiceItemTotals,
|
||||||
|
setInvoiceTotals,
|
||||||
calculateItemTotals,
|
calculateItemTotals,
|
||||||
calculateInvoiceTotals,
|
calculateInvoiceTotals,
|
||||||
]);
|
]);
|
||||||
|
|||||||
@ -1,15 +1,14 @@
|
|||||||
import { NumericStringSchema } from "@erp/core";
|
|
||||||
import { z } from "zod/v4";
|
import { z } from "zod/v4";
|
||||||
|
|
||||||
export const InvoiceItemFormSchema = z.object({
|
export const InvoiceItemFormSchema = z.object({
|
||||||
is_non_valued: z.boolean(),
|
is_non_valued: z.boolean(),
|
||||||
|
|
||||||
description: z.string().max(2000).optional().default(""),
|
description: z.string().max(2000).optional().default(""),
|
||||||
quantity: NumericStringSchema.optional(),
|
quantity: z.any(), //NumericStringSchema.optional(),
|
||||||
unit_amount: NumericStringSchema.optional(),
|
unit_amount: z.any(), //NumericStringSchema.optional(),
|
||||||
|
|
||||||
subtotal_amount: z.number(),
|
subtotal_amount: z.any(), //z.number(),
|
||||||
discount_percentage: NumericStringSchema.optional(),
|
discount_percentage: z.any(), //NumericStringSchema.optional(),
|
||||||
discount_amount: z.number(),
|
discount_amount: z.number(),
|
||||||
taxable_amount: z.number(),
|
taxable_amount: z.number(),
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user