From 04184ebf1d57627e113b49853f9e5bbc9207cb6c Mon Sep 17 00:00:00 2001 From: david Date: Sat, 4 Apr 2026 19:38:09 +0200 Subject: [PATCH] Repaso de clientes --- .../response/create-customer.result.dto.ts | 2 +- .../use-customer-create.controller.ts | 6 +- .../utils/build-customer-create-params.ts | 56 ++++++++++--------- .../adapters/get-customer-by-id.adapter.ts | 4 +- .../src/web/shared/api/create-customer.api.ts | 20 +++++-- .../shared/api/delete-customer-by-id.api.ts | 11 ++-- .../web/shared/api/get-customer-by-id.api.ts | 16 ++---- modules/customers/src/web/shared/api/index.ts | 2 +- ...i.ts => list-customers-by-criteria.api.ts} | 11 ++-- .../shared/api/update-customer-by-id.api.ts | 2 +- .../hooks/use-customer-create-mutation.ts | 9 +-- .../hooks/use-customer-delete-mutation.ts | 56 +++++++++---------- .../use-customer-update.controller.ts | 2 +- 13 files changed, 98 insertions(+), 99 deletions(-) rename modules/customers/src/web/shared/api/{get-list-customers-by-criteria.api.ts => list-customers-by-criteria.api.ts} (77%) diff --git a/modules/customers/src/common/dto/response/create-customer.result.dto.ts b/modules/customers/src/common/dto/response/create-customer.result.dto.ts index 32540d38..6d266a4f 100644 --- a/modules/customers/src/common/dto/response/create-customer.result.dto.ts +++ b/modules/customers/src/common/dto/response/create-customer.result.dto.ts @@ -4,4 +4,4 @@ import { } from "./get-customer-by-id.response.dto"; export const CreateCustomerResponseSchema = GetCustomerByIdResponseSchema; -export type CustomerCreationResponseDTO = GetCustomerByIdResponseDTO; +export type CreateCustomerResponseDTO = GetCustomerByIdResponseDTO; diff --git a/modules/customers/src/web/create/controllers/use-customer-create.controller.ts b/modules/customers/src/web/create/controllers/use-customer-create.controller.ts index 77aa00d7..dafe14b6 100644 --- a/modules/customers/src/web/create/controllers/use-customer-create.controller.ts +++ b/modules/customers/src/web/create/controllers/use-customer-create.controller.ts @@ -48,11 +48,11 @@ export const useCustomerCreateController = (options?: UseCustomerCreateControlle const submitHandler = form.handleSubmit( async (formData) => { - const inputPayload: CreateCustomerParams = buildCreateCustomerParams(formData); + const params: CreateCustomerParams = buildCreateCustomerParams(formData); try { // Enviamos cambios al servidor - const created = await mutateAsync(inputPayload); // payload es CustomerCreatePayload + const created = await mutateAsync(params); // payload es CustomerCreatePayload if (options?.successToasts !== false) { showSuccessToast( @@ -69,7 +69,7 @@ export const useCustomerCreateController = (options?: UseCustomerCreateControlle showErrorToast(t("pages.create.error.title"), normalizedError.message); } - options?.onError?.(normalizedError, inputPayload); + options?.onError?.(normalizedError, params); } }, (errors: FieldErrors) => { diff --git a/modules/customers/src/web/create/utils/build-customer-create-params.ts b/modules/customers/src/web/create/utils/build-customer-create-params.ts index 01f873bb..2a3a6a9d 100644 --- a/modules/customers/src/web/create/utils/build-customer-create-params.ts +++ b/modules/customers/src/web/create/utils/build-customer-create-params.ts @@ -21,38 +21,42 @@ import type { CustomerCreateForm } from "../entities"; */ export const buildCreateCustomerParams = (formData: CustomerCreateForm): CreateCustomerParams => { + // La API de creación de cliente requiere un ID único para el nuevo cliente + const id = UniqueID.generateNewID().toString(); + return { - // Generamos un ID único para el nuevo cliente. - // La API de creación de cliente requiere un ID, - id: UniqueID.generateNewID().toString(), + id, - reference: formData.reference, - is_company: formData.isCompany ? "1" : "0", - name: formData.name, - trade_name: formData.tradeName, - tin: formData.tin, - default_taxes: formData.defaultTaxes, + data: { + id, + reference: formData.reference, + is_company: formData.isCompany ? "1" : "0", + name: formData.name, + trade_name: formData.tradeName, + tin: formData.tin, + default_taxes: formData.defaultTaxes, - street: formData.street, - street2: formData.street2, - city: formData.city, - province: formData.province, - postal_code: formData.postalCode, - country: formData.country, + street: formData.street, + street2: formData.street2, + city: formData.city, + province: formData.province, + postal_code: formData.postalCode, + country: formData.country, - email_primary: formData.primaryEmail, - email_secondary: formData.secondaryEmail, - phone_primary: formData.primaryPhone, - phone_secondary: formData.secondaryPhone, - mobile_primary: formData.primaryMobile, - mobile_secondary: formData.secondaryMobile, + email_primary: formData.primaryEmail, + email_secondary: formData.secondaryEmail, + phone_primary: formData.primaryPhone, + phone_secondary: formData.secondaryPhone, + mobile_primary: formData.primaryMobile, + mobile_secondary: formData.secondaryMobile, - fax: formData.fax, - website: formData.website, + fax: formData.fax, + website: formData.website, - legal_record: formData.legalRecord, + legal_record: formData.legalRecord, - language_code: formData.languageCode, - currency_code: formData.currencyCode, + language_code: formData.languageCode, + currency_code: formData.currencyCode, + }, }; }; diff --git a/modules/customers/src/web/shared/adapters/get-customer-by-id.adapter.ts b/modules/customers/src/web/shared/adapters/get-customer-by-id.adapter.ts index 246f3f15..8bc4e003 100644 --- a/modules/customers/src/web/shared/adapters/get-customer-by-id.adapter.ts +++ b/modules/customers/src/web/shared/adapters/get-customer-by-id.adapter.ts @@ -1,4 +1,4 @@ -import type { CustomerCreationResponseDTO } from "@erp/customers/common"; +import type { CreateCustomerResponseDTO } from "@erp/customers/common"; import type { GetCustomerByIdResult, UpdateCustomerByIdResult } from "../api"; import type { Customer } from "../entities"; @@ -18,7 +18,7 @@ import type { Customer } from "../entities"; export const GetCustomerByIdAdapter = { fromDTO( - dto: GetCustomerByIdResult | CustomerCreationResponseDTO | UpdateCustomerByIdResult, + dto: GetCustomerByIdResult | CreateCustomerResponseDTO | UpdateCustomerByIdResult, context?: unknown ): Customer { const taxesAdapter = (taxes: string) => diff --git a/modules/customers/src/web/shared/api/create-customer.api.ts b/modules/customers/src/web/shared/api/create-customer.api.ts index 2ed71617..44eb4245 100644 --- a/modules/customers/src/web/shared/api/create-customer.api.ts +++ b/modules/customers/src/web/shared/api/create-customer.api.ts @@ -1,6 +1,6 @@ import type { IDataSource } from "@erp/core/client"; -import type { CreateCustomerRequestDTO, CustomerCreationResponseDTO } from "../../../common"; +import type { CreateCustomerRequestDTO, CreateCustomerResponseDTO } from "../../../common"; /** * Crea un nuevo cliente en el sistema utilizando la fuente de datos proporcionada. @@ -11,12 +11,22 @@ import type { CreateCustomerRequestDTO, CustomerCreationResponseDTO } from "../. * @throws Error si el ID del cliente no es proporcionado o si la creación falla. */ -export type CreateCustomerParams = CreateCustomerRequestDTO; +export interface CreateCustomerParams { + id: string; + data: CreateCustomerRequestDTO; +} -export type CreateCustomerResult = CustomerCreationResponseDTO; +export type CreateCustomerResult = CreateCustomerResponseDTO; export function createCustomer(dataSource: IDataSource, params: CreateCustomerParams) { - const { id } = params; + const { id, data } = params; + if (!id) throw new Error("customerId is required"); - return dataSource.createOne("customers", params); + + if (id !== data.id) throw new Error("customerId in params must match id in data"); + + return dataSource.createOne( + "customers", + data + ); } diff --git a/modules/customers/src/web/shared/api/delete-customer-by-id.api.ts b/modules/customers/src/web/shared/api/delete-customer-by-id.api.ts index d3acdb5c..9a69c971 100644 --- a/modules/customers/src/web/shared/api/delete-customer-by-id.api.ts +++ b/modules/customers/src/web/shared/api/delete-customer-by-id.api.ts @@ -5,23 +5,22 @@ import type { IDataSource } from "@erp/core/client"; * * @param dataSource - La fuente de datos para interactuar con la API. * @param params - Los parámetros necesarios para eliminar el cliente. - * @param signal - Un AbortSignal para cancelar la solicitud si es necesario. * @returns Una promesa que se resuelve cuando el cliente ha sido eliminado exitosamente. * @throws Error si el ID del cliente no es proporcionado o si la eliminación falla. */ -export type DeleteCustomerByIdParams = { +export interface DeleteCustomerByIdParams { id: string; -}; + signal?: AbortSignal; +} export type DeleteCustomerByIdResult = void; export function deleteCustomerById( dataSource: IDataSource, - params: DeleteCustomerByIdParams, - signal?: AbortSignal + params: DeleteCustomerByIdParams ): Promise { - const { id } = params; + const { id, signal } = params; if (!id) throw new Error("customerId is required"); return dataSource.deleteOne("customers", id, { signal, diff --git a/modules/customers/src/web/shared/api/get-customer-by-id.api.ts b/modules/customers/src/web/shared/api/get-customer-by-id.api.ts index 612fec98..ab05869b 100644 --- a/modules/customers/src/web/shared/api/get-customer-by-id.api.ts +++ b/modules/customers/src/web/shared/api/get-customer-by-id.api.ts @@ -7,23 +7,19 @@ import type { GetCustomerByIdResponseDTO } from "../../../common"; * * @param dataSource - La fuente de datos para interactuar con la API. * @param params - Los parámetros necesarios para obtener el cliente, incluyendo su ID. - * @param signal - Un AbortSignal para cancelar la solicitud si es necesario. * @returns Una promesa que resuelve con los detalles del cliente solicitado. * @throws Error si el ID del cliente no es proporcionado o si la recuperación falla. */ -export type GetCustomerByIdParams = { +export interface GetCustomerByIdParams { id: string; -}; + signal?: AbortSignal; +} export type GetCustomerByIdResult = GetCustomerByIdResponseDTO; -export function getCustomerById( - dataSource: IDataSource, - params: GetCustomerByIdParams, - signal?: AbortSignal -) { - const { id } = params; +export function getCustomerById(dataSource: IDataSource, params: GetCustomerByIdParams) { + const { id, signal } = params; if (!id) throw new Error("customerId is required"); - return dataSource.getOne("customers", id, { signal }); + return dataSource.getOne("customers", id, { signal }); } diff --git a/modules/customers/src/web/shared/api/index.ts b/modules/customers/src/web/shared/api/index.ts index 9ba88218..24bb70d5 100644 --- a/modules/customers/src/web/shared/api/index.ts +++ b/modules/customers/src/web/shared/api/index.ts @@ -1,5 +1,5 @@ export * from "./create-customer.api"; export * from "./delete-customer-by-id.api"; export * from "./get-customer-by-id.api"; -export * from "./get-list-customers-by-criteria.api"; +export * from "./list-customers-by-criteria.api"; export * from "./update-customer-by-id.api"; diff --git a/modules/customers/src/web/shared/api/get-list-customers-by-criteria.api.ts b/modules/customers/src/web/shared/api/list-customers-by-criteria.api.ts similarity index 77% rename from modules/customers/src/web/shared/api/get-list-customers-by-criteria.api.ts rename to modules/customers/src/web/shared/api/list-customers-by-criteria.api.ts index b27ad19b..3e2a5509 100644 --- a/modules/customers/src/web/shared/api/get-list-customers-by-criteria.api.ts +++ b/modules/customers/src/web/shared/api/list-customers-by-criteria.api.ts @@ -9,24 +9,23 @@ import type { ListCustomersResponseDTO } from "../../../common"; * * @param dataSource - La fuente de datos para interactuar con la API. * @param params - Los parámetros necesarios para listar los clientes, incluyendo los criterios de búsqueda. - * @param signal - Un AbortSignal para cancelar la solicitud si es necesario. * @returns Una promesa que resuelve con una lista de clientes que cumplen con los criterios especificados. * @throws Error si la recuperación de la lista de clientes falla. */ export type ListCustomersByCriteriaParams = { - criteria: CriteriaDTO; + criteria?: CriteriaDTO; + signal?: AbortSignal; }; export type ListCustomersResult = ListCustomersResponseDTO; export function getListCustomersByCriteria( dataSource: IDataSource, - params: ListCustomersByCriteriaParams, - signal?: AbortSignal + params: ListCustomersByCriteriaParams ): Promise { - const { criteria } = params; - return dataSource.getList("customers", { + const { criteria, signal } = params || { criteria: undefined, signal: undefined }; + return dataSource.getList("customers", { signal, ...criteria, }); diff --git a/modules/customers/src/web/shared/api/update-customer-by-id.api.ts b/modules/customers/src/web/shared/api/update-customer-by-id.api.ts index 81cfb50e..4994ed56 100644 --- a/modules/customers/src/web/shared/api/update-customer-by-id.api.ts +++ b/modules/customers/src/web/shared/api/update-customer-by-id.api.ts @@ -25,7 +25,7 @@ export function updateCustomerById( const { id, data } = params; if (!id) throw new Error("customerId is required"); - return dataSource.updateOne( + return dataSource.updateOne( "customers", id, data diff --git a/modules/customers/src/web/shared/hooks/use-customer-create-mutation.ts b/modules/customers/src/web/shared/hooks/use-customer-create-mutation.ts index ca66f05b..20579a6d 100644 --- a/modules/customers/src/web/shared/hooks/use-customer-create-mutation.ts +++ b/modules/customers/src/web/shared/hooks/use-customer-create-mutation.ts @@ -1,5 +1,5 @@ import { useDataSource } from "@erp/core/hooks"; -import { UniqueID, ValidationErrorCollection } from "@repo/rdx-ddd"; +import { ValidationErrorCollection } from "@repo/rdx-ddd"; import { type DefaultError, useMutation, useQueryClient } from "@tanstack/react-query"; import { CreateCustomerRequestSchema } from "../../../common"; @@ -25,15 +25,12 @@ export const useCustomerCreateMutation = () => { mutationKey: CUSTOMER_CREATE_KEY, mutationFn: async (payload) => { - const id = UniqueID.generateNewID().toString(); - const payloadWithId: CreateCustomerParams = { ...payload, id }; - - const result = schema.safeParse(payloadWithId); + const result = schema.safeParse(payload); if (!result.success) { throw new ValidationErrorCollection("Validation failed", toValidationErrors(result.error)); } - const dto: CreateCustomerResult = await createCustomer(dataSource, payloadWithId); + const dto: CreateCustomerResult = await createCustomer(dataSource, payload); return GetCustomerByIdAdapter.fromDTO(dto); }, diff --git a/modules/customers/src/web/shared/hooks/use-customer-delete-mutation.ts b/modules/customers/src/web/shared/hooks/use-customer-delete-mutation.ts index 3295d6b9..7437386d 100644 --- a/modules/customers/src/web/shared/hooks/use-customer-delete-mutation.ts +++ b/modules/customers/src/web/shared/hooks/use-customer-delete-mutation.ts @@ -1,11 +1,7 @@ import { useDataSource } from "@erp/core/hooks"; import { type DefaultError, useMutation, useQueryClient } from "@tanstack/react-query"; -import { - type DeleteCustomerByIdParams, - type DeleteCustomerByIdResult, - deleteCustomerById, -} from "../api"; +import { type DeleteCustomerByIdParams, deleteCustomerById } from "../api"; import { type DeleteCustomerCacheContext, @@ -22,33 +18,31 @@ export const useCustomerDeleteMutation = () => { const queryClient = useQueryClient(); const dataSource = useDataSource(); - return useMutation< - DeleteCustomerByIdResult, - DefaultError, - DeleteCustomerByIdParams, - DeleteCustomerContext - >({ - mutationKey: CUSTOMER_DELETE_KEY, - mutationFn: async ({ id }) => { - if (!id) { - throw new Error("customerId is required"); - } + return useMutation<{ id: string }, DefaultError, DeleteCustomerByIdParams, DeleteCustomerContext>( + { + mutationKey: CUSTOMER_DELETE_KEY, + mutationFn: async ({ id, signal }) => { + if (!id) { + throw new Error("customerId is required"); + } - await deleteCustomerById(dataSource, { id }, new AbortController().signal); - }, - onMutate: async ({ id }) => { - return prepareDeleteCustomerOptimisticUpdate(queryClient, id); - }, + await deleteCustomerById(dataSource, { id, signal }); + return { id }; + }, + onMutate: async ({ id }) => { + return prepareDeleteCustomerOptimisticUpdate(queryClient, id); + }, - onError: (_error, _variables, context) => { - rollbackDeleteCustomerOptimisticUpdate(queryClient, context); - }, + onError: (_error, _variables, context) => { + rollbackDeleteCustomerOptimisticUpdate(queryClient, context); + }, - onSuccess: (_, variables) => { - finalizeDeletedCustomerCaches(queryClient, variables.id); - }, - onSettled: async () => { - await invalidateCustomerListQueries(queryClient); - }, - }); + onSuccess: ({ id }) => { + finalizeDeletedCustomerCaches(queryClient, id); + }, + onSettled: async () => { + await invalidateCustomerListQueries(queryClient); + }, + } + ); }; diff --git a/modules/customers/src/web/update/controllers/use-customer-update.controller.ts b/modules/customers/src/web/update/controllers/use-customer-update.controller.ts index 14f148db..3e0d4a92 100644 --- a/modules/customers/src/web/update/controllers/use-customer-update.controller.ts +++ b/modules/customers/src/web/update/controllers/use-customer-update.controller.ts @@ -98,8 +98,8 @@ export const useCustomerUpdateController = ( } const previousData = customerData; - const patchData = buildCustomerUpdatePatch(formData, dirtyFields); + const patchData = buildCustomerUpdatePatch(formData, dirtyFields); const params: UpdateCustomerByIdParams = buildUpdateCustomerByIdParams(customerId, patchData); try {