From a4f928b7169c1ba6a74710dc8ba80f4433a12820 Mon Sep 17 00:00:00 2001 From: david Date: Tue, 23 Sep 2025 11:14:29 +0200 Subject: [PATCH] . --- .../use-unsaved-changes-notifier.tsx | 1 - .../components/editor/customer-edit-form.tsx | 16 +- .../web/hooks/use-create-customer-mutation.ts | 8 +- .../src/web/pages/create/customer-create.tsx | 4 +- .../src/web/schemas/customer.form.schema.ts | 6 +- .../verifactu-repository.interface.ts | 75 ++++++++++ .../api/domain/services/verifactu.service.ts | 139 ++++++++++++++++++ 7 files changed, 233 insertions(+), 16 deletions(-) create mode 100644 modules/verifactu/src/api/domain/repositories/verifactu-repository.interface.ts create mode 100644 modules/verifactu/src/api/domain/services/verifactu.service.ts diff --git a/modules/core/src/web/hooks/use-unsaved-changes-notifier/use-unsaved-changes-notifier.tsx b/modules/core/src/web/hooks/use-unsaved-changes-notifier/use-unsaved-changes-notifier.tsx index 66f8b47e..5ca0c852 100644 --- a/modules/core/src/web/hooks/use-unsaved-changes-notifier/use-unsaved-changes-notifier.tsx +++ b/modules/core/src/web/hooks/use-unsaved-changes-notifier/use-unsaved-changes-notifier.tsx @@ -86,7 +86,6 @@ export function UnsavedChangesProvider({ return ( -

hola

{children}
diff --git a/modules/customers/src/web/components/editor/customer-edit-form.tsx b/modules/customers/src/web/components/editor/customer-edit-form.tsx index 9a888b58..594585b1 100644 --- a/modules/customers/src/web/components/editor/customer-edit-form.tsx +++ b/modules/customers/src/web/components/editor/customer-edit-form.tsx @@ -49,13 +49,17 @@ export function CustomerEditForm({ return ( -
-
- - - - +
+
+ +
+
+ + + + +
diff --git a/modules/customers/src/web/hooks/use-create-customer-mutation.ts b/modules/customers/src/web/hooks/use-create-customer-mutation.ts index 0d2e85af..5dd2364a 100644 --- a/modules/customers/src/web/hooks/use-create-customer-mutation.ts +++ b/modules/customers/src/web/hooks/use-create-customer-mutation.ts @@ -1,18 +1,18 @@ import { useDataSource } from "@erp/core/hooks"; import { UniqueID } from "@repo/rdx-ddd"; import { useMutation, useQueryClient } from "@tanstack/react-query"; -import { CustomerCreateData, CustomerData } from "../schemas"; +import { CustomerFormData } from "../schemas"; import { CUSTOMERS_LIST_KEY } from "./use-update-customer-mutation"; type CreateCustomerPayload = { - data: CustomerCreateData; + data: CustomerFormData; }; export function useCreateCustomerMutation() { const queryClient = useQueryClient(); const dataSource = useDataSource(); - return useMutation({ + return useMutation({ mutationKey: ["customer:create"], mutationFn: async (payload) => { @@ -23,7 +23,7 @@ export function useCreateCustomerMutation() { ...data, id: customerId.toString(), }); - return created as CustomerData; + return created as CustomerFormData; }, onSuccess: () => { diff --git a/modules/customers/src/web/pages/create/customer-create.tsx b/modules/customers/src/web/pages/create/customer-create.tsx index 64df4ca1..1cdfdb84 100644 --- a/modules/customers/src/web/pages/create/customer-create.tsx +++ b/modules/customers/src/web/pages/create/customer-create.tsx @@ -25,6 +25,8 @@ export const CustomerCreate = () => { // 3) Submit con navegación condicionada por éxito const handleSubmit = async (formData: CustomerFormData) => { + console.log("formData => ", formData); + /*const changedData: Record = {}; Object.keys(dirtyFields).forEach((field) => { @@ -51,8 +53,6 @@ export const CustomerCreate = () => { // Aquí puedes manejar los errores, por ejemplo, mostrar un mensaje al usuario }; - console.log("render"); - return ( <> diff --git a/modules/customers/src/web/schemas/customer.form.schema.ts b/modules/customers/src/web/schemas/customer.form.schema.ts index 4d14346c..233e27dc 100644 --- a/modules/customers/src/web/schemas/customer.form.schema.ts +++ b/modules/customers/src/web/schemas/customer.form.schema.ts @@ -4,7 +4,7 @@ export const CustomerFormSchema = z.object({ reference: z.string().optional(), is_company: z.string().optional(), - name: z.string().optional(), + name: z.string().nonempty(), trade_name: z.string().optional(), tin: z.string().optional(), default_taxes: z.array(z.string()).optional(), // completo (sustituye), o null => vaciar @@ -28,8 +28,8 @@ export const CustomerFormSchema = z.object({ legal_record: z.string().optional(), - language_code: z.string().optional(), - currency_code: z.string().optional(), + language_code: z.string().nonempty(), + currency_code: z.string().nonempty(), }); export type CustomerFormData = z.infer; diff --git a/modules/verifactu/src/api/domain/repositories/verifactu-repository.interface.ts b/modules/verifactu/src/api/domain/repositories/verifactu-repository.interface.ts new file mode 100644 index 00000000..a266bfbb --- /dev/null +++ b/modules/verifactu/src/api/domain/repositories/verifactu-repository.interface.ts @@ -0,0 +1,75 @@ +import { Criteria } from "@repo/rdx-criteria/server"; +import { UniqueID } from "@repo/rdx-ddd"; +import { Collection, Result } from "@repo/rdx-utils"; +import { CustomerInvoiceListDTO } from "../../infrastructure"; +import { CustomerInvoice } from "../aggregates"; + +/** + * Interfaz del repositorio para el agregado `CustomerInvoice`. + * El escopado multitenant está representado por `companyId`. + */ +export interface ICustomerInvoiceRepository { + /** + * + * Persiste una nueva factura o actualiza una existente. + * Retorna el objeto actualizado tras la operación. + * + * @param invoice - El agregado a guardar. + * @param transaction - Transacción activa para la operación. + * @returns Result + */ + save(invoice: CustomerInvoice, transaction: any): Promise>; + + /** + * Comprueba si existe una factura con un `id` dentro de una `company`. + */ + existsByIdInCompany( + companyId: UniqueID, + id: UniqueID, + transaction?: any + ): Promise>; + + /** + * Recupera una factura por su ID y companyId. + * Devuelve un `NotFoundError` si no se encuentra. + */ + getByIdInCompany( + companyId: UniqueID, + id: UniqueID, + transaction?: any + ): Promise>; + + /** + * + * Consulta facturas dentro de una empresa usando un + * objeto Criteria (filtros, orden, paginación). + * El resultado está encapsulado en un objeto `Collection`. + * + * @param companyId - ID de la empresa. + * @param criteria - Criterios de búsqueda. + * @param transaction - Transacción activa para la operación. + * @returns Result, Error> + * + * @see Criteria + */ + findByCriteriaInCompany( + companyId: UniqueID, + criteria: Criteria, + transaction: any + ): Promise, Error>>; + + /** + * + * Elimina o marca como eliminada una factura dentro de una empresa. + * + * @param companyId - ID de la empresa. + * @param id - UUID de la factura a eliminar. + * @param transaction - Transacción activa para la operación. + * @returns Result + */ + deleteByIdInCompany( + companyId: UniqueID, + id: UniqueID, + transaction: any + ): Promise>; +} diff --git a/modules/verifactu/src/api/domain/services/verifactu.service.ts b/modules/verifactu/src/api/domain/services/verifactu.service.ts new file mode 100644 index 00000000..a0fa7535 --- /dev/null +++ b/modules/verifactu/src/api/domain/services/verifactu.service.ts @@ -0,0 +1,139 @@ +import { Criteria } from "@repo/rdx-criteria/server"; +import { UniqueID } from "@repo/rdx-ddd"; +import { Collection, Result } from "@repo/rdx-utils"; +import { Transaction } from "sequelize"; +import { CustomerInvoiceListDTO } from "../../infrastructure"; +import { CustomerInvoice, CustomerInvoicePatchProps, CustomerInvoiceProps } from "../aggregates"; +import { ICustomerInvoiceRepository } from "../repositories"; + +export class CustomerInvoiceService { + constructor(private readonly repository: ICustomerInvoiceRepository) {} + + /** + * Construye un nuevo agregado CustomerInvoice a partir de props validadas. + * + * @param companyId - Identificador de la empresa a la que pertenece el cliente. + * @param props - Las propiedades ya validadas para crear la factura. + * @param invoiceId - Identificador UUID de la factura (opcional). + * @returns Result - El agregado construido o un error si falla la creación. + */ + buildInvoiceInCompany( + companyId: UniqueID, + props: Omit, + invoiceId?: UniqueID + ): Result { + return CustomerInvoice.create({ ...props, companyId }, invoiceId); + } + + /** + * Guarda una instancia de CustomerInvoice en persistencia. + * + * @param invoice - El agregado a guardar. + * @param transaction - Transacción activa para la operación. + * @returns Result - El agregado guardado o un error si falla la operación. + */ + async saveInvoice( + invoice: CustomerInvoice, + transaction: any + ): Promise> { + return this.repository.save(invoice, transaction); + } + + /** + * + * Comprueba si existe o no en persistencia una factura con el ID proporcionado + * + * @param companyId - Identificador UUID de la empresa a la que pertenece el cliente. + * @param invoiceId - Identificador UUID de la factura. + * @param transaction - Transacción activa para la operación. + * @returns Result - Existe la factura o no. + */ + + async existsByIdInCompany( + companyId: UniqueID, + invoiceId: UniqueID, + transaction?: any + ): Promise> { + return this.repository.existsByIdInCompany(companyId, invoiceId, transaction); + } + + /** + * Obtiene una colección de facturas que cumplen con los filtros definidos en un objeto Criteria. + * + * @param companyId - Identificador UUID de la empresa a la que pertenece el cliente. + * @param criteria - Objeto con condiciones de filtro, paginación y orden. + * @param transaction - Transacción activa para la operación. + * @returns Result, Error> - Colección de facturas o error. + */ + async findInvoiceByCriteriaInCompany( + companyId: UniqueID, + criteria: Criteria, + transaction?: Transaction + ): Promise, Error>> { + return this.repository.findByCriteriaInCompany(companyId, criteria, transaction); + } + + /** + * Recupera una factura por su identificador único. + * + * @param invoiceId - Identificador UUID de la factura. + * @param transaction - Transacción activa para la operación. + * @returns Result - Factura encontrada o error. + */ + async getInvoiceByIdInCompany( + companyId: UniqueID, + invoiceId: UniqueID, + transaction?: Transaction + ): Promise> { + return await this.repository.getByIdInCompany(companyId, invoiceId, transaction); + } + + /** + * Actualiza parcialmente una factura existente con nuevos datos. + * No lo guarda en el repositorio. + * + * @param companyId - Identificador de la empresa a la que pertenece el cliente. + * @param invoiceId - Identificador de la factura a actualizar. + * @param changes - Subconjunto de props válidas para aplicar. + * @param transaction - Transacción activa para la operación. + * @returns Result - Factura actualizada o error. + */ + async updateInvoiceByIdInCompany( + companyId: UniqueID, + invoiceId: UniqueID, + changes: CustomerInvoicePatchProps, + transaction?: Transaction + ): Promise> { + // Verificar si la factura existe + const invoiceResult = await this.getInvoiceByIdInCompany(companyId, invoiceId, transaction); + + if (invoiceResult.isFailure) { + return Result.fail(invoiceResult.error); + } + + const invoice = invoiceResult.data; + const updatedInvoice = invoice.update(changes); + + if (updatedInvoice.isFailure) { + return Result.fail(updatedInvoice.error); + } + + return Result.ok(updatedInvoice.data); + } + + /** + * Elimina (o marca como eliminada) una factura según su ID. + * + * @param companyId - Identificador de la empresa a la que pertenece el cliente. + * @param invoiceId - Identificador UUID de la factura. + * @param transaction - Transacción activa para la operación. + * @returns Result - Resultado de la operación. + */ + async deleteInvoiceByIdInCompany( + companyId: UniqueID, + invoiceId: UniqueID, + transaction?: Transaction + ): Promise> { + return this.repository.deleteByIdInCompany(companyId, invoiceId, transaction); + } +}