import { EntityNotFoundError, SequelizeRepository, translateSequelizeError } from "@erp/core/api"; import { Criteria, CriteriaToSequelizeConverter } from "@repo/rdx-criteria/server"; import { UniqueID } from "@repo/rdx-ddd"; import { Collection, Result } from "@repo/rdx-utils"; import { Transaction } from "sequelize"; import { Customer, ICustomerRepository } from "../../domain"; import { ICustomerMapper } from "../mappers/customer.mapper"; import { CustomerModel } from "./customer.model"; export class CustomerRepository extends SequelizeRepository implements ICustomerRepository { private readonly mapper!: ICustomerMapper; constructor(mapper: ICustomerMapper) { super(); this.mapper = mapper; } /** * * Guarda un nuevo cliente o actualiza uno existente. * * @param customer - El cliente a guardar. * @param transaction - Transacción activa para la operación. * @returns Result */ async save(customer: Customer, transaction: Transaction): Promise> { try { const data = this.mapper.mapToPersistence(customer); const [instance] = await CustomerModel.upsert(data, { transaction, returning: true }); const savedCustomer = this.mapper.mapToDomain(instance); return savedCustomer; } catch (err: unknown) { return Result.fail(translateSequelizeError(err)); } } /** * Comprueba si existe un Customer con un `id` dentro de una `company`. * * @param companyId - Identificador UUID de la empresa a la que pertenece el cliente. * @param id - Identificador UUID del cliente. * @param transaction - Transacción activa para la operación. * @returns Result */ async existsByIdInCompany( companyId: UniqueID, id: UniqueID, transaction?: Transaction ): Promise> { try { const count = await CustomerModel.count({ where: { id: id.toString(), company_id: companyId.toString() }, transaction, }); return Result.ok(Boolean(count > 0)); } catch (error: any) { return Result.fail(translateSequelizeError(error)); } } /** * Recupera un cliente por su ID y companyId. * * @param companyId - Identificador UUID de la empresa a la que pertenece el cliente. * @param id - Identificador UUID del cliente. * @param transaction - Transacción activa para la operación. * @returns Result */ async getByIdInCompany( companyId: UniqueID, id: UniqueID, transaction?: Transaction ): Promise> { try { const row = await CustomerModel.findOne({ where: { id: id.toString(), company_id: companyId.toString() }, transaction, }); if (!row) { return Result.fail(new EntityNotFoundError("Customer", "id", id.toString())); } const customer = this.mapper.mapToDomain(row); return customer; } catch (error: any) { return Result.fail(translateSequelizeError(error)); } } /** * Recupera múltiples customers dentro de una empresa según un criterio dinámico (búsqueda, paginación, etc.). * * @param companyId - Identificador UUID de la empresa a la que pertenece el cliente. * @param criteria - Criterios de búsqueda. * @param transaction - Transacción activa para la operación. * @returns Result, Error> * * @see Criteria */ async findByCriteriaInCompany( companyId: UniqueID, criteria: Criteria, transaction?: Transaction ): Promise>> { try { const converter = new CriteriaToSequelizeConverter(); const query = converter.convert(criteria); query.where = { ...query.where, company_id: companyId.toString(), }; const instances = await CustomerModel.findAll({ ...query, transaction, }); return this.mapper.mapArrayToDomain(instances); } catch (err: unknown) { return Result.fail(translateSequelizeError(err)); } } /** * * Elimina o marca como eliminado un cliente. * * @param companyId - Identificador UUID de la empresa a la que pertenece el cliente. * @param id - UUID del cliente a eliminar. * @param transaction - Transacción activa para la operación. * @returns Result */ async deleteByIdInCompany( companyId: UniqueID, id: UniqueID, transaction: Transaction ): Promise> { try { const deleted = await CustomerModel.destroy({ where: { id: id.toString(), company_id: companyId.toString() }, transaction, }); return Result.ok(); } catch (err: unknown) { return Result.fail(translateSequelizeError(err)); } } }