Clientes
This commit is contained in:
parent
bec5a54756
commit
01ca0bd5dc
@ -134,8 +134,8 @@ export const CustomerInvoicesListGrid = () => {
|
|||||||
resizable: true,
|
resizable: true,
|
||||||
},
|
},
|
||||||
pagination: true,
|
pagination: true,
|
||||||
paginationPageSize: 10,
|
paginationPageSize: 15,
|
||||||
paginationPageSizeSelector: [10, 20, 30, 50],
|
paginationPageSizeSelector: [10, 15, 20, 30, 50],
|
||||||
localeText: AG_GRID_LOCALE_ES,
|
localeText: AG_GRID_LOCALE_ES,
|
||||||
}),
|
}),
|
||||||
[autoSizeStrategy, colDefs]
|
[autoSizeStrategy, colDefs]
|
||||||
|
|||||||
@ -4,18 +4,18 @@ export const CreateCustomerRequestSchema = z.object({
|
|||||||
id: z.string().nonempty(),
|
id: z.string().nonempty(),
|
||||||
|
|
||||||
reference: z.string().optional(),
|
reference: z.string().optional(),
|
||||||
is_company: z.string().toLowerCase().default("false"),
|
is_company: z.string().toLowerCase().default("true"),
|
||||||
name: z.string(),
|
name: z.string(),
|
||||||
trade_name: z.string().optional(),
|
trade_name: z.string().optional(),
|
||||||
tin: z.string().optional(),
|
tin: z.string().optional(),
|
||||||
default_taxes: z.array(z.string()).default([]).optional(),
|
default_taxes: z.array(z.string()).default([]),
|
||||||
|
|
||||||
street: z.string().optional(),
|
street: z.string().optional(),
|
||||||
street2: z.string().optional(),
|
street2: z.string().optional(),
|
||||||
city: z.string().optional(),
|
city: z.string().optional(),
|
||||||
province: z.string().optional(),
|
province: z.string().optional(),
|
||||||
postal_code: z.string().optional(),
|
postal_code: z.string().optional(),
|
||||||
country: z.string().default("es").optional(),
|
country: z.string().toLowerCase().default("es").optional(),
|
||||||
|
|
||||||
email_primary: z.string().optional(),
|
email_primary: z.string().optional(),
|
||||||
email_secondary: z.string().optional(),
|
email_secondary: z.string().optional(),
|
||||||
|
|||||||
@ -31,7 +31,11 @@ export const CustomersListGrid = () => {
|
|||||||
isLoading: isLoadingCustomers,
|
isLoading: isLoadingCustomers,
|
||||||
isError: isLoadError,
|
isError: isLoadError,
|
||||||
error: loadError,
|
error: loadError,
|
||||||
} = useCustomersQuery();
|
} = useCustomersQuery({
|
||||||
|
pagination: {
|
||||||
|
pageSize: 999,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
// Column Definitions: Defines & controls grid columns.
|
// Column Definitions: Defines & controls grid columns.
|
||||||
const [colDefs] = useState<ColDef[]>([
|
const [colDefs] = useState<ColDef[]>([
|
||||||
@ -113,8 +117,8 @@ export const CustomersListGrid = () => {
|
|||||||
resizable: true,
|
resizable: true,
|
||||||
},
|
},
|
||||||
pagination: true,
|
pagination: true,
|
||||||
paginationPageSize: 10,
|
paginationPageSize: 15,
|
||||||
paginationPageSizeSelector: [10, 20, 30, 50],
|
paginationPageSizeSelector: [10, 15, 20, 30, 50],
|
||||||
localeText: AG_GRID_LOCALE_ES,
|
localeText: AG_GRID_LOCALE_ES,
|
||||||
}),
|
}),
|
||||||
[autoSizeStrategy, colDefs]
|
[autoSizeStrategy, colDefs]
|
||||||
|
|||||||
@ -22,6 +22,7 @@ export const CustomerBasicInfoFields = () => {
|
|||||||
const { control } = useFormContext<CustomerFormData>();
|
const { control } = useFormContext<CustomerFormData>();
|
||||||
|
|
||||||
const isCompany = useWatch({
|
const isCompany = useWatch({
|
||||||
|
control,
|
||||||
name: "is_company",
|
name: "is_company",
|
||||||
defaultValue: "true",
|
defaultValue: "true",
|
||||||
});
|
});
|
||||||
@ -53,7 +54,9 @@ export const CustomerBasicInfoFields = () => {
|
|||||||
<FormLabel>{t("form_fields.customer_type.label")}</FormLabel>
|
<FormLabel>{t("form_fields.customer_type.label")}</FormLabel>
|
||||||
<FormControl>
|
<FormControl>
|
||||||
<RadioGroup
|
<RadioGroup
|
||||||
onValueChange={field.onChange}
|
onValueChange={(value: string) => {
|
||||||
|
field.onChange(value === "false" ? "false" : "true");
|
||||||
|
}}
|
||||||
defaultValue={field.value ? "true" : "false"}
|
defaultValue={field.value ? "true" : "false"}
|
||||||
className='flex items-center gap-6'
|
className='flex items-center gap-6'
|
||||||
>
|
>
|
||||||
|
|||||||
@ -2,7 +2,7 @@ import { zodResolver } from "@hookform/resolvers/zod";
|
|||||||
import { FieldErrors, FormProvider, useForm } from "react-hook-form";
|
import { FieldErrors, FormProvider, useForm } from "react-hook-form";
|
||||||
|
|
||||||
import { useEffect } from "react";
|
import { useEffect } from "react";
|
||||||
import { CustomerFormData, CustomerFormSchema } from "../../schemas";
|
import { CreateCustomerFormSchema, CustomerFormData } from "../../schemas";
|
||||||
import { FormDebug } from "../form-debug";
|
import { FormDebug } from "../form-debug";
|
||||||
import { CustomerAdditionalConfigFields } from "./customer-additional-config-fields";
|
import { CustomerAdditionalConfigFields } from "./customer-additional-config-fields";
|
||||||
import { CustomerAddressFields } from "./customer-address-fields";
|
import { CustomerAddressFields } from "./customer-address-fields";
|
||||||
@ -27,7 +27,7 @@ export function CustomerEditForm({
|
|||||||
onDirtyChange,
|
onDirtyChange,
|
||||||
}: CustomerFormProps) {
|
}: CustomerFormProps) {
|
||||||
const form = useForm<CustomerFormData>({
|
const form = useForm<CustomerFormData>({
|
||||||
resolver: zodResolver(CustomerFormSchema),
|
resolver: zodResolver(CreateCustomerFormSchema),
|
||||||
defaultValues: initialValues,
|
defaultValues: initialValues,
|
||||||
disabled,
|
disabled,
|
||||||
});
|
});
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
import { useDataSource } from "@erp/core/hooks";
|
import { useDataSource } from "@erp/core/hooks";
|
||||||
import { UniqueID } from "@repo/rdx-ddd";
|
import { UniqueID, ValidationErrorCollection } from "@repo/rdx-ddd";
|
||||||
import { useMutation, useQueryClient } from "@tanstack/react-query";
|
import { useMutation, useQueryClient } from "@tanstack/react-query";
|
||||||
|
import { CreateCustomerRequestSchema, CustomerCreationResponseDTO } from "../../common";
|
||||||
import { CustomerFormData } from "../schemas";
|
import { CustomerFormData } from "../schemas";
|
||||||
import { CUSTOMERS_LIST_KEY } from "./use-update-customer-mutation";
|
import { CUSTOMERS_LIST_KEY } from "./use-update-customer-mutation";
|
||||||
|
|
||||||
@ -11,19 +12,35 @@ type CreateCustomerPayload = {
|
|||||||
export function useCreateCustomerMutation() {
|
export function useCreateCustomerMutation() {
|
||||||
const queryClient = useQueryClient();
|
const queryClient = useQueryClient();
|
||||||
const dataSource = useDataSource();
|
const dataSource = useDataSource();
|
||||||
|
const schema = CreateCustomerRequestSchema;
|
||||||
|
|
||||||
return useMutation<CustomerFormData, Error, CreateCustomerPayload>({
|
return useMutation<CustomerCreationResponseDTO, Error, CreateCustomerPayload>({
|
||||||
mutationKey: ["customer:create"],
|
mutationKey: ["customer:create"],
|
||||||
|
|
||||||
mutationFn: async (payload) => {
|
mutationFn: async (payload) => {
|
||||||
const { data } = payload;
|
const { data } = payload;
|
||||||
const customerId = UniqueID.generateNewID();
|
const customerId = UniqueID.generateNewID();
|
||||||
|
|
||||||
const created = await dataSource.createOne("customers", {
|
const newCustomerData = {
|
||||||
...data,
|
...data,
|
||||||
id: customerId.toString(),
|
id: customerId.toString(),
|
||||||
});
|
};
|
||||||
return created as CustomerFormData;
|
|
||||||
|
const result = schema.safeParse(newCustomerData);
|
||||||
|
if (!result.success) {
|
||||||
|
// Construye errores detallados
|
||||||
|
const validationErrors = result.error.issues.map((err) => ({
|
||||||
|
field: err.path.join("."),
|
||||||
|
message: err.message,
|
||||||
|
}));
|
||||||
|
|
||||||
|
console.debug(validationErrors);
|
||||||
|
|
||||||
|
throw new ValidationErrorCollection("Validation failed", validationErrors);
|
||||||
|
}
|
||||||
|
|
||||||
|
const created = await dataSource.createOne("customers", newCustomerData);
|
||||||
|
return created as CustomerCreationResponseDTO;
|
||||||
},
|
},
|
||||||
|
|
||||||
onSuccess: () => {
|
onSuccess: () => {
|
||||||
|
|||||||
@ -17,35 +17,35 @@ export const CustomerCreate = () => {
|
|||||||
|
|
||||||
// 2) Estado de creación (mutación)
|
// 2) Estado de creación (mutación)
|
||||||
const {
|
const {
|
||||||
mutateAsync,
|
mutate,
|
||||||
isPending: isCreating,
|
isPending: isCreating,
|
||||||
isError: isCreateError,
|
isError: isCreateError,
|
||||||
error: createError,
|
error: createError,
|
||||||
} = useCreateCustomerMutation();
|
} = useCreateCustomerMutation();
|
||||||
|
|
||||||
// 3) Submit con navegación condicionada por éxito
|
// 3) Submit con navegación condicionada por éxito
|
||||||
const handleSubmit = async (formData: CustomerFormData) => {
|
const handleSubmit = (formData: CustomerFormData) => {
|
||||||
console.log("formData => ", formData);
|
mutate(
|
||||||
|
{ data: formData },
|
||||||
/*const changedData: Record<string, string> = {};
|
{
|
||||||
|
onSuccess(data) {
|
||||||
Object.keys(dirtyFields).forEach((field) => {
|
setIsDirty(false);
|
||||||
const value = String(currentValues[field as keyof CustomerFormData]);
|
|
||||||
changedData[field] = value;
|
|
||||||
});*/
|
|
||||||
|
|
||||||
try {
|
|
||||||
const result = await mutateAsync({ data: formData });
|
|
||||||
console.log(result);
|
|
||||||
|
|
||||||
if (result) {
|
|
||||||
showSuccessToast(t("pages.create.successTitle"), t("pages.create.successMsg"));
|
showSuccessToast(t("pages.create.successTitle"), t("pages.create.successMsg"));
|
||||||
navigate("/customers/list");
|
|
||||||
}
|
// El timeout es para que a React le dé tiempo a procesar
|
||||||
} catch (e) {
|
// el cambio de estado de isDirty / setIsDirty.
|
||||||
showErrorToast(t("pages.create.errorTitle"), (e as Error).message);
|
setTimeout(() => {
|
||||||
} finally {
|
navigate("/customers/list", {
|
||||||
|
state: { customerId: data.id, isNew: true },
|
||||||
|
replace: true,
|
||||||
|
});
|
||||||
|
}, 0);
|
||||||
|
},
|
||||||
|
onError(error) {
|
||||||
|
showErrorToast(t("pages.create.errorTitle"), error.message);
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleError = (errors: FieldErrors<CustomerFormData>) => {
|
const handleError = (errors: FieldErrors<CustomerFormData>) => {
|
||||||
|
|||||||
@ -1,20 +1,30 @@
|
|||||||
import * as z from "zod/v4";
|
import * as z from "zod/v4";
|
||||||
|
|
||||||
export const CustomerFormSchema = z.object({
|
export const CreateCustomerFormSchema = z.object({
|
||||||
reference: z.string().optional(),
|
reference: z.string().optional(),
|
||||||
|
|
||||||
is_company: z.string().optional(),
|
is_company: z.enum(["true", "false"]),
|
||||||
name: z.string().nonempty(),
|
name: z
|
||||||
|
.string({
|
||||||
|
error: "El nombre es obligatorio",
|
||||||
|
})
|
||||||
|
.min(1, "El nombre no puede estar vacío"),
|
||||||
trade_name: z.string().optional(),
|
trade_name: z.string().optional(),
|
||||||
tin: z.string().optional(),
|
tin: z.string().optional(),
|
||||||
default_taxes: z.array(z.string()).optional(), // completo (sustituye), o null => vaciar
|
default_taxes: z.array(z.string()).default([]),
|
||||||
|
|
||||||
street: z.string().optional(),
|
street: z.string().optional(),
|
||||||
street2: z.string().optional(),
|
street2: z.string().optional(),
|
||||||
city: z.string().optional(),
|
city: z.string().optional(),
|
||||||
province: z.string().optional(),
|
province: z.string().optional(),
|
||||||
postal_code: z.string().optional(),
|
postal_code: z.string().optional(),
|
||||||
country: z.string().optional(),
|
country: z
|
||||||
|
.string({
|
||||||
|
error: "El país es obligatorio",
|
||||||
|
})
|
||||||
|
.min(1, "El país no puede estar vacío")
|
||||||
|
.toLowerCase() // asegura minúsculas
|
||||||
|
.default("es"),
|
||||||
|
|
||||||
email_primary: z.string().optional(),
|
email_primary: z.string().optional(),
|
||||||
email_secondary: z.string().optional(),
|
email_secondary: z.string().optional(),
|
||||||
@ -28,20 +38,33 @@ export const CustomerFormSchema = z.object({
|
|||||||
|
|
||||||
legal_record: z.string().optional(),
|
legal_record: z.string().optional(),
|
||||||
|
|
||||||
language_code: z.string().nonempty(),
|
language_code: z
|
||||||
currency_code: z.string().nonempty(),
|
.string({
|
||||||
|
error: "El idioma es obligatorio",
|
||||||
|
})
|
||||||
|
.min(1, "Debe indicar un idioma")
|
||||||
|
.toUpperCase() // asegura mayúsculas
|
||||||
|
.default("es"),
|
||||||
|
|
||||||
|
currency_code: z
|
||||||
|
.string({
|
||||||
|
error: "La moneda es obligatoria",
|
||||||
|
})
|
||||||
|
.min(1, "La moneda no puede estar vacía")
|
||||||
|
.toUpperCase() // asegura mayúsculas
|
||||||
|
.default("EUR"),
|
||||||
});
|
});
|
||||||
|
|
||||||
export type CustomerFormData = z.infer<typeof CustomerFormSchema>;
|
export type CustomerFormData = z.infer<typeof CreateCustomerFormSchema>;
|
||||||
|
|
||||||
export const defaultCustomerFormData: CustomerFormData = {
|
export const defaultCustomerFormData: CustomerFormData = {
|
||||||
reference: "",
|
reference: "",
|
||||||
|
|
||||||
is_company: "false",
|
is_company: "true",
|
||||||
name: "",
|
name: "",
|
||||||
trade_name: "",
|
trade_name: "",
|
||||||
tin: "",
|
tin: "",
|
||||||
default_taxes: [],
|
default_taxes: ["iva_21"],
|
||||||
|
|
||||||
street: "",
|
street: "",
|
||||||
street2: "",
|
street2: "",
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user