Clientes
This commit is contained in:
parent
bec5a54756
commit
01ca0bd5dc
@ -134,8 +134,8 @@ export const CustomerInvoicesListGrid = () => {
|
||||
resizable: true,
|
||||
},
|
||||
pagination: true,
|
||||
paginationPageSize: 10,
|
||||
paginationPageSizeSelector: [10, 20, 30, 50],
|
||||
paginationPageSize: 15,
|
||||
paginationPageSizeSelector: [10, 15, 20, 30, 50],
|
||||
localeText: AG_GRID_LOCALE_ES,
|
||||
}),
|
||||
[autoSizeStrategy, colDefs]
|
||||
|
||||
@ -4,18 +4,18 @@ export const CreateCustomerRequestSchema = z.object({
|
||||
id: z.string().nonempty(),
|
||||
|
||||
reference: z.string().optional(),
|
||||
is_company: z.string().toLowerCase().default("false"),
|
||||
is_company: z.string().toLowerCase().default("true"),
|
||||
name: z.string(),
|
||||
trade_name: 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(),
|
||||
street2: z.string().optional(),
|
||||
city: z.string().optional(),
|
||||
province: 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_secondary: z.string().optional(),
|
||||
|
||||
@ -31,7 +31,11 @@ export const CustomersListGrid = () => {
|
||||
isLoading: isLoadingCustomers,
|
||||
isError: isLoadError,
|
||||
error: loadError,
|
||||
} = useCustomersQuery();
|
||||
} = useCustomersQuery({
|
||||
pagination: {
|
||||
pageSize: 999,
|
||||
},
|
||||
});
|
||||
|
||||
// Column Definitions: Defines & controls grid columns.
|
||||
const [colDefs] = useState<ColDef[]>([
|
||||
@ -113,8 +117,8 @@ export const CustomersListGrid = () => {
|
||||
resizable: true,
|
||||
},
|
||||
pagination: true,
|
||||
paginationPageSize: 10,
|
||||
paginationPageSizeSelector: [10, 20, 30, 50],
|
||||
paginationPageSize: 15,
|
||||
paginationPageSizeSelector: [10, 15, 20, 30, 50],
|
||||
localeText: AG_GRID_LOCALE_ES,
|
||||
}),
|
||||
[autoSizeStrategy, colDefs]
|
||||
|
||||
@ -22,6 +22,7 @@ export const CustomerBasicInfoFields = () => {
|
||||
const { control } = useFormContext<CustomerFormData>();
|
||||
|
||||
const isCompany = useWatch({
|
||||
control,
|
||||
name: "is_company",
|
||||
defaultValue: "true",
|
||||
});
|
||||
@ -53,7 +54,9 @@ export const CustomerBasicInfoFields = () => {
|
||||
<FormLabel>{t("form_fields.customer_type.label")}</FormLabel>
|
||||
<FormControl>
|
||||
<RadioGroup
|
||||
onValueChange={field.onChange}
|
||||
onValueChange={(value: string) => {
|
||||
field.onChange(value === "false" ? "false" : "true");
|
||||
}}
|
||||
defaultValue={field.value ? "true" : "false"}
|
||||
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 { useEffect } from "react";
|
||||
import { CustomerFormData, CustomerFormSchema } from "../../schemas";
|
||||
import { CreateCustomerFormSchema, CustomerFormData } from "../../schemas";
|
||||
import { FormDebug } from "../form-debug";
|
||||
import { CustomerAdditionalConfigFields } from "./customer-additional-config-fields";
|
||||
import { CustomerAddressFields } from "./customer-address-fields";
|
||||
@ -27,7 +27,7 @@ export function CustomerEditForm({
|
||||
onDirtyChange,
|
||||
}: CustomerFormProps) {
|
||||
const form = useForm<CustomerFormData>({
|
||||
resolver: zodResolver(CustomerFormSchema),
|
||||
resolver: zodResolver(CreateCustomerFormSchema),
|
||||
defaultValues: initialValues,
|
||||
disabled,
|
||||
});
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
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 { CreateCustomerRequestSchema, CustomerCreationResponseDTO } from "../../common";
|
||||
import { CustomerFormData } from "../schemas";
|
||||
import { CUSTOMERS_LIST_KEY } from "./use-update-customer-mutation";
|
||||
|
||||
@ -11,19 +12,35 @@ type CreateCustomerPayload = {
|
||||
export function useCreateCustomerMutation() {
|
||||
const queryClient = useQueryClient();
|
||||
const dataSource = useDataSource();
|
||||
const schema = CreateCustomerRequestSchema;
|
||||
|
||||
return useMutation<CustomerFormData, Error, CreateCustomerPayload>({
|
||||
return useMutation<CustomerCreationResponseDTO, Error, CreateCustomerPayload>({
|
||||
mutationKey: ["customer:create"],
|
||||
|
||||
mutationFn: async (payload) => {
|
||||
const { data } = payload;
|
||||
const customerId = UniqueID.generateNewID();
|
||||
|
||||
const created = await dataSource.createOne("customers", {
|
||||
const newCustomerData = {
|
||||
...data,
|
||||
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: () => {
|
||||
|
||||
@ -17,35 +17,35 @@ export const CustomerCreate = () => {
|
||||
|
||||
// 2) Estado de creación (mutación)
|
||||
const {
|
||||
mutateAsync,
|
||||
mutate,
|
||||
isPending: isCreating,
|
||||
isError: isCreateError,
|
||||
error: createError,
|
||||
} = useCreateCustomerMutation();
|
||||
|
||||
// 3) Submit con navegación condicionada por éxito
|
||||
const handleSubmit = async (formData: CustomerFormData) => {
|
||||
console.log("formData => ", formData);
|
||||
const handleSubmit = (formData: CustomerFormData) => {
|
||||
mutate(
|
||||
{ data: formData },
|
||||
{
|
||||
onSuccess(data) {
|
||||
setIsDirty(false);
|
||||
showSuccessToast(t("pages.create.successTitle"), t("pages.create.successMsg"));
|
||||
|
||||
/*const changedData: Record<string, string> = {};
|
||||
|
||||
Object.keys(dirtyFields).forEach((field) => {
|
||||
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"));
|
||||
navigate("/customers/list");
|
||||
// El timeout es para que a React le dé tiempo a procesar
|
||||
// el cambio de estado de isDirty / setIsDirty.
|
||||
setTimeout(() => {
|
||||
navigate("/customers/list", {
|
||||
state: { customerId: data.id, isNew: true },
|
||||
replace: true,
|
||||
});
|
||||
}, 0);
|
||||
},
|
||||
onError(error) {
|
||||
showErrorToast(t("pages.create.errorTitle"), error.message);
|
||||
},
|
||||
}
|
||||
} catch (e) {
|
||||
showErrorToast(t("pages.create.errorTitle"), (e as Error).message);
|
||||
} finally {
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
const handleError = (errors: FieldErrors<CustomerFormData>) => {
|
||||
|
||||
@ -1,20 +1,30 @@
|
||||
import * as z from "zod/v4";
|
||||
|
||||
export const CustomerFormSchema = z.object({
|
||||
export const CreateCustomerFormSchema = z.object({
|
||||
reference: z.string().optional(),
|
||||
|
||||
is_company: z.string().optional(),
|
||||
name: z.string().nonempty(),
|
||||
is_company: z.enum(["true", "false"]),
|
||||
name: z
|
||||
.string({
|
||||
error: "El nombre es obligatorio",
|
||||
})
|
||||
.min(1, "El nombre no puede estar vacío"),
|
||||
trade_name: 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(),
|
||||
street2: z.string().optional(),
|
||||
city: z.string().optional(),
|
||||
province: 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_secondary: z.string().optional(),
|
||||
@ -28,20 +38,33 @@ export const CustomerFormSchema = z.object({
|
||||
|
||||
legal_record: z.string().optional(),
|
||||
|
||||
language_code: z.string().nonempty(),
|
||||
currency_code: z.string().nonempty(),
|
||||
language_code: z
|
||||
.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 = {
|
||||
reference: "",
|
||||
|
||||
is_company: "false",
|
||||
is_company: "true",
|
||||
name: "",
|
||||
trade_name: "",
|
||||
tin: "",
|
||||
default_taxes: [],
|
||||
default_taxes: ["iva_21"],
|
||||
|
||||
street: "",
|
||||
street2: "",
|
||||
|
||||
Loading…
Reference in New Issue
Block a user