diff --git a/apps/server/archive/contexts/accounts/application/create-account.use-case.ts b/apps/server/archive/contexts/accounts/application/create-account.use-case.ts deleted file mode 100644 index d0409f5f..00000000 --- a/apps/server/archive/contexts/accounts/application/create-account.use-case.ts +++ /dev/null @@ -1,99 +0,0 @@ -import { - EmailAddress, - PhoneNumber, - PostalAddress, - TINNumber, - UniqueID, -} from "@/core/common/domain"; - -import { - type Account, - AccountStatus, - type IAccountProps, - type IAccountService, -} from "@/contexts/accounts/domain"; -import { ITransactionManager } from "@/core/common/infrastructure/database"; -import { logger } from "@/core/logger"; -import { Maybe, Result } from "@repo/rdx-utils"; -import { ICreateAccountRequestDTO } from "../presentation"; - -export class CreateAccountUseCase { - constructor( - private readonly accountService: IAccountService, - private readonly transactionManager: ITransactionManager - ) {} - - public execute( - accountID: UniqueID, - dto: ICreateAccountRequestDTO - ): Promise> { - return this.transactionManager.complete(async (transaction) => { - try { - const validOrErrors = this.validateAccountData(dto); - if (validOrErrors.isFailure) { - return Result.fail(validOrErrors.error); - } - - const data = validOrErrors.data; - - // Update account with dto - return await this.accountService.createAccount(accountID, data, transaction); - } catch (error: unknown) { - logger.error(error as Error); - return Result.fail(error as Error); - } - }); - } - - private validateAccountData(dto: ICreateAccountRequestDTO): Result { - const errors: Error[] = []; - - const tinOrError = TINNumber.create(dto.tin); - const emailOrError = EmailAddress.create(dto.email); - const phoneOrError = PhoneNumber.create(dto.phone); - const faxOrError = PhoneNumber.createNullable(dto.fax); - const postalAddressOrError = PostalAddress.create({ - street: dto.street, - city: dto.city, - state: dto.state, - postalCode: dto.postal_code, - country: dto.country, - }); - - const result = Result.combine([ - tinOrError, - emailOrError, - phoneOrError, - faxOrError, - postalAddressOrError, - ]); - - if (result.isFailure) { - return Result.fail(result.error); - } - - const validatedData: IAccountProps = { - status: AccountStatus.createInactive(), - isFreelancer: dto.is_companyr, - name: dto.name, - tradeName: dto.trade_name ? Maybe.some(dto.trade_name) : Maybe.none(), - tin: tinOrError.data, - address: postalAddressOrError.data, - email: emailOrError.data, - phone: phoneOrError.data, - fax: faxOrError.data, - website: dto.website ? Maybe.some(dto.website) : Maybe.none(), - legalRecord: dto.legal_record, - defaultTax: dto.default_tax, - langCode: dto.language_code, - currencyCode: dto.currency_code, - logo: dto.logo ? Maybe.some(dto.logo) : Maybe.none(), - }; - - if (errors.length > 0) { - const message = errors.map((err) => err.message).toString(); - return Result.fail(new Error(message)); - } - return Result.ok(validatedData); - } -} diff --git a/apps/server/archive/contexts/accounts/application/get-account.use-case.ts b/apps/server/archive/contexts/accounts/application/get-account.use-case.ts deleted file mode 100644 index 385e927c..00000000 --- a/apps/server/archive/contexts/accounts/application/get-account.use-case.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { Account, IAccountService } from "@/contexts/accounts/domain"; -import { UniqueID } from "@/core/common/domain"; -import { ITransactionManager } from "@/core/common/infrastructure/database"; -import { logger } from "@/core/logger"; -import { Result } from "@repo/rdx-utils"; - -export class GetAccountUseCase { - constructor( - private readonly accountService: IAccountService, - private readonly transactionManager: ITransactionManager - ) {} - - public execute(accountID: UniqueID): Promise> { - return this.transactionManager.complete(async (transaction) => { - try { - return await this.accountService.findAccountById(accountID, transaction); - } catch (error: unknown) { - logger.error(error as Error); - return Result.fail(error as Error); - } - }); - } -} diff --git a/apps/server/archive/contexts/accounts/application/index.ts b/apps/server/archive/contexts/accounts/application/index.ts deleted file mode 100644 index 0f17dc7a..00000000 --- a/apps/server/archive/contexts/accounts/application/index.ts +++ /dev/null @@ -1,4 +0,0 @@ -export * from "./create-account.use-case"; -export * from "./get-account.use-case"; -export * from "./list-accounts.use-case"; -export * from "./update-account.use-case"; diff --git a/apps/server/archive/contexts/accounts/application/list-accounts.use-case.ts b/apps/server/archive/contexts/accounts/application/list-accounts.use-case.ts deleted file mode 100644 index bbf0c3cc..00000000 --- a/apps/server/archive/contexts/accounts/application/list-accounts.use-case.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { Account, IAccountService } from "@/contexts/accounts/domain"; -import { ITransactionManager } from "@/core/common/infrastructure/database"; -import { Collection, Result } from "@repo/rdx-utils"; - -export class ListAccountsUseCase { - constructor( - private readonly accountService: IAccountService, - private readonly transactionManager: ITransactionManager - ) {} - - public execute(): Promise, Error>> { - return this.transactionManager.complete(async (transaction) => { - try { - return await this.accountService.findAccounts(transaction); - } catch (error: unknown) { - logger.error(error as Error); - return Result.fail(error as Error); - } - }); - } -} diff --git a/apps/server/archive/contexts/accounts/application/update-account.use-case.test.ts b/apps/server/archive/contexts/accounts/application/update-account.use-case.test.ts deleted file mode 100644 index c88249ea..00000000 --- a/apps/server/archive/contexts/accounts/application/update-account.use-case.test.ts +++ /dev/null @@ -1,46 +0,0 @@ -import { UniqueID } from "@/core/common/domain"; -import { TransactionManager } from "@/core/common/infrastructure/database"; -import { Result } from "@repo/rdx-utils"; -import { AccountService } from "../domain"; -import { UpdateAccountUseCase } from "./update-account.use-case"; - -const mockAccountService: AccountService = { - updateAccountById: jest.fn(), -} as unknown as AccountService; - -const mockTransactionManager: TransactionManager = { - complete(work: (transaction: any) => Promise): void { - jest.fn(); - }, -} as unknown as TransactionManager; - -const id = UniqueID.create("", true).data; - -describe("UpdateAccountUseCase", () => { - let updateAccountUseCase: UpdateAccountUseCase; - - beforeEach(() => { - updateAccountUseCase = new UpdateAccountUseCase(mockAccountService, mockTransactionManager); - }); - - it("deber铆a actualizar una cuenta y retornar un DTO", async () => { - const mockUpdatedAccount = { id: "123", name: "Nuevo Nombre" }; - (mockAccountService.updateAccountById as jest.Mock).mockResolvedValue( - Result.ok(mockUpdatedAccount) - ); - - const result = await updateAccountUseCase.execute(id, { name: "Nuevo Nombre" }); - expect(result.isSuccess).toBe(true); - expect(result.data.name).toBe("Nuevo Nombre"); - }); - - it("deber铆a retornar error si la actualizaci贸n falla", async () => { - (mockAccountService.updateAccountById as jest.Mock).mockResolvedValue( - Result.fail(new Error("Account not found")) - ); - - const result = await updateAccountUseCase.execute(id, { name: "Nuevo Nombre" }); - expect(result.isFailure).toBe(true); - expect(result.error.message).toBe("Account not found"); - }); -}); diff --git a/apps/server/archive/contexts/accounts/application/update-account.use-case.ts b/apps/server/archive/contexts/accounts/application/update-account.use-case.ts deleted file mode 100644 index 753adf83..00000000 --- a/apps/server/archive/contexts/accounts/application/update-account.use-case.ts +++ /dev/null @@ -1,127 +0,0 @@ -import { - EmailAddress, - PhoneNumber, - PostalAddress, - TINNumber, - UniqueID, -} from "@/core/common/domain"; - -import { Account, IAccountProps, IAccountService } from "@/contexts/accounts/domain"; -import { ITransactionManager } from "@/core/common/infrastructure/database"; -import { logger } from "@/core/logger"; -import { Maybe, Result } from "@repo/rdx-utils"; -import { IUpdateAccountRequestDTO } from "../presentation"; - -export class UpdateAccountUseCase { - constructor( - private readonly accountService: IAccountService, - private readonly transactionManager: ITransactionManager - ) {} - - public execute( - accountID: UniqueID, - dto: Partial - ): Promise> { - return this.transactionManager.complete(async (transaction) => { - try { - const validOrErrors = this.validateAccountData(dto); - if (validOrErrors.isFailure) { - return Result.fail(validOrErrors.error); - } - - const data = validOrErrors.data; - - // Update account with dto - return await this.accountService.updateAccountById(accountID, data, transaction); - } catch (error: unknown) { - logger.error(error as Error); - return Result.fail(error as Error); - } - }); - } - - private validateAccountData( - dto: Partial - ): Result, Error> { - const errors: Error[] = []; - const validatedData: Partial = {}; - - if (dto.is_companyr) { - validatedData.isFreelancer = dto.is_companyr; - } - - if (dto.name) { - validatedData.name = dto.name; - } - - if (dto.trade_name) { - validatedData.tradeName = Maybe.some(dto.trade_name); - } - - if (dto.tin) { - const tinOrError = TINNumber.create(dto.tin); - if (tinOrError.isFailure) errors.push(tinOrError.error); - else validatedData.tin = tinOrError.data; - } - - if (dto.email) { - const emailOrError = EmailAddress.create(dto.email); - if (emailOrError.isFailure) errors.push(emailOrError.error); - else validatedData.email = emailOrError.data; - } - - if (dto.phone) { - const phoneOrError = PhoneNumber.create(dto.phone); - if (phoneOrError.isFailure) errors.push(phoneOrError.error); - else validatedData.phone = phoneOrError.data; - } - - if (dto.fax) { - const faxOrError = PhoneNumber.create(dto.fax); - if (faxOrError.isFailure) errors.push(faxOrError.error); - else validatedData.fax = Maybe.some(faxOrError.data); - } - - if (dto.street || dto.city || dto.state || dto.postal_code || dto.country) { - const postalAddressOrError = PostalAddress.create({ - street: dto.street ?? "", - city: dto.city ?? "", - state: dto.state ?? "", - postalCode: dto.postal_code ?? "", - country: dto.country ?? "", - }); - if (postalAddressOrError.isFailure) errors.push(postalAddressOrError.error); - else validatedData.address = postalAddressOrError.data; - } - - if (dto.website) { - validatedData.website = Maybe.some(dto.website); - } - - if (dto.legal_record) { - validatedData.legalRecord = dto.legal_record; - } - - if (dto.default_tax) { - validatedData.defaultTax = dto.default_tax; - } - - if (dto.language_code) { - validatedData.langCode = dto.language_code; - } - - if (dto.currency_code) { - validatedData.currencyCode = dto.currency_code; - } - - if (dto.logo) { - validatedData.logo = Maybe.some(dto.logo); - } - - if (errors.length > 0) { - const message = errors.map((err) => err.message).toString(); - return Result.fail(new Error(message)); - } - return Result.ok(validatedData); - } -} diff --git a/apps/server/archive/contexts/accounts/domain/aggregates/account.ts b/apps/server/archive/contexts/accounts/domain/aggregates/account.ts deleted file mode 100644 index 679e88c7..00000000 --- a/apps/server/archive/contexts/accounts/domain/aggregates/account.ts +++ /dev/null @@ -1,188 +0,0 @@ -import { - AggregateRoot, - type EmailAddress, - type PhoneNumber, - PostalAddress, - type TINNumber, - UniqueID, -} from "@/core"; -import { Maybe, Result } from "@repo/rdx-utils"; -import { AccountStatus } from "../value-objects"; - -export interface IAccountProps { - status: AccountStatus; - - isFreelancer: boolean; - name: string; - tin: TINNumber; - address: PostalAddress; - email: EmailAddress; - phone: PhoneNumber; - legalRecord: string; - defaultTax: number; - - langCode: string; - currencyCode: string; - - tradeName: Maybe; - website: Maybe; - fax: Maybe; - logo: Maybe; -} - -export interface IAccount { - id: UniqueID; - status: AccountStatus; - name: string; - tin: TINNumber; - address: PostalAddress; - email: EmailAddress; - phone: PhoneNumber; - legalRecord: string; - defaultTax: number; - - langCode: string; - currencyCode: string; - - tradeName: Maybe; - fax: Maybe; - website: Maybe; - logo: Maybe; - - isAccount: boolean; - isFreelancer: boolean; - isActive: boolean; - - activate(): boolean; - deactivate(): boolean; -} - -export class Account extends AggregateRoot implements IAccount { - id: UniqueID; - static create(props: IAccountProps, id?: UniqueID): Result { - const account = new Account(props, id); - - // Reglas de negocio / validaciones - // ... - // ... - - // 馃敼 Disparar evento de dominio "AccountAuthenticatedEvent" - //const { account } = props; - //user.addDomainEvent(new AccountAuthenticatedEvent(id, account.toString())); - - return Result.ok(account); - } - - static update(oldAccount: Account, data: Partial): Result { - const updatedPostalAddress = PostalAddress.update(oldAccount.address, data.address ?? {}).data; - - return Account.create( - { - isFreelancer: data.isFreelancer ?? oldAccount.isFreelancer, - - name: data.name ?? oldAccount.name, - tin: data.tin ?? oldAccount.tin, - - address: updatedPostalAddress, - email: data.email ?? oldAccount.email, - phone: data.phone ?? oldAccount.phone, - - legalRecord: data.legalRecord ?? oldAccount.legalRecord, - defaultTax: data.defaultTax ?? oldAccount.defaultTax, - status: oldAccount.props.status, - langCode: data.langCode ?? oldAccount.langCode, - currencyCode: data.currencyCode ?? oldAccount.currencyCode, - - tradeName: data.tradeName ?? oldAccount.tradeName, - website: data.website ?? oldAccount.website, - fax: data.fax ?? oldAccount.fax, - logo: data.logo ?? oldAccount.logo, - }, - oldAccount.id - ).getOrElse(this); - } - - activate() { - if (!this.props.status.canTransitionTo("active")) { - return false; - } - this.props.status = AccountStatus.createActive(); - return true; - } - - deactivate() { - if (!this.props.status.canTransitionTo("inactive")) { - return false; - } - this.props.status = AccountStatus.createInactive(); - return true; - } - - get status() { - return this.props.status; - } - - get name() { - return this.props.name; - } - - get tradeName() { - return this.props.tradeName; - } - - get tin(): TINNumber { - return this.props.tin; - } - - get address(): PostalAddress { - return this.props.address; - } - - get email(): EmailAddress { - return this.props.email; - } - - get phone(): PhoneNumber { - return this.props.phone; - } - - get fax(): Maybe { - return this.props.fax; - } - - get website() { - return this.props.website; - } - - get legalRecord() { - return this.props.legalRecord; - } - - get defaultTax() { - return this.props.defaultTax; - } - - get langCode() { - return this.props.langCode; - } - - get currencyCode() { - return this.props.currencyCode; - } - - get logo() { - return this.props.logo; - } - - get isAccount(): boolean { - return !this.props.isFreelancer; - } - - get isFreelancer(): boolean { - return this.props.isFreelancer; - } - - get isActive(): boolean { - return this.props.status.equals(AccountStatus.createActive()); - } -} diff --git a/apps/server/archive/contexts/accounts/domain/aggregates/index.ts b/apps/server/archive/contexts/accounts/domain/aggregates/index.ts deleted file mode 100644 index ed4079f3..00000000 --- a/apps/server/archive/contexts/accounts/domain/aggregates/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from "./account"; diff --git a/apps/server/archive/contexts/accounts/domain/index.ts b/apps/server/archive/contexts/accounts/domain/index.ts deleted file mode 100644 index 5dcd597d..00000000 --- a/apps/server/archive/contexts/accounts/domain/index.ts +++ /dev/null @@ -1,4 +0,0 @@ -export * from "./aggregates"; -export * from "./repositories"; -export * from "./services"; -export * from "./value-objects"; diff --git a/apps/server/archive/contexts/accounts/domain/repositories/account-repository.interface.ts b/apps/server/archive/contexts/accounts/domain/repositories/account-repository.interface.ts deleted file mode 100644 index 9acd9f86..00000000 --- a/apps/server/archive/contexts/accounts/domain/repositories/account-repository.interface.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { EmailAddress, UniqueID } from "@/core/common/domain"; -import { Collection, Result } from "@repo/rdx-utils"; -import { Account } from "../aggregates"; - -export interface IAccountRepository { - accountExists(id: UniqueID, transaction?: any): Promise>; - findAll(transaction?: any): Promise, Error>>; - findById(id: UniqueID, transaction?: any): Promise>; - findByEmail(email: EmailAddress, transaction?: any): Promise>; - - create(account: Account, transaction?: any): Promise; - update(account: Account, transaction?: any): Promise; -} diff --git a/apps/server/archive/contexts/accounts/domain/repositories/index.ts b/apps/server/archive/contexts/accounts/domain/repositories/index.ts deleted file mode 100644 index f0804e69..00000000 --- a/apps/server/archive/contexts/accounts/domain/repositories/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from "./account-repository.interface"; diff --git a/apps/server/archive/contexts/accounts/domain/services/account-service.integration.test.ts b/apps/server/archive/contexts/accounts/domain/services/account-service.integration.test.ts deleted file mode 100644 index a937a832..00000000 --- a/apps/server/archive/contexts/accounts/domain/services/account-service.integration.test.ts +++ /dev/null @@ -1,153 +0,0 @@ -import { Maybe, Result } from "@repo/rdx-utils"; - -import { - EmailAddress, - PhoneNumber, - PostalAddress, - TINNumber, - UniqueID, -} from "@/core/common/domain"; - -import { Account, type IAccountProps } from "../aggregates"; -import type { IAccountRepository } from "../repositories"; -import { AccountStatus } from "../value-objects"; - -import { AccountService } from "./account.service"; - -const mockAccountRepository: IAccountRepository = { - accountExists: jest.fn(), - findAll: jest.fn(), - findByEmail: jest.fn(), - findById: jest.fn(), - create: jest.fn(), - update: jest.fn(), -}; - -const sampleAccountPrimitives = { - id: "c5743279-e1cf-4dd5-baae-6698c8c6183c", - is_companyr: false, - name: "Empresa XYZ", - trade_name: "XYZ Trading", - tin: "123456789", - street: "Calle Principal 123", - city: "Madrid", - state: "Madrid", - postal_code: "28001", - country: "Espa帽a", - email: "contacto@xyz.com", - phone: "+34 600 123 456", - fax: "+34 600 654 321", - website: "https://xyz.com", - legal_record: "Registro Mercantil XYZ", - default_tax: 21, - status: "active", - language_code: "es", - currency_code: "EUR", - logo: "https://xyz.com/logo.png", -}; - -const accountBuilder = (accountData: any) => { - const idOrError = UniqueID.create(sampleAccountPrimitives.id); - const tinOrError = TINNumber.create(sampleAccountPrimitives.tin); - const emailOrError = EmailAddress.create(sampleAccountPrimitives.email); - const phoneOrError = PhoneNumber.create(sampleAccountPrimitives.phone); - const faxOrError = PhoneNumber.createNullable(sampleAccountPrimitives.fax); - const postalAddressOrError = PostalAddress.create({ - street: sampleAccountPrimitives.street, - city: sampleAccountPrimitives.city, - state: sampleAccountPrimitives.state, - postalCode: sampleAccountPrimitives.postal_code, - country: sampleAccountPrimitives.country, - }); - - const result = Result.combine([ - idOrError, - tinOrError, - emailOrError, - phoneOrError, - faxOrError, - postalAddressOrError, - ]); - - if (result.isFailure) { - return Result.fail(result.error); - } - - const validatedData: IAccountProps = { - status: AccountStatus.createInactive(), - isFreelancer: sampleAccountPrimitives.is_companyr, - name: sampleAccountPrimitives.name, - tradeName: sampleAccountPrimitives.trade_name - ? Maybe.some(sampleAccountPrimitives.trade_name) - : Maybe.none(), - tin: tinOrError.data, - address: postalAddressOrError.data, - email: emailOrError.data, - phone: phoneOrError.data, - fax: faxOrError.data, - website: sampleAccountPrimitives.website - ? Maybe.some(sampleAccountPrimitives.website) - : Maybe.none(), - legalRecord: sampleAccountPrimitives.legal_record, - defaultTax: sampleAccountPrimitives.default_tax, - langCode: sampleAccountPrimitives.language_code, - currencyCode: sampleAccountPrimitives.currency_code, - logo: sampleAccountPrimitives.logo ? Maybe.some(sampleAccountPrimitives.logo) : Maybe.none(), - }; - - return Account.create(validatedData, idOrError.data); -}; - -describe("AccountService - Integraci贸n", () => { - let accountService: AccountService; - let activeSampleAccount: Account; - let inactiveSampleAccount: Account; - let accountId: UniqueID; - - beforeEach(() => { - accountService = new AccountService(mockAccountRepository); - inactiveSampleAccount = accountBuilder(sampleAccountPrimitives).data; - }); - - it("deber铆a activar una cuenta existente", async () => { - const existingAccount = inactiveSampleAccount; - (mockAccountRepository.findById as jest.Mock).mockResolvedValue(Result.ok(existingAccount)); - (mockAccountRepository.update as jest.Mock).mockResolvedValue(undefined); - - const result = await accountService.activateAccount(existingAccount.id); - - expect(result.isSuccess).toBe(true); - expect(result.data.isActive).toBeTruthy(); - expect(mockAccountRepository.update).toHaveBeenCalledWith(result.data); - }); - - it("deber铆a desactivar una cuenta existente", async () => { - const existingAccount = Account.update(inactiveSampleAccount, { - status: AccountStatus.createActive(), - }).data; - - (mockAccountRepository.findById as jest.Mock).mockResolvedValue(Result.ok(existingAccount)); - (mockAccountRepository.update as jest.Mock).mockResolvedValue(undefined); - - const result = await accountService.deactivateAccount(existingAccount.id); - expect(result.isSuccess).toBe(true); - expect(result.data.isActive).toBeFalsy(); - expect(mockAccountRepository.update).toHaveBeenCalledWith(result.data); - }); - - it("deber铆a retornar error si la cuenta no existe al activar", async () => { - (mockAccountRepository.findById as jest.Mock).mockResolvedValue(null); - - const result = await accountService.activateAccount(UniqueID.create("", true).data); - expect(result.isFailure).toBe(true); - expect(result.error.message).toBe("Account not found"); - }); - - it("deber铆a retornar error si la cuenta no existe al desactivar", async () => { - (mockAccountRepository.findById as jest.Mock).mockResolvedValue(null); - - const result = await accountService.deactivateAccount(UniqueID.create("", true).data); - expect(result.isFailure).toBe(true); - expect(result.error.message).toBe("Account not found"); - }); -}); diff --git a/apps/server/archive/contexts/accounts/domain/services/account-service.interface.ts b/apps/server/archive/contexts/accounts/domain/services/account-service.interface.ts deleted file mode 100644 index 53effcbb..00000000 --- a/apps/server/archive/contexts/accounts/domain/services/account-service.interface.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { UniqueID } from "@/core/common/domain"; -import { Collection, Result } from "@repo/rdx-utils"; -import { Account, IAccountProps } from "../aggregates"; - -export interface IAccountService { - findAccounts(transaction?: any): Promise, Error>>; - findAccountById(accountId: UniqueID, transaction?: any): Promise>; - - updateAccountById( - accountId: UniqueID, - data: Partial, - transaction?: any - ): Promise>; - - createAccount( - accountId: UniqueID, - data: IAccountProps, - transaction?: any - ): Promise>; -} diff --git a/apps/server/archive/contexts/accounts/domain/services/account-service.test.ts b/apps/server/archive/contexts/accounts/domain/services/account-service.test.ts deleted file mode 100644 index 26cf6f14..00000000 --- a/apps/server/archive/contexts/accounts/domain/services/account-service.test.ts +++ /dev/null @@ -1,70 +0,0 @@ -import { UniqueID } from "@/core/common/domain"; -import { Account } from "../aggregates"; -import { IAccountRepository } from "../repositories"; -import { AccountService } from "./account.service"; - -const mockAccountRepository: IAccountRepository = { - accountExists: jest.fn(), - findAll: jest.fn(), - findByEmail: jest.fn(), - findById: jest.fn(), - create: jest.fn(), - update: jest.fn(), -}; - -const sampleAccount = { - id: "c5743279-e1cf-4dd5-baae-6698c8c6183c", - is_companyr: false, - name: "Empresa XYZ", - trade_name: "XYZ Trading", - tin: "123456789", - street: "Calle Principal 123", - city: "Madrid", - state: "Madrid", - postal_code: "28001", - country: "Espa帽a", - email: "contacto@xyz.com", - phone: "+34 600 123 456", - fax: "+34 600 654 321", - website: "https://xyz.com", - legal_record: "Registro Mercantil XYZ", - default_tax: 21, - status: "active", - language_code: "es", - currency_code: "EUR", - logo: "https://xyz.com/logo.png", -}; - -const accountId = UniqueID.create(sampleAccount.id).data; - -describe("AccountService", () => { - let accountService: AccountService; - - beforeEach(() => { - accountService = new AccountService(mockAccountRepository); - }); - - it("deber铆a actualizar una cuenta existente", async () => { - const existingAccount = new Account( - { - /* datos simulados */ - }, - "123" - ); - (mockAccountRepository.findById as jest.Mock).mockResolvedValue(existingAccount); - (mockAccountRepository.create as jest.Mock).mockResolvedValue(undefined); - - const result = await accountService.updateAccountById(accountId, { name: "Nuevo Nombre" }); - expect(result.isSuccess).toBe(true); - expect(result.data.name).toBe("Nuevo Nombre"); - expect(mockAccountRepository.save).toHaveBeenCalled(); - }); - - it("deber铆a retornar error si la cuenta no existe", async () => { - (mockAccountRepository.findById as jest.Mock).mockResolvedValue(null); - - const result = await accountService.updateAccountById(accountId, { name: "Nuevo Nombre" }); - expect(result.isFailure).toBe(true); - expect(result.error.message).toBe("Account not found"); - }); -}); diff --git a/apps/server/archive/contexts/accounts/domain/services/account.service.ts b/apps/server/archive/contexts/accounts/domain/services/account.service.ts deleted file mode 100644 index d243d55c..00000000 --- a/apps/server/archive/contexts/accounts/domain/services/account.service.ts +++ /dev/null @@ -1,105 +0,0 @@ -import { UniqueID } from "@/core/common/domain"; -import { Collection, Result } from "@repo/rdx-utils"; -import { Transaction } from "sequelize"; -import { Account, IAccountProps } from "../aggregates"; -import { IAccountRepository } from "../repositories"; -import { IAccountService } from "./account-service.interface"; - -export class AccountService implements IAccountService { - constructor(private readonly repo: IAccountRepository) {} - - async findAccounts(transaction?: Transaction): Promise, Error>> { - const accountsOrError = await this.repo.findAll(transaction); - if (accountsOrError.isFailure) { - return Result.fail(accountsOrError.error); - } - - // Solo devolver usuarios activos - //const allAccounts = accountsOrError.data.filter((account) => account.isActive); - //return Result.ok(new Collection(allAccounts)); - - return accountsOrError; - } - - async findAccountById(accountId: UniqueID, transaction?: Transaction): Promise> { - return await this.repo.findById(accountId, transaction); - } - - async updateAccountById( - accountId: UniqueID, - data: Partial, - transaction?: Transaction - ): Promise> { - // Verificar si la cuenta existe - const accountOrError = await this.repo.findById(accountId, transaction); - if (accountOrError.isFailure) { - return Result.fail(new Error("Account not found")); - } - - const updatedAccountOrError = Account.update(accountOrError.data, data); - if (updatedAccountOrError.isFailure) { - return Result.fail( - new Error(`Error updating account: ${updatedAccountOrError.error.message}`) - ); - } - - const updateAccount = updatedAccountOrError.data; - - await this.repo.update(updateAccount, transaction); - return Result.ok(updateAccount); - } - - async createAccount( - accountId: UniqueID, - data: IAccountProps, - transaction?: Transaction - ): Promise> { - // Verificar si la cuenta existe - const accountOrError = await this.repo.findById(accountId, transaction); - if (accountOrError.isSuccess) { - return Result.fail(new Error("Account exists")); - } - - const newAccountOrError = Account.create(data, accountId); - if (newAccountOrError.isFailure) { - return Result.fail(new Error(`Error creating account: ${newAccountOrError.error.message}`)); - } - - const newAccount = newAccountOrError.data; - - await this.repo.create(newAccount, transaction); - return Result.ok(newAccount); - } - - async activateAccount(id: UniqueID, transaction?: Transaction): Promise> { - const accountOrError = await this.repo.findById(id, transaction); - - if (accountOrError.isFailure) { - return Result.fail(new Error("Account not found")); - } - - const account = accountOrError.data; - if (account.activate()) { - await this.repo.update(account, transaction); - return Result.ok(); - } - return Result.fail(new Error("Error activating account")); - } - - async deactivateAccount( - id: UniqueID, - transaction?: Transaction - ): Promise> { - const accountOrError = await this.repo.findById(id, transaction); - if (accountOrError.isFailure) { - return Result.fail(new Error("Account not found")); - } - - const account = accountOrError.data; - if (account.deactivate()) { - await this.repo.update(account, transaction); - return Result.ok(); - } - return Result.fail(new Error("Error deactivating account")); - } -} diff --git a/apps/server/archive/contexts/accounts/domain/services/index.ts b/apps/server/archive/contexts/accounts/domain/services/index.ts deleted file mode 100644 index 207020c4..00000000 --- a/apps/server/archive/contexts/accounts/domain/services/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from "./account-service.interface"; -export * from "./account.service"; diff --git a/apps/server/archive/contexts/accounts/domain/value-objects/account-status.test.ts b/apps/server/archive/contexts/accounts/domain/value-objects/account-status.test.ts deleted file mode 100644 index acec6376..00000000 --- a/apps/server/archive/contexts/accounts/domain/value-objects/account-status.test.ts +++ /dev/null @@ -1,72 +0,0 @@ -import { ACCOUNT_STATUS, AccountStatus } from "./account-status"; - -describe("AccountStatus Value Object", () => { - describe("Creaci贸n de estados v谩lidos", () => { - it("deber铆a crear un estado inactivo correctamente", () => { - const status = AccountStatus.createInactive(); - expect(status.getValue()).toBe(ACCOUNT_STATUS.INACTIVE); - }); - - it("deber铆a crear un estado activo correctamente", () => { - const status = AccountStatus.createActive(); - expect(status.getValue()).toBe(ACCOUNT_STATUS.ACTIVE); - }); - - it("deber铆a crear un estado v谩lido usando el m茅todo create", () => { - const result = AccountStatus.create(ACCOUNT_STATUS.ACTIVE); - expect(result.isSuccess).toBe(true); - expect(result.data.getValue()).toBe(ACCOUNT_STATUS.ACTIVE); - }); - - it("deber铆a fallar al crear un estado inv谩lido", () => { - const result = AccountStatus.create("invalid-status"); - expect(result.isFailure).toBe(true); - expect(result.error.message).toBe("Estado de la cuenta no v谩lido: invalid-status"); - }); - }); - - describe("Verificaci贸n de transiciones", () => { - it("deber铆a permitir la transici贸n de 'inactive' a 'active'", () => { - const status = AccountStatus.createInactive(); - expect(status.canTransitionTo(ACCOUNT_STATUS.ACTIVE)).toBe(true); - }); - - it("deber铆a permitir la transici贸n de 'active' a 'inactive'", () => { - const status = AccountStatus.createActive(); - expect(status.canTransitionTo(ACCOUNT_STATUS.INACTIVE)).toBe(true); - }); - - it("deber铆a impedir transiciones no permitidas", () => { - const status = AccountStatus.createInactive(); - expect(status.canTransitionTo("invalid")).toBe(false); - }); - - it("deber铆a realizar una transici贸n v谩lida correctamente", () => { - const inactiveStatus = AccountStatus.createInactive(); - const transitionResult = inactiveStatus.transitionTo(ACCOUNT_STATUS.ACTIVE); - - expect(transitionResult.isSuccess).toBe(true); - expect(transitionResult.data.getValue()).toBe(ACCOUNT_STATUS.ACTIVE); - }); - - it("deber铆a fallar en una transici贸n inv谩lida", () => { - const status = AccountStatus.createInactive(); - const transitionResult = status.transitionTo("invalid"); - - expect(transitionResult.isFailure).toBe(true); - expect(transitionResult.error.message).toBe("Transici贸n no permitida de inactive a invalid"); - }); - }); - - describe("M茅todos auxiliares", () => { - it("deber铆a devolver correctamente el valor con getValue()", () => { - const status = AccountStatus.createInactive(); - expect(status.getValue()).toBe(ACCOUNT_STATUS.INACTIVE); - }); - - it("deber铆a devolver correctamente el valor con toString()", () => { - const status = AccountStatus.createActive(); - expect(status.toString()).toBe(ACCOUNT_STATUS.ACTIVE); - }); - }); -}); diff --git a/apps/server/archive/contexts/accounts/domain/value-objects/account-status.ts b/apps/server/archive/contexts/accounts/domain/value-objects/account-status.ts deleted file mode 100644 index 2d2fa94e..00000000 --- a/apps/server/archive/contexts/accounts/domain/value-objects/account-status.ts +++ /dev/null @@ -1,59 +0,0 @@ -import { ValueObject } from "@repo/rdx-ddd"; -import { Result } from "@repo/rdx-utils"; - -interface IAccountStatusProps { - value: string; -} - -export enum ACCOUNT_STATUS { - INACTIVE = "inactive", - ACTIVE = "active", -} - -export class AccountStatus extends ValueObject { - private static readonly ALLOWED_STATUSES = ["inactive", "active"]; - - private static readonly TRANSITIONS: Record = { - inactive: [ACCOUNT_STATUS.ACTIVE], - active: [ACCOUNT_STATUS.INACTIVE], - }; - - static create(value: string): Result { - if (!this.ALLOWED_STATUSES.includes(value)) { - return Result.fail(new Error(`Estado de la cuenta no v谩lido: ${value}`)); - } - - return Result.ok( - value === "active" ? AccountStatus.createActive() : AccountStatus.createInactive() - ); - } - - public static createInactive(): AccountStatus { - return new AccountStatus({ value: ACCOUNT_STATUS.INACTIVE }); - } - - public static createActive(): AccountStatus { - return new AccountStatus({ value: ACCOUNT_STATUS.ACTIVE }); - } - - getValue(): string { - return this.props.value; - } - - canTransitionTo(nextStatus: string): boolean { - return AccountStatus.TRANSITIONS[this.props.value].includes(nextStatus); - } - - transitionTo(nextStatus: string): Result { - if (!this.canTransitionTo(nextStatus)) { - return Result.fail( - new Error(`Transici贸n no permitida de ${this.props.value} a ${nextStatus}`) - ); - } - return AccountStatus.create(nextStatus); - } - - toPrimitive(): string { - return this.getValue(); - } -} diff --git a/apps/server/archive/contexts/accounts/domain/value-objects/index.ts b/apps/server/archive/contexts/accounts/domain/value-objects/index.ts deleted file mode 100644 index 88c6ddf6..00000000 --- a/apps/server/archive/contexts/accounts/domain/value-objects/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from "./account-status"; diff --git a/apps/server/archive/contexts/accounts/infraestructure/index.ts b/apps/server/archive/contexts/accounts/infraestructure/index.ts deleted file mode 100644 index 7ccefa3a..00000000 --- a/apps/server/archive/contexts/accounts/infraestructure/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from "./mappers"; -export * from "./sequelize"; diff --git a/apps/server/archive/contexts/accounts/infraestructure/mappers/account.mapper.ts b/apps/server/archive/contexts/accounts/infraestructure/mappers/account.mapper.ts deleted file mode 100644 index cacda792..00000000 --- a/apps/server/archive/contexts/accounts/infraestructure/mappers/account.mapper.ts +++ /dev/null @@ -1,107 +0,0 @@ -import { Maybe, Result } from "@repo/rdx-utils"; - -import { Account, AccountStatus } from "@/contexts/accounts/domain/"; -import { - EmailAddress, - PhoneNumber, - PostalAddress, - TINNumber, - UniqueID, -} from "@/core/common/domain"; -import { - type ISequelizeMapper, - type MapperParamsType, - SequelizeMapper, -} from "@/core/common/infrastructure/sequelize/sequelize-mapper"; - -import type { AccountCreationAttributes, AccountModel } from "../sequelize/account.model"; - -export interface IAccountMapper - extends ISequelizeMapper {} - -export class AccountMapper - extends SequelizeMapper - implements IAccountMapper -{ - public mapToDomain(source: AccountModel, params?: MapperParamsType): Result { - const idOrError = UniqueID.create(source.id); - const statusOrError = AccountStatus.create(source.status); - const tinOrError = TINNumber.create(source.tin); - const emailOrError = EmailAddress.create(source.email); - const phoneOrError = PhoneNumber.create(source.phone); - const faxOrError = PhoneNumber.createNullable(source.fax); - const postalAddressOrError = PostalAddress.create({ - street: source.street, - city: source.city, - state: source.state, - postalCode: source.postal_code, - country: source.country, - }); - - const result = Result.combine([ - idOrError, - statusOrError, - tinOrError, - emailOrError, - phoneOrError, - faxOrError, - postalAddressOrError, - ]); - - if (result.isFailure) { - return Result.fail(result.error); - } - - return Account.create( - { - status: statusOrError.data, - isFreelancer: source.is_companyr, - name: source.name, - tradeName: source.trade_name ? Maybe.some(source.trade_name) : Maybe.none(), - tin: tinOrError.data, - address: postalAddressOrError.data, - email: emailOrError.data, - phone: phoneOrError.data, - fax: faxOrError.data, - website: source.website ? Maybe.some(source.website) : Maybe.none(), - legalRecord: source.legal_record, - defaultTax: source.default_tax, - langCode: source.language_code, - currencyCode: source.currency_code, - logo: source.logo ? Maybe.some(source.logo) : Maybe.none(), - }, - idOrError.data - ); - } - - public mapToPersistence(source: Account, params?: MapperParamsType): AccountCreationAttributes { - return { - id: source.id.toPrimitive(), - is_companyr: source.isFreelancer, - name: source.name, - trade_name: source.tradeName.getOrUndefined(), - tin: source.tin.toPrimitive(), - - street: source.address.street, - city: source.address.city, - state: source.address.state, - postal_code: source.address.postalCode, - country: source.address.country, - - email: source.email.toPrimitive(), - phone: source.phone.toPrimitive(), - fax: source.fax.isSome() ? source.fax.getOrUndefined()?.toPrimitive() : undefined, - website: source.website.getOrUndefined(), - - legal_record: source.legalRecord, - default_tax: source.defaultTax, - status: source.isActive ? "active" : "inactive", - language_code: source.langCode, - currency_code: source.currencyCode, - logo: source.logo.getOrUndefined(), - }; - } -} - -const accountMapper: AccountMapper = new AccountMapper(); -export { accountMapper }; diff --git a/apps/server/archive/contexts/accounts/infraestructure/mappers/index.ts b/apps/server/archive/contexts/accounts/infraestructure/mappers/index.ts deleted file mode 100644 index b32ce87d..00000000 --- a/apps/server/archive/contexts/accounts/infraestructure/mappers/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from "./account.mapper"; diff --git a/apps/server/archive/contexts/accounts/infraestructure/sequelize/account.model.ts b/apps/server/archive/contexts/accounts/infraestructure/sequelize/account.model.ts deleted file mode 100644 index 9b4e8099..00000000 --- a/apps/server/archive/contexts/accounts/infraestructure/sequelize/account.model.ts +++ /dev/null @@ -1,171 +0,0 @@ -import { - CreationOptional, - DataTypes, - InferAttributes, - InferCreationAttributes, - Model, - Sequelize, -} from "sequelize"; - -export type AccountCreationAttributes = InferCreationAttributes & {}; - -export class AccountModel extends Model, AccountCreationAttributes> { - // To avoid table creation - /*static async sync(): Promise { - return Promise.resolve(); - }*/ - - declare id: string; - - declare is_companyr: boolean; - declare name: string; - declare trade_name: CreationOptional; - declare tin: string; - - declare street: string; - declare city: string; - declare state: string; - declare postal_code: string; - declare country: string; - - declare email: string; - declare phone: string; - declare fax: CreationOptional; - declare website: CreationOptional; - - declare legal_record: string; - - declare default_tax: number; - declare status: string; - declare language_code: string; - declare currency_code: string; - declare logo: CreationOptional; -} - -export default (sequelize: Sequelize) => { - AccountModel.init( - { - id: { - type: DataTypes.UUID, - primaryKey: true, - }, - is_companyr: { - type: DataTypes.BOOLEAN, - allowNull: false, - }, - name: { - type: DataTypes.STRING, - allowNull: false, - }, - trade_name: { - type: DataTypes.STRING, - allowNull: true, - defaultValue: null, - }, - tin: { - type: DataTypes.STRING, - allowNull: false, - }, - - street: { - type: DataTypes.STRING, - allowNull: false, - }, - city: { - type: DataTypes.STRING, - allowNull: false, - }, - state: { - type: DataTypes.STRING, - allowNull: false, - }, - postal_code: { - type: DataTypes.STRING, - allowNull: false, - }, - country: { - type: DataTypes.STRING, - allowNull: false, - }, - - email: { - type: DataTypes.STRING, - allowNull: false, - validate: { - isEmail: true, - }, - }, - phone: { - type: DataTypes.STRING, - allowNull: false, - }, - fax: { - type: DataTypes.STRING, - allowNull: true, - defaultValue: null, - }, - website: { - type: DataTypes.STRING, - allowNull: true, - defaultValue: null, - validate: { - isUrl: true, - }, - }, - legal_record: { - type: DataTypes.TEXT, - allowNull: false, - }, - - default_tax: { - type: new DataTypes.SMALLINT(), - allowNull: false, - defaultValue: 2100, - }, - - logo: { - type: DataTypes.STRING, - allowNull: true, - defaultValue: null, - }, - - language_code: { - type: DataTypes.STRING(2), - allowNull: false, - defaultValue: "es", - }, - - currency_code: { - type: new DataTypes.STRING(3), - allowNull: false, - defaultValue: "EUR", - }, - - status: { - type: DataTypes.STRING, - allowNull: false, - defaultValue: "active", - }, - }, - { - sequelize, - tableName: "accounts", - - paranoid: true, // softs deletes - timestamps: true, - - createdAt: "created_at", - updatedAt: "updated_at", - deletedAt: "deleted_at", - - indexes: [{ name: "email_idx", fields: ["email"], unique: true }], - - whereMergeStrategy: "and", // <- c贸mo tratar el merge de un scope - - defaultScope: {}, - - scopes: {}, - } - ); - return AccountModel; -}; diff --git a/apps/server/archive/contexts/accounts/infraestructure/sequelize/account.repository.ts b/apps/server/archive/contexts/accounts/infraestructure/sequelize/account.repository.ts deleted file mode 100644 index 6270e763..00000000 --- a/apps/server/archive/contexts/accounts/infraestructure/sequelize/account.repository.ts +++ /dev/null @@ -1,102 +0,0 @@ -import { Account } from "@/contexts/accounts/domain"; -import { IAccountRepository } from "@/contexts/accounts/domain/repositories/account-repository.interface"; -import { EmailAddress, UniqueID } from "@/core/common/domain"; -import { SequelizeRepository } from "@/core/common/infrastructure"; -import { Collection, Result } from "@repo/rdx-utils"; -import { Transaction } from "sequelize"; -import { IAccountMapper, accountMapper } from "../mappers/account.mapper"; -import { AccountModel } from "./account.model"; - -class AccountRepository extends SequelizeRepository implements IAccountRepository { - private readonly _mapper!: IAccountMapper; - - /** - * 馃敼 Funci贸n personalizada para mapear errores de unicidad en autenticaci贸n - */ - private _customErrorMapper(error: Error): string | null { - if (error.name === "SequelizeUniqueConstraintError") { - return "Account with this email already exists"; - } - - return null; - } - - constructor(mapper: IAccountMapper) { - super(); - this._mapper = mapper; - } - - async accountExists(id: UniqueID, transaction?: Transaction): Promise> { - try { - const _account = await this._getById(AccountModel, id, {}, transaction); - - return Result.ok(Boolean(id.equals(_account.id))); - } catch (error: any) { - return this._handleDatabaseError(error, this._customErrorMapper); - } - } - - async findAll(transaction?: Transaction): Promise, Error>> { - try { - const rawAccounts: any = await this._findAll(AccountModel, {}, transaction); - - if (!rawAccounts === true) { - return Result.fail(new Error("Account with email not exists")); - } - - return this._mapper.mapArrayToDomain(rawAccounts); - } catch (error: any) { - return this._handleDatabaseError(error, this._customErrorMapper); - } - } - - async findById(id: UniqueID, transaction?: Transaction): Promise> { - try { - const rawAccount: any = await this._getById(AccountModel, id, {}, transaction); - - if (!rawAccount === true) { - return Result.fail(new Error(`Account with id ${id.toString()} not exists`)); - } - - return this._mapper.mapToDomain(rawAccount); - } catch (error: any) { - return this._handleDatabaseError(error, this._customErrorMapper); - } - } - - async findByEmail( - email: EmailAddress, - transaction?: Transaction - ): Promise> { - try { - const rawAccount: any = await this._getBy( - AccountModel, - "email", - email.toString(), - {}, - transaction - ); - - if (!rawAccount === true) { - return Result.fail(new Error(`Account with email ${email.toString()} not exists`)); - } - - return this._mapper.mapToDomain(rawAccount); - } catch (error: any) { - return this._handleDatabaseError(error, this._customErrorMapper); - } - } - - async create(account: Account, transaction?: Transaction): Promise { - const accountData = this._mapper.mapToPersistence(account); - await this._save(AccountModel, account.id, accountData, {}, transaction); - } - - async update(account: Account, transaction?: Transaction): Promise { - const accountData = this._mapper.mapToPersistence(account); - await this._save(AccountModel, account.id, accountData, {}, transaction); - } -} - -const accountRepository = new AccountRepository(accountMapper); -export { accountRepository }; diff --git a/apps/server/archive/contexts/accounts/infraestructure/sequelize/index.ts b/apps/server/archive/contexts/accounts/infraestructure/sequelize/index.ts deleted file mode 100644 index 402ae901..00000000 --- a/apps/server/archive/contexts/accounts/infraestructure/sequelize/index.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { IAccountRepository } from "@/contexts/accounts/domain/repositories/account-repository.interface"; -import { accountRepository } from "./account.repository"; - -export * from "./account.model"; - -export * from "./account.repository"; - -export const createAccountRepository = (): IAccountRepository => { - return accountRepository; -}; diff --git a/apps/server/archive/contexts/accounts/presentation/controllers/create-account/create-account.controller.ts b/apps/server/archive/contexts/accounts/presentation/controllers/create-account/create-account.controller.ts deleted file mode 100644 index 6946004e..00000000 --- a/apps/server/archive/contexts/accounts/presentation/controllers/create-account/create-account.controller.ts +++ /dev/null @@ -1,45 +0,0 @@ -import { UniqueID } from "@/core/common/domain"; -import { ExpressController } from "@/core/common/presentation"; -import { CreateAccountUseCase } from "../../../application"; -import { ICreateAccountRequestDTO } from "../../dto"; -import { ICreateAccountPresenter } from "./create-account.presenter"; - -export class CreateAccountController extends ExpressController { - public constructor( - private readonly createAccount: CreateAccountUseCase, - private readonly presenter: ICreateAccountPresenter - ) { - super(); - } - - protected async executeImpl() { - const createDTO: ICreateAccountRequestDTO = this.req.body; - - // Validar ID - const accountIdOrError = UniqueID.create(createDTO.id); - if (accountIdOrError.isFailure) return this.invalidInputError("Account ID not valid"); - - const accountOrError = await this.createAccount.execute(accountIdOrError.data, createDTO); - - if (accountOrError.isFailure) { - return this.handleError(accountOrError.error); - } - - return this.ok(this.presenter.toDTO(accountOrError.data)); - } - - private handleError(error: Error) { - const message = error.message; - - if ( - message.includes("Database connection lost") || - message.includes("Database request timed out") - ) { - return this.unavailableError( - "Database service is currently unavailable. Please try again later." - ); - } - - return this.conflictError(message); - } -} diff --git a/apps/server/archive/contexts/accounts/presentation/controllers/create-account/create-account.presenter.ts b/apps/server/archive/contexts/accounts/presentation/controllers/create-account/create-account.presenter.ts deleted file mode 100644 index ac82a1c0..00000000 --- a/apps/server/archive/contexts/accounts/presentation/controllers/create-account/create-account.presenter.ts +++ /dev/null @@ -1,37 +0,0 @@ -import { Account } from "@/contexts/accounts/domain"; -import { ensureBoolean, ensureNumber, ensureString } from "@repo/rdx-utils"; -import { ICreateAccountResponseDTO } from "../../dto"; - -export interface ICreateAccountPresenter { - toDTO: (account: Account) => ICreateAccountResponseDTO; -} - -export const createAccountPresenter: ICreateAccountPresenter = { - toDTO: (account: Account): ICreateAccountResponseDTO => ({ - id: ensureString(account.id.toString()), - - is_companyr: ensureBoolean(account.isFreelancer), - name: ensureString(account.name), - trade_name: ensureString(account.tradeName.getOrUndefined()), - tin: ensureString(account.tin.toString()), - - street: ensureString(account.address.street), - city: ensureString(account.address.city), - state: ensureString(account.address.state), - postal_code: ensureString(account.address.postalCode), - country: ensureString(account.address.country), - - email: ensureString(account.email.toString()), - phone: ensureString(account.phone.toString()), - fax: ensureString(account.fax.getOrUndefined()?.toString()), - website: ensureString(account.website.getOrUndefined()), - - legal_record: ensureString(account.legalRecord), - - default_tax: ensureNumber(account.defaultTax), - status: ensureString(account.isActive ? "active" : "inactive"), - language_code: ensureString(account.langCode), - currency_code: ensureString(account.currencyCode), - logo: ensureString(account.logo.getOrUndefined()), - }), -}; diff --git a/apps/server/archive/contexts/accounts/presentation/controllers/create-account/index.ts b/apps/server/archive/contexts/accounts/presentation/controllers/create-account/index.ts deleted file mode 100644 index 35bc7650..00000000 --- a/apps/server/archive/contexts/accounts/presentation/controllers/create-account/index.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { CreateAccountUseCase } from "@/contexts/accounts/application/create-account.use-case"; -import { AccountService } from "@/contexts/accounts/domain"; -import { accountRepository } from "@/contexts/accounts/infraestructure"; -import { SequelizeTransactionManager } from "@/core/common/infrastructure"; -import { CreateAccountController } from "./create-account.controller"; -import { createAccountPresenter } from "./create-account.presenter"; - -export const buildCreateAccountController = () => { - const transactionManager = new SequelizeTransactionManager(); - const accountService = new AccountService(accountRepository); - - const useCase = new CreateAccountUseCase(accountService, transactionManager); - const presenter = createAccountPresenter; - - return new CreateAccountController(useCase, presenter); -}; diff --git a/apps/server/archive/contexts/accounts/presentation/controllers/get-account/get-account.controller.ts b/apps/server/archive/contexts/accounts/presentation/controllers/get-account/get-account.controller.ts deleted file mode 100644 index 0c893a10..00000000 --- a/apps/server/archive/contexts/accounts/presentation/controllers/get-account/get-account.controller.ts +++ /dev/null @@ -1,44 +0,0 @@ -import { GetAccountUseCase } from "@/contexts/accounts/application"; -import { UniqueID } from "@/core/common/domain"; -import { ExpressController } from "@/core/common/presentation"; -import { IGetAccountPresenter } from "./get-account.presenter"; - -export class GetAccountController extends ExpressController { - public constructor( - private readonly getAccount: GetAccountUseCase, - private readonly presenter: IGetAccountPresenter - ) { - super(); - } - - protected async executeImpl() { - const { accountId } = this.req.params; - - // Validar ID - const accountIdOrError = UniqueID.create(accountId); - if (accountIdOrError.isFailure) return this.invalidInputError("Account ID not valid"); - - const accountOrError = await this.getAccount.execute(accountIdOrError.data); - - if (accountOrError.isFailure) { - return this.handleError(accountOrError.error); - } - - return this.ok(this.presenter.toDTO(accountOrError.data)); - } - - private handleError(error: Error) { - const message = error.message; - - if ( - message.includes("Database connection lost") || - message.includes("Database request timed out") - ) { - return this.unavailableError( - "Database service is currently unavailable. Please try again later." - ); - } - - return this.conflictError(message); - } -} diff --git a/apps/server/archive/contexts/accounts/presentation/controllers/get-account/get-account.presenter.ts b/apps/server/archive/contexts/accounts/presentation/controllers/get-account/get-account.presenter.ts deleted file mode 100644 index 7c3fef8f..00000000 --- a/apps/server/archive/contexts/accounts/presentation/controllers/get-account/get-account.presenter.ts +++ /dev/null @@ -1,37 +0,0 @@ -import { Account } from "@/contexts/accounts/domain"; -import { ensureBoolean, ensureNumber, ensureString } from "@repo/rdx-utils"; -import { IGetAccountResponseDTO } from "../../dto"; - -export interface IGetAccountPresenter { - toDTO: (account: Account) => IGetAccountResponseDTO; -} - -export const getAccountPresenter: IGetAccountPresenter = { - toDTO: (account: Account): IGetAccountResponseDTO => ({ - id: ensureString(account.id.toPrimitive()), - - is_companyr: ensureBoolean(account.isFreelancer), - name: ensureString(account.name), - trade_name: ensureString(account.tradeName.getOrUndefined()), - tin: ensureString(account.tin.toPrimitive()), - - street: ensureString(account.address.street), - city: ensureString(account.address.city), - state: ensureString(account.address.state), - postal_code: ensureString(account.address.postalCode), - country: ensureString(account.address.country), - - email: ensureString(account.email.toPrimitive()), - phone: ensureString(account.phone.toPrimitive()), - fax: ensureString(account.fax.getOrUndefined()?.toPrimitive()), - website: ensureString(account.website.getOrUndefined()), - - legal_record: ensureString(account.legalRecord), - - default_tax: ensureNumber(account.defaultTax), - status: ensureString(account.isActive ? "active" : "inactive"), - language_code: ensureString(account.langCode), - currency_code: ensureString(account.currencyCode), - logo: ensureString(account.logo.getOrUndefined()), - }), -}; diff --git a/apps/server/archive/contexts/accounts/presentation/controllers/get-account/index.ts b/apps/server/archive/contexts/accounts/presentation/controllers/get-account/index.ts deleted file mode 100644 index 0a0dee47..00000000 --- a/apps/server/archive/contexts/accounts/presentation/controllers/get-account/index.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { GetAccountUseCase } from "@/contexts/accounts/application"; -import { AccountService } from "@/contexts/accounts/domain"; -import { accountRepository } from "@/contexts/accounts/infraestructure"; -import { SequelizeTransactionManager } from "@/core/common/infrastructure"; -import { GetAccountController } from "./get-account.controller"; -import { getAccountPresenter } from "./get-account.presenter"; - -export const buildGetAccountController = () => { - const transactionManager = new SequelizeTransactionManager(); - const accountService = new AccountService(accountRepository); - - const useCase = new GetAccountUseCase(accountService, transactionManager); - const presenter = getAccountPresenter; - - return new GetAccountController(useCase, presenter); -}; diff --git a/apps/server/archive/contexts/accounts/presentation/controllers/index.ts b/apps/server/archive/contexts/accounts/presentation/controllers/index.ts deleted file mode 100644 index bf0d307c..00000000 --- a/apps/server/archive/contexts/accounts/presentation/controllers/index.ts +++ /dev/null @@ -1,4 +0,0 @@ -export * from "./create-account"; -export * from "./get-account"; -export * from "./list-accounts"; -export * from "./update-account"; diff --git a/apps/server/archive/contexts/accounts/presentation/controllers/list-accounts/index.ts b/apps/server/archive/contexts/accounts/presentation/controllers/list-accounts/index.ts deleted file mode 100644 index 3f520952..00000000 --- a/apps/server/archive/contexts/accounts/presentation/controllers/list-accounts/index.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { ListAccountsUseCase } from "@/contexts/accounts/application"; -import { AccountService } from "@/contexts/accounts/domain"; -import { accountRepository } from "@/contexts/accounts/infraestructure"; -import { SequelizeTransactionManager } from "@/core/common/infrastructure"; -import { ListAccountsController } from "./list-accounts.controller"; -import { listAccountsPresenter } from "./list-accounts.presenter"; - -export const buildListAccountsController = () => { - const transactionManager = new SequelizeTransactionManager(); - const accountService = new AccountService(accountRepository); - - const useCase = new ListAccountsUseCase(accountService, transactionManager); - const presenter = listAccountsPresenter; - - return new ListAccountsController(useCase, presenter); -}; diff --git a/apps/server/archive/contexts/accounts/presentation/controllers/list-accounts/list-accounts.controller.ts b/apps/server/archive/contexts/accounts/presentation/controllers/list-accounts/list-accounts.controller.ts deleted file mode 100644 index 0bf8bded..00000000 --- a/apps/server/archive/contexts/accounts/presentation/controllers/list-accounts/list-accounts.controller.ts +++ /dev/null @@ -1,37 +0,0 @@ -import { ListAccountsUseCase } from "@/contexts/accounts/application"; -import { ExpressController } from "@/core/common/presentation"; -import { IListAccountsPresenter } from "./list-accounts.presenter"; - -export class ListAccountsController extends ExpressController { - public constructor( - private readonly listAccounts: ListAccountsUseCase, - private readonly presenter: IListAccountsPresenter - ) { - super(); - } - - protected async executeImpl() { - const accountsOrError = await this.listAccounts.execute(); - - if (accountsOrError.isFailure) { - return this.handleError(accountsOrError.error); - } - - return this.ok(this.presenter.toDTO(accountsOrError.data)); - } - - private handleError(error: Error) { - const message = error.message; - - if ( - message.includes("Database connection lost") || - message.includes("Database request timed out") - ) { - return this.unavailableError( - "Database service is currently unavailable. Please try again later." - ); - } - - return this.conflictError(message); - } -} diff --git a/apps/server/archive/contexts/accounts/presentation/controllers/list-accounts/list-accounts.presenter.ts b/apps/server/archive/contexts/accounts/presentation/controllers/list-accounts/list-accounts.presenter.ts deleted file mode 100644 index 91afbf1f..00000000 --- a/apps/server/archive/contexts/accounts/presentation/controllers/list-accounts/list-accounts.presenter.ts +++ /dev/null @@ -1,38 +0,0 @@ -import { Account } from "@/contexts/accounts/domain"; -import { Collection, ensureBoolean, ensureNumber, ensureString } from "@repo/rdx-utils"; -import { IListAccountsResponseDTO } from "../../dto"; - -export interface IListAccountsPresenter { - toDTO: (accounts: Collection) => IListAccountsResponseDTO[]; -} - -export const listAccountsPresenter: IListAccountsPresenter = { - toDTO: (accounts: Collection): IListAccountsResponseDTO[] => - accounts.map((account) => ({ - id: ensureString(account.id.toString()), - - is_companyr: ensureBoolean(account.isFreelancer), - name: ensureString(account.name), - trade_name: ensureString(account.tradeName.getOrUndefined()), - tin: ensureString(account.tin.toString()), - - street: ensureString(account.address.street), - city: ensureString(account.address.city), - state: ensureString(account.address.state), - postal_code: ensureString(account.address.postalCode), - country: ensureString(account.address.country), - - email: ensureString(account.email.toString()), - phone: ensureString(account.phone.toString()), - fax: ensureString(account.fax.getOrUndefined()?.toString()), - website: ensureString(account.website.getOrUndefined()), - - legal_record: ensureString(account.legalRecord), - - default_tax: ensureNumber(account.defaultTax), - status: ensureString(account.isActive ? "active" : "inactive"), - language_code: ensureString(account.langCode), - currency_code: ensureString(account.currencyCode), - logo: ensureString(account.logo.getOrUndefined()), - })), -}; diff --git a/apps/server/archive/contexts/accounts/presentation/controllers/update-account/index.ts b/apps/server/archive/contexts/accounts/presentation/controllers/update-account/index.ts deleted file mode 100644 index df1c8e50..00000000 --- a/apps/server/archive/contexts/accounts/presentation/controllers/update-account/index.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { UpdateAccountUseCase } from "@/contexts/accounts/application"; -import { AccountService } from "@/contexts/accounts/domain"; -import { accountRepository } from "@/contexts/accounts/infraestructure"; -import { SequelizeTransactionManager } from "@/core/common/infrastructure"; -import { UpdateAccountController } from "./update-account.controller"; -import { updateAccountPresenter } from "./update-account.presenter"; - -export const buildUpdateAccountController = () => { - const transactionManager = new SequelizeTransactionManager(); - const accountService = new AccountService(accountRepository); - - const useCase = new UpdateAccountUseCase(accountService, transactionManager); - const presenter = updateAccountPresenter; - - return new UpdateAccountController(useCase, presenter); -}; diff --git a/apps/server/archive/contexts/accounts/presentation/controllers/update-account/update-account.controller.ts b/apps/server/archive/contexts/accounts/presentation/controllers/update-account/update-account.controller.ts deleted file mode 100644 index 2bc41ae6..00000000 --- a/apps/server/archive/contexts/accounts/presentation/controllers/update-account/update-account.controller.ts +++ /dev/null @@ -1,46 +0,0 @@ -import { UpdateAccountUseCase } from "@/contexts/accounts/application/update-account.use-case"; -import { UniqueID } from "@/core/common/domain"; -import { ExpressController } from "@/core/common/presentation"; -import { IUpdateAccountRequestDTO } from "../../dto"; -import { IUpdateAccountPresenter } from "./update-account.presenter"; - -export class UpdateAccountController extends ExpressController { - public constructor( - private readonly updateAccount: UpdateAccountUseCase, - private readonly presenter: IUpdateAccountPresenter - ) { - super(); - } - - protected async executeImpl() { - const { accountId } = this.req.params; - const updateDTO: IUpdateAccountRequestDTO = this.req.body; - - // Validar ID - const accountIdOrError = UniqueID.create(accountId); - if (accountIdOrError.isFailure) return this.invalidInputError("Account ID not valid"); - - const accountOrError = await this.updateAccount.execute(accountIdOrError.data, updateDTO); - - if (accountOrError.isFailure) { - return this.handleError(accountOrError.error); - } - - return this.ok(this.presenter.toDTO(accountOrError.data)); - } - - private handleError(error: Error) { - const message = error.message; - - if ( - message.includes("Database connection lost") || - message.includes("Database request timed out") - ) { - return this.unavailableError( - "Database service is currently unavailable. Please try again later." - ); - } - - return this.conflictError(message); - } -} diff --git a/apps/server/archive/contexts/accounts/presentation/controllers/update-account/update-account.presenter.ts b/apps/server/archive/contexts/accounts/presentation/controllers/update-account/update-account.presenter.ts deleted file mode 100644 index 293f8251..00000000 --- a/apps/server/archive/contexts/accounts/presentation/controllers/update-account/update-account.presenter.ts +++ /dev/null @@ -1,37 +0,0 @@ -import { Account } from "@/contexts/accounts/domain"; -import { ensureBoolean, ensureNumber, ensureString } from "@repo/rdx-utils"; -import { IUpdateAccountResponseDTO } from "../../dto"; - -export interface IUpdateAccountPresenter { - toDTO: (account: Account) => IUpdateAccountResponseDTO; -} - -export const updateAccountPresenter: IUpdateAccountPresenter = { - toDTO: (account: Account): IUpdateAccountResponseDTO => ({ - id: ensureString(account.id.toString()), - - is_companyr: ensureBoolean(account.isFreelancer), - name: ensureString(account.name), - trade_name: ensureString(account.tradeName.getOrUndefined()), - tin: ensureString(account.tin.toString()), - - street: ensureString(account.address.street), - city: ensureString(account.address.city), - state: ensureString(account.address.state), - postal_code: ensureString(account.address.postalCode), - country: ensureString(account.address.country), - - email: ensureString(account.email.toString()), - phone: ensureString(account.phone.toString()), - fax: ensureString(account.fax.getOrUndefined()?.toString()), - website: ensureString(account.website.getOrUndefined()), - - legal_record: ensureString(account.legalRecord), - - default_tax: ensureNumber(account.defaultTax), - status: ensureString(account.isActive ? "active" : "inactive"), - language_code: ensureString(account.langCode), - currency_code: ensureString(account.currencyCode), - logo: ensureString(account.logo.getOrUndefined()), - }), -}; diff --git a/apps/server/archive/contexts/accounts/presentation/dto/accounts.request.dto.ts b/apps/server/archive/contexts/accounts/presentation/dto/accounts.request.dto.ts deleted file mode 100644 index 73904fec..00000000 --- a/apps/server/archive/contexts/accounts/presentation/dto/accounts.request.dto.ts +++ /dev/null @@ -1,52 +0,0 @@ -export type IListAccountsRequestDTO = {}; - -export interface ICreateAccountRequestDTO { - id: string; - is_companyr: boolean; - name: string; - trade_name: string; - tin: string; - - street: string; - city: string; - state: string; - postal_code: string; - country: string; - - email: string; - phone: string; - fax: string; - website: string; - - legal_record: string; - - default_tax: number; - language_code: string; - currency_code: string; - logo: string; -} - -export interface IUpdateAccountRequestDTO { - is_companyr: boolean; - name: string; - trade_name: string; - tin: string; - - street: string; - city: string; - state: string; - postal_code: string; - country: string; - - email: string; - phone: string; - fax: string; - website: string; - - legal_record: string; - - default_tax: number; - language_code: string; - currency_code: string; - logo: string; -} diff --git a/apps/server/archive/contexts/accounts/presentation/dto/accounts.response.dto.ts b/apps/server/archive/contexts/accounts/presentation/dto/accounts.response.dto.ts deleted file mode 100644 index 684ba86d..00000000 --- a/apps/server/archive/contexts/accounts/presentation/dto/accounts.response.dto.ts +++ /dev/null @@ -1,114 +0,0 @@ -export interface IListAccountsResponseDTO { - id: string; - - is_companyr: boolean; - name: string; - trade_name: string; - tin: string; - - street: string; - city: string; - state: string; - postal_code: string; - country: string; - - email: string; - phone: string; - fax: string; - website: string; - - legal_record: string; - - default_tax: number; - status: string; - language_code: string; - currency_code: string; - logo: string; -} - -export interface IGetAccountResponseDTO { - id: string; - - is_companyr: boolean; - name: string; - trade_name: string; - tin: string; - - street: string; - city: string; - state: string; - postal_code: string; - country: string; - - email: string; - phone: string; - fax: string; - website: string; - - legal_record: string; - - default_tax: number; - status: string; - language_code: string; - currency_code: string; - logo: string; -} - -export interface ICreateAccountResponseDTO { - id: string; - - is_companyr: boolean; - name: string; - trade_name: string; - tin: string; - - street: string; - city: string; - state: string; - postal_code: string; - country: string; - - email: string; - phone: string; - fax: string; - website: string; - - legal_record: string; - - default_tax: number; - status: string; - language_code: string; - currency_code: string; - logo: string; -} - -// Inferir el tipo en TypeScript desde el esquema Zod -//export type IUpdateAcccountResponseDTO = z.infer; - -export interface IUpdateAccountResponseDTO { - id: string; - - is_companyr: boolean; - name: string; - trade_name: string; - tin: string; - - street: string; - city: string; - state: string; - postal_code: string; - country: string; - - email: string; - phone: string; - fax: string; - website: string; - - legal_record: string; - - default_tax: number; - status: string; - language_code: string; - currency_code: string; - logo: string; -} diff --git a/apps/server/archive/contexts/accounts/presentation/dto/accounts.schemas.ts b/apps/server/archive/contexts/accounts/presentation/dto/accounts.schemas.ts deleted file mode 100644 index 504fc1d9..00000000 --- a/apps/server/archive/contexts/accounts/presentation/dto/accounts.schemas.ts +++ /dev/null @@ -1,63 +0,0 @@ -import * as z from "zod/v4"; - -export const ListAccountsRequestSchema = z.object({}); - -export const IGetAccountRequestSchema = z.object({}); - -export const ICreateAccountRequestSchema = z.object({ - id: z.string(), - - is_companyr: z.boolean(), - name: z.string(), - trade_name: z.string(), - tin: z.string(), - - street: z.string(), - city: z.string(), - state: z.string(), - postal_code: z.string(), - country: z.string(), - - email: z.string().email(), // Validaci贸n espec铆fica para email - phone: z.string(), - fax: z.string(), - website: z.string().url(), // Validaci贸n espec铆fica para URL - - legal_record: z.string(), - - default_tax: z.number(), - status: z.string(), - language_code: LanguageCodeSchema, - currency_code: CurrencyCodeSchema, - logo: z.string(), -}); - -export const IUpdateAccountRequestSchema = z.object({ - id: z.string(), - - is_companyr: z.boolean(), - name: z.string(), - trade_name: z.string(), - tin: z.string(), - - street: z.string(), - city: z.string(), - state: z.string(), - postal_code: z.string(), - country: z.string(), - - email: z.string().email(), // Validaci贸n espec铆fica para email - phone: z.string(), - fax: z.string(), - website: z.string().url(), // Validaci贸n espec铆fica para URL - - legal_record: z.string(), - - default_tax: z.number(), - status: z.string(), - language_code: LanguageCodeSchema, - currency_code: CurrencyCodeSchema, - logo: z.string(), -}); - -export const IDeleteAccountRequestSchema = z.object({}); diff --git a/apps/server/archive/contexts/accounts/presentation/dto/index.ts b/apps/server/archive/contexts/accounts/presentation/dto/index.ts deleted file mode 100644 index c2224ec7..00000000 --- a/apps/server/archive/contexts/accounts/presentation/dto/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -export * from "./accounts.request.dto"; -export * from "./accounts.response.dto"; -export * from "./accounts.schemas"; diff --git a/apps/server/archive/contexts/accounts/presentation/index.ts b/apps/server/archive/contexts/accounts/presentation/index.ts deleted file mode 100644 index a123289d..00000000 --- a/apps/server/archive/contexts/accounts/presentation/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from "./controllers"; -export * from "./dto"; diff --git a/apps/server/archive/contexts/auth/application/index.ts b/apps/server/archive/contexts/auth/application/index.ts deleted file mode 100644 index fec328bf..00000000 --- a/apps/server/archive/contexts/auth/application/index.ts +++ /dev/null @@ -1,5 +0,0 @@ -export * from "./list-users"; -export * from "./login"; -export * from "./logout"; -export * from "./refresh-token"; -export * from "./register"; diff --git a/apps/server/archive/contexts/auth/application/list-users/index.ts b/apps/server/archive/contexts/auth/application/list-users/index.ts deleted file mode 100644 index 47eeda4a..00000000 --- a/apps/server/archive/contexts/auth/application/list-users/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from "./list-users.use-case"; diff --git a/apps/server/archive/contexts/auth/application/list-users/list-users.use-case.ts b/apps/server/archive/contexts/auth/application/list-users/list-users.use-case.ts deleted file mode 100644 index 92412fa7..00000000 --- a/apps/server/archive/contexts/auth/application/list-users/list-users.use-case.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { ITransactionManager } from "@/core/common/infrastructure/database"; -import { Collection, Result } from "@repo/rdx-utils"; -import { User } from "../../domain"; -import { IUserService } from "../../domain/services"; - -export class ListUsersUseCase { - constructor( - private readonly userService: IUserService, - private readonly transactionManager: ITransactionManager - ) {} - - public execute(): Promise, Error>> { - return this.transactionManager.complete((transaction) => { - return this.userService.findUsers(transaction); - }); - } -} diff --git a/apps/server/archive/contexts/auth/application/login/index.ts b/apps/server/archive/contexts/auth/application/login/index.ts deleted file mode 100644 index 71e9adab..00000000 --- a/apps/server/archive/contexts/auth/application/login/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from "./login.use-case"; diff --git a/apps/server/archive/contexts/auth/application/login/login.use-case.ts b/apps/server/archive/contexts/auth/application/login/login.use-case.ts deleted file mode 100644 index 989ba01e..00000000 --- a/apps/server/archive/contexts/auth/application/login/login.use-case.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { ITransactionManager } from "@/core/common/infrastructure/database"; -import { LoginData } from "../../domain"; -import { IAuthService } from "../../domain/services"; - -export class LoginUseCase { - constructor( - private readonly authService: IAuthService, - private readonly transactionManager: ITransactionManager - ) {} - - public async execute(loginData: LoginData) { - return await this.transactionManager.complete(async (transaction) => { - return await this.authService.loginUser(loginData, transaction); - }); - } -} diff --git a/apps/server/archive/contexts/auth/application/logout/index.ts b/apps/server/archive/contexts/auth/application/logout/index.ts deleted file mode 100644 index c7dcefc5..00000000 --- a/apps/server/archive/contexts/auth/application/logout/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from "./logout.use-case"; diff --git a/apps/server/archive/contexts/auth/application/logout/logout.use-case.ts b/apps/server/archive/contexts/auth/application/logout/logout.use-case.ts deleted file mode 100644 index 7d45e974..00000000 --- a/apps/server/archive/contexts/auth/application/logout/logout.use-case.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { ITransactionManager } from "@/core/common/infrastructure/database"; -import { LogoutData } from "../../domain"; -import { IAuthService } from "../../domain/services"; - -export class LogoutUseCase { - constructor( - private readonly authService: IAuthService, - private readonly transactionManager: ITransactionManager - ) {} - - public async execute(logoutData: LogoutData) { - return await this.transactionManager.complete(async (transaction) => { - return await this.authService.logoutUser(logoutData, transaction); - }); - } -} diff --git a/apps/server/archive/contexts/auth/application/refresh-token/index.ts b/apps/server/archive/contexts/auth/application/refresh-token/index.ts deleted file mode 100644 index e1939e9b..00000000 --- a/apps/server/archive/contexts/auth/application/refresh-token/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from "./refresh-token.use-case"; diff --git a/apps/server/archive/contexts/auth/application/refresh-token/refresh-token.use-case.ts b/apps/server/archive/contexts/auth/application/refresh-token/refresh-token.use-case.ts deleted file mode 100644 index 3dc2c11f..00000000 --- a/apps/server/archive/contexts/auth/application/refresh-token/refresh-token.use-case.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { ITransactionManager } from "@/core/common/infrastructure/database"; -import { Token } from "../../domain"; -import { IAuthService } from "../../domain/services"; - -export class RefreshTokenUseCase { - constructor( - private readonly authService: IAuthService, - private readonly transactionManager: ITransactionManager - ) {} - - public async execute(token: Token) { - return await this.transactionManager.complete(async (transaction) => { - const payloadData = this.authService.verifyRefreshToken(token); - - /*if (!payload || !payload.email || !payload.user_id || !payload.tab_id || !payload.roles) { - return Result.fail(new Error("Invalid input data")); - }*/ - - return this.authService.generateRefreshToken({ - ...payloadData, - }); - }); - } -} diff --git a/apps/server/archive/contexts/auth/application/register/index.ts b/apps/server/archive/contexts/auth/application/register/index.ts deleted file mode 100644 index 8d88027a..00000000 --- a/apps/server/archive/contexts/auth/application/register/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from "./register.use-case"; diff --git a/apps/server/archive/contexts/auth/application/register/register.use-case.ts b/apps/server/archive/contexts/auth/application/register/register.use-case.ts deleted file mode 100644 index 08dec2a3..00000000 --- a/apps/server/archive/contexts/auth/application/register/register.use-case.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { ITransactionManager } from "@/core/common/infrastructure/database"; -import { logger } from "@/core/logger"; -import { Result } from "@repo/rdx-utils"; -import { RegisterData } from "../../domain"; -import { IAuthService } from "../../domain/services"; - -export class RegisterUseCase { - constructor( - private readonly authService: IAuthService, - private readonly transactionManager: ITransactionManager - ) {} - - public async execute(registerData: RegisterData) { - return await this.transactionManager.complete(async (transaction) => { - try { - return await this.authService.registerUser(registerData, transaction); - } catch (error: unknown) { - logger.error(error as Error); - return Result.fail(error as Error); - } - }); - } -} diff --git a/apps/server/archive/contexts/auth/domain/aggregates/authenticated-user.ts b/apps/server/archive/contexts/auth/domain/aggregates/authenticated-user.ts deleted file mode 100644 index e64458a8..00000000 --- a/apps/server/archive/contexts/auth/domain/aggregates/authenticated-user.ts +++ /dev/null @@ -1,91 +0,0 @@ -import { Result } from "@repo/rdx-utils"; - -import { AggregateRoot, EmailAddress, UniqueID } from "@/core/common/domain"; -import { UserAuthenticatedEvent } from "../events"; -import { HashPassword, PlainPassword, Username } from "../value-objects"; - -export interface IAuthenticatedUserProps { - username: Username; - email: EmailAddress; - hashPassword: HashPassword; - roles: string[]; -} - -export interface IAuthenticatedUser { - username: Username; - email: EmailAddress; - hashPassword: HashPassword; - - accessToken: string; - refreshToken: string; - - isUser: boolean; - isAdmin: boolean; - - verifyPassword(candidatePassword: PlainPassword): Promise; - hasRole(role: string): boolean; - hasRoles(roles: string[]): boolean; - getRoles(): string[]; - toPersistenceData(): any; -} - -export class AuthenticatedUser - extends AggregateRoot - implements IAuthenticatedUser -{ - public accessToken = ""; - public refreshToken = ""; - - static create(props: IAuthenticatedUserProps, id: UniqueID): Result { - const user = new AuthenticatedUser(props, id); - - // 馃敼 Disparar evento de dominio "UserAuthenticatedEvent" - const { email } = props; - user.addDomainEvent(new UserAuthenticatedEvent(id, email.toString())); - - return Result.ok(user); - } - - verifyPassword(candidatePassword: PlainPassword): Promise { - return this.props.hashPassword.verifyPassword(candidatePassword.toString()); - } - - getRoles(): string[] { - return this.props.roles; - } - - hasRole(role: string): boolean { - return (this.props.roles || []).some((r) => r === role); - } - - hasRoles(roles: string[]): boolean { - return roles && roles.map((rol) => this.hasRole(rol)).some((value) => value != false); - } - - get username(): Username { - return this.props.username; - } - - get email(): EmailAddress { - return this.props.email; - } - - get hashPassword(): HashPassword { - return this.props.hashPassword; - } - - get isUser(): boolean { - return this.hasRole("user"); - } - - get isAdmin(): boolean { - return this.hasRole("admin"); - } - - /** - * 馃敼 Devuelve una representaci贸n lista para persistencia - */ - toPersistenceData(): any { - return; - } -} diff --git a/apps/server/archive/contexts/auth/domain/aggregates/index.ts b/apps/server/archive/contexts/auth/domain/aggregates/index.ts deleted file mode 100644 index a20563f2..00000000 --- a/apps/server/archive/contexts/auth/domain/aggregates/index.ts +++ /dev/null @@ -1,4 +0,0 @@ -export * from "./authenticated-user"; - -export * from "./role"; -export * from "./user"; diff --git a/apps/server/archive/contexts/auth/domain/aggregates/role.ts b/apps/server/archive/contexts/auth/domain/aggregates/role.ts deleted file mode 100644 index f01c51f2..00000000 --- a/apps/server/archive/contexts/auth/domain/aggregates/role.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { AggregateRoot, UniqueID } from "@/core/common/domain"; -import { Result } from "@repo/rdx-utils"; - -export type IRoleProps = {}; - -export type IRole = {}; - -export class Role extends AggregateRoot implements IRole { - static create(props: IRoleProps, id: UniqueID): Result { - const role = new Role(props, id); - return Result.ok(role); - } - - toPersistenceData(): any {} -} diff --git a/apps/server/archive/contexts/auth/domain/aggregates/user-permission.ts b/apps/server/archive/contexts/auth/domain/aggregates/user-permission.ts deleted file mode 100644 index e69de29b..00000000 diff --git a/apps/server/archive/contexts/auth/domain/aggregates/user.ts b/apps/server/archive/contexts/auth/domain/aggregates/user.ts deleted file mode 100644 index 4a05a0ae..00000000 --- a/apps/server/archive/contexts/auth/domain/aggregates/user.ts +++ /dev/null @@ -1,67 +0,0 @@ -import { AggregateRoot, EmailAddress, UniqueID } from "@/core/common/domain"; -import { Result } from "@repo/rdx-utils"; -import { UserAuthenticatedEvent } from "../events"; -import { Username } from "../value-objects"; - -export interface IUserProps { - username: Username; - email: EmailAddress; - roles: string[]; -} - -export interface IUser { - username: Username; - email: EmailAddress; - - isUser: boolean; - isAdmin: boolean; - isActive: boolean; - - hasRole(role: string): boolean; - hasRoles(roles: string[]): boolean; - getRoles(): string[]; -} - -export class User extends AggregateRoot implements IUser { - static create(props: IUserProps, id: UniqueID): Result { - const user = new User(props, id); - - // 馃敼 Disparar evento de dominio "UserAuthenticatedEvent" - const { email } = props; - user.addDomainEvent(new UserAuthenticatedEvent(id, email.toString())); - - return Result.ok(user); - } - - getRoles(): string[] { - return this.props.roles; - } - - hasRole(role: string): boolean { - return (this.props.roles || []).some((r) => r === role); - } - - hasRoles(roles: string[]): boolean { - return roles.map((rol) => this.hasRole(rol)).some((value) => value != false); - } - - get username(): Username { - return this.props.username; - } - - get email(): EmailAddress { - return this.props.email; - } - - get isUser(): boolean { - return this.hasRole("user"); - } - - get isAdmin(): boolean { - return this.hasRole("admin"); - } - - get isActive(): boolean { - return true; - } -} diff --git a/apps/server/archive/contexts/auth/domain/entities/index.ts b/apps/server/archive/contexts/auth/domain/entities/index.ts deleted file mode 100644 index a66561ad..00000000 --- a/apps/server/archive/contexts/auth/domain/entities/index.ts +++ /dev/null @@ -1,5 +0,0 @@ -export * from "./jwt-payload"; -export * from "./login-data"; -export * from "./logout-data"; -export * from "./register-data"; -export * from "./tab-context"; diff --git a/apps/server/archive/contexts/auth/domain/entities/jwt-payload.ts b/apps/server/archive/contexts/auth/domain/entities/jwt-payload.ts deleted file mode 100644 index 220e1a5c..00000000 --- a/apps/server/archive/contexts/auth/domain/entities/jwt-payload.ts +++ /dev/null @@ -1,67 +0,0 @@ -import { DomainEntity, EmailAddress, UniqueID } from "@/core/common/domain"; -import { Result } from "@repo/rdx-utils"; - -export interface IJWTPayloadProps { - tabId: UniqueID; - userId: UniqueID; - email: EmailAddress; -} - -export interface IJWTPayloadPrimitives { - tab_id: string; - user_id: string; - email: string; -} - -export interface IJWTPayload { - tabId: UniqueID; - userId: UniqueID; - email: EmailAddress; - - toPersistenceData(): any; -} - -export class JWTPayload extends DomainEntity implements IJWTPayload { - static create(props: IJWTPayloadProps): Result { - return Result.ok(new JWTPayload(props)); - } - - static createFromPrimitives(values: IJWTPayloadPrimitives): Result { - const { email, user_id, tab_id } = values; - const emailOrError = EmailAddress.create(email); - const userIdOrError = UniqueID.create(user_id, false); - const tabIdOrError = UniqueID.create(tab_id, false); - - const result = Result.combine([emailOrError, userIdOrError, tabIdOrError]); - - if (result.isFailure) { - return Result.fail(result.error); - } - - return JWTPayload.create({ - email: emailOrError.data, - userId: userIdOrError.data, - tabId: tabIdOrError.data, - }); - } - - get tabId(): UniqueID { - return this.props.tabId; - } - - get userId(): UniqueID { - return this.props.userId; - } - - get email(): EmailAddress { - return this.props.email; - } - - toPersistenceData(): any { - return { - tab_id: this.tabId.toString(), - user_id: this.userId.toString(), - email: this.email.toString(), - }; - } -} diff --git a/apps/server/archive/contexts/auth/domain/entities/login-data.ts b/apps/server/archive/contexts/auth/domain/entities/login-data.ts deleted file mode 100644 index 72909387..00000000 --- a/apps/server/archive/contexts/auth/domain/entities/login-data.ts +++ /dev/null @@ -1,58 +0,0 @@ -import { DomainEntity, EmailAddress, UniqueID } from "@/core/common/domain"; -import { Result } from "@repo/rdx-utils"; -import { PlainPassword } from "../value-objects"; - -export interface ILoginDataProps { - email: EmailAddress; - plainPassword: PlainPassword; - tabId: UniqueID; -} - -export interface ILoginDataPrimitives { - email: string; - plainPassword: string; - tabId: string; -} - -export interface ILoginData { - email: EmailAddress; - plainPassword: PlainPassword; - tabId: UniqueID; -} - -export class LoginData extends DomainEntity implements ILoginData { - static create(props: ILoginDataProps): Result { - return Result.ok(new this(props)); - } - - static createFromPrimitives(values: ILoginDataPrimitives): Result { - const { email, plainPassword, tabId } = values; - const emailOrError = EmailAddress.create(email); - const plainPasswordOrError = PlainPassword.create(plainPassword); - const tabIdOrError = UniqueID.create(tabId, false); - - const result = Result.combine([emailOrError, plainPasswordOrError, tabIdOrError]); - - if (result.isFailure) { - return Result.fail(result.error); - } - - return LoginData.create({ - email: emailOrError.data, - plainPassword: plainPasswordOrError.data, - tabId: tabIdOrError.data, - }); - } - - get email(): EmailAddress { - return this.props.email; - } - - get plainPassword(): PlainPassword { - return this.props.plainPassword; - } - - get tabId(): UniqueID { - return this.props.tabId; - } -} diff --git a/apps/server/archive/contexts/auth/domain/entities/logout-data.ts b/apps/server/archive/contexts/auth/domain/entities/logout-data.ts deleted file mode 100644 index 1c30f557..00000000 --- a/apps/server/archive/contexts/auth/domain/entities/logout-data.ts +++ /dev/null @@ -1,48 +0,0 @@ -import { DomainEntity, EmailAddress, UniqueID } from "@/core/common/domain"; -import { Result } from "@repo/rdx-utils"; - -export interface ILogoutDataProps { - email: EmailAddress; - tabId: UniqueID; -} - -export interface ILogoutDataPrimitives { - email: string; - tabId: string; -} - -export interface ILogoutData { - email: EmailAddress; - tabId: UniqueID; -} - -export class LogoutData extends DomainEntity implements ILogoutData { - static create(props: ILogoutDataProps): Result { - return Result.ok(new this(props)); - } - - static createFromPrimitives(values: ILogoutDataPrimitives): Result { - const { email, tabId } = values; - const emailOrError = EmailAddress.create(email); - const tabIdOrError = UniqueID.create(tabId, false); - - const result = Result.combine([emailOrError, tabIdOrError]); - - if (result.isFailure) { - return Result.fail(result.error); - } - - return LogoutData.create({ - email: emailOrError.data, - tabId: tabIdOrError.data, - }); - } - - get email(): EmailAddress { - return this.props.email; - } - - get tabId(): UniqueID { - return this.props.tabId; - } -} diff --git a/apps/server/archive/contexts/auth/domain/entities/register-data.ts b/apps/server/archive/contexts/auth/domain/entities/register-data.ts deleted file mode 100644 index 7ccf8311..00000000 --- a/apps/server/archive/contexts/auth/domain/entities/register-data.ts +++ /dev/null @@ -1,59 +0,0 @@ -import { DomainEntity, EmailAddress } from "@/core/common/domain"; -import { Result } from "@repo/rdx-utils"; -import { HashPassword, Username } from "../value-objects"; - -export interface IRegisterDataProps { - username: Username; - email: EmailAddress; - hashPassword: HashPassword; -} - -export interface IRegisterDataPrimitives { - username: string; - email: string; - plainPassword: string; -} - -export interface IRegisterData { - username: Username; - email: EmailAddress; - hashPassword: HashPassword; -} - -export class RegisterData extends DomainEntity implements IRegisterData { - static create(props: IRegisterDataProps): Result { - return Result.ok(new this(props)); - } - - static createFromPrimitives(props: IRegisterDataPrimitives): Result { - const { username, email, plainPassword } = props; - - const userNameOrError = Username.create(username); - const emailOrError = EmailAddress.create(email); - const hashPasswordOrError = HashPassword.createFromPlainText(plainPassword); - - const result = Result.combine([userNameOrError, emailOrError, hashPasswordOrError]); - - if (result.isFailure) { - return Result.fail(result.error); - } - - return RegisterData.create({ - username: userNameOrError.data, - email: emailOrError.data, - hashPassword: hashPasswordOrError.data, - }); - } - - get username(): Username { - return this.props.username; - } - - get email(): EmailAddress { - return this.props.email; - } - - get hashPassword(): HashPassword { - return this.props.hashPassword; - } -} diff --git a/apps/server/archive/contexts/auth/domain/entities/tab-context.ts b/apps/server/archive/contexts/auth/domain/entities/tab-context.ts deleted file mode 100644 index 92284247..00000000 --- a/apps/server/archive/contexts/auth/domain/entities/tab-context.ts +++ /dev/null @@ -1,49 +0,0 @@ -import { DomainEntity, UniqueID } from "@/core/common/domain"; -import { Result } from "@repo/rdx-utils"; - -export interface ITabContextProps { - tabId: UniqueID; - userId: UniqueID; -} - -export interface ITabContextPrimitives { - id: string; - tab_id: string; - user_id: string; -} - -export interface ITabContext { - tabId: UniqueID; - userId: UniqueID; -} - -export class TabContext extends DomainEntity implements ITabContext { - static create(props: ITabContextProps, id?: UniqueID): Result { - return Result.ok(new this(props, id)); - } - - static createFromPrimitives(values: ITabContextPrimitives): Result { - const { user_id, tab_id } = values; - const userIdOrError = UniqueID.create(user_id, false); - const tabIdOrError = UniqueID.create(tab_id, false); - - const result = Result.combine([userIdOrError, tabIdOrError]); - - if (result.isFailure) { - return Result.fail(result.error); - } - - return TabContext.create({ - userId: userIdOrError.data, - tabId: tabIdOrError.data, - }); - } - - get tabId(): UniqueID { - return this.props.tabId; - } - - get userId(): UniqueID { - return this.props.userId; - } -} diff --git a/apps/server/archive/contexts/auth/domain/events/index.ts b/apps/server/archive/contexts/auth/domain/events/index.ts deleted file mode 100644 index c228d2e1..00000000 --- a/apps/server/archive/contexts/auth/domain/events/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from "./user-authenticated.event"; diff --git a/apps/server/archive/contexts/auth/domain/events/user-authenticated.event.ts b/apps/server/archive/contexts/auth/domain/events/user-authenticated.event.ts deleted file mode 100644 index 84e80692..00000000 --- a/apps/server/archive/contexts/auth/domain/events/user-authenticated.event.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { IDomainEvent, UniqueID } from "@/core/common/domain"; - -export class UserAuthenticatedEvent implements IDomainEvent { - public readonly eventName = "UserAuthenticated"; - public readonly occurredAt: Date; - - constructor( - public readonly aggregateId: UniqueID, - public readonly email: string // Email en formato string - ) { - this.occurredAt = new Date(); - } -} diff --git a/apps/server/archive/contexts/auth/domain/index.ts b/apps/server/archive/contexts/auth/domain/index.ts deleted file mode 100644 index 4a16e729..00000000 --- a/apps/server/archive/contexts/auth/domain/index.ts +++ /dev/null @@ -1,5 +0,0 @@ -export * from "./aggregates"; -export * from "./entities"; -export * from "./events"; -export * from "./repositories"; -export * from "./value-objects"; diff --git a/apps/server/archive/contexts/auth/domain/repositories/authenticated-user-repository.interface.ts b/apps/server/archive/contexts/auth/domain/repositories/authenticated-user-repository.interface.ts deleted file mode 100644 index 707417a2..00000000 --- a/apps/server/archive/contexts/auth/domain/repositories/authenticated-user-repository.interface.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { Result } from "@repo/rdx-utils"; - -import { EmailAddress } from "@/core/common/domain"; -import { AuthenticatedUser } from "../aggregates"; -import { Username } from "../value-objects"; - -export interface IAuthenticatedUserRepository { - getUserByEmail(email: EmailAddress, transaction?: any): Promise>; - userExists( - username: Username, - email: EmailAddress, - transaction?: any - ): Promise>; - createUser(user: AuthenticatedUser, transaction?: any): Promise>; -} diff --git a/apps/server/archive/contexts/auth/domain/repositories/index.ts b/apps/server/archive/contexts/auth/domain/repositories/index.ts deleted file mode 100644 index b5f0a9ed..00000000 --- a/apps/server/archive/contexts/auth/domain/repositories/index.ts +++ /dev/null @@ -1,4 +0,0 @@ -export * from "./authenticated-user-repository.interface"; -export * from "./tab-context-repository.interface"; -export * from "./user-permission-repository.interface"; -export * from "./user-repository.interface"; diff --git a/apps/server/archive/contexts/auth/domain/repositories/tab-context-repository.interface.ts b/apps/server/archive/contexts/auth/domain/repositories/tab-context-repository.interface.ts deleted file mode 100644 index fd840a08..00000000 --- a/apps/server/archive/contexts/auth/domain/repositories/tab-context-repository.interface.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { UniqueID } from "@/core/common/domain"; -import { Result } from "@repo/rdx-utils"; -import { Transaction } from "sequelize"; -import { TabContext } from "../entities"; - -export interface ITabContextRepository { - getContextByTabId(tabId: UniqueID, transaction?: any): Promise>; - - contextExistsByTabId(tabId: UniqueID, transaction?: any): Promise>; - - registerContextByTabId( - context: TabContext, - transaction?: Transaction - ): Promise>; - - unregisterContextByTabId( - context: TabContext, - transaction?: Transaction - ): Promise>; -} diff --git a/apps/server/archive/contexts/auth/domain/repositories/user-permission-repository.interface.ts b/apps/server/archive/contexts/auth/domain/repositories/user-permission-repository.interface.ts deleted file mode 100644 index dcb36c54..00000000 --- a/apps/server/archive/contexts/auth/domain/repositories/user-permission-repository.interface.ts +++ /dev/null @@ -1 +0,0 @@ -export type IUserPermissionRepository = {} diff --git a/apps/server/archive/contexts/auth/domain/repositories/user-repository.interface.ts b/apps/server/archive/contexts/auth/domain/repositories/user-repository.interface.ts deleted file mode 100644 index 2a372477..00000000 --- a/apps/server/archive/contexts/auth/domain/repositories/user-repository.interface.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { EmailAddress, UniqueID } from "@/core/common/domain"; -import { Collection, Result } from "@repo/rdx-utils"; -import { User } from "../aggregates"; - -export interface IUserRepository { - findAll(transaction?: any): Promise, Error>>; - findById(id: UniqueID, transaction?: any): Promise>; - findByEmail(email: EmailAddress, transaction?: any): Promise>; -} diff --git a/apps/server/archive/contexts/auth/domain/services/auth-service.interface.ts b/apps/server/archive/contexts/auth/domain/services/auth-service.interface.ts deleted file mode 100644 index 420e8b18..00000000 --- a/apps/server/archive/contexts/auth/domain/services/auth-service.interface.ts +++ /dev/null @@ -1,42 +0,0 @@ -import { EmailAddress } from "@/core/common/domain"; -import { Result } from "@repo/rdx-utils"; -import { - AuthenticatedUser, - IJWTPayload, - LoginData, - LogoutData, - RegisterData, - TabContext, - Token, -} from ".."; - -export interface IAuthService { - generateAccessToken(payload: IJWTPayload): Result; - generateRefreshToken(payload: IJWTPayload): Result; - verifyRefreshToken(token: Token): IJWTPayload; - - registerUser( - registerData: RegisterData, - transaction?: any - ): Promise>; - - loginUser( - loginData: LoginData, - transaction?: any - ): Promise< - Result< - { - user: AuthenticatedUser; - tabContext: TabContext; - tokens: { - accessToken: Token; - refreshToken: Token; - }; - }, - Error - > - >; - - logoutUser(logoutData: LogoutData, transaction?: any): Promise>; - getUserByEmail(email: EmailAddress, transaction?: any): Promise>; -} diff --git a/apps/server/archive/contexts/auth/domain/services/auth.service.ts b/apps/server/archive/contexts/auth/domain/services/auth.service.ts deleted file mode 100644 index 91bf4d9f..00000000 --- a/apps/server/archive/contexts/auth/domain/services/auth.service.ts +++ /dev/null @@ -1,205 +0,0 @@ -import { EmailAddress } from "@/core/common/domain"; -import { Result } from "@repo/rdx-utils"; -import { - AuthenticatedUser, - type IJWTPayload, - type LoginData, - type RegisterData, - TabContext, - Token, -} from ".."; - -import { UniqueID } from "@/core/common/domain"; -import { IAuthenticatedUserRepository, JWTPayload } from ".."; -import { JwtHelper } from "../../../../../../../modules/auth/src/api/lib/passport/jwt.helper"; -import { ITabContextRepository } from "../repositories/tab-context-repository.interface"; -import { IAuthService } from "./auth-service.interface"; - -const ACCESS_EXPIRATION = process.env.JWT_ACCESS_EXPIRATION || "1h"; -const REFRESH_EXPIRATION = process.env.JWT_REFRESH_EXPIRATION || "7d"; - -export class AuthService implements IAuthService { - constructor( - private readonly authUserRepo: IAuthenticatedUserRepository, - private readonly tabContextRepo: ITabContextRepository - ) {} - - generateAccessToken(payload: IJWTPayload): Result { - const data = payload.toPersistenceData(); - return Token.create(JwtHelper.generateToken(data, ACCESS_EXPIRATION)); - } - - generateRefreshToken(payload: IJWTPayload): Result { - const data = payload.toPersistenceData(); - return Token.create(JwtHelper.generateToken(data, REFRESH_EXPIRATION)); - } - - verifyRefreshToken(token: Token): IJWTPayload { - return JwtHelper.verifyToken(token.toString()); - } - - /** - * - * Registra un nuevo usuario en la base de datos bajo transacci贸n. - */ - async registerUser( - registerData: RegisterData, - transaction?: any - ): Promise> { - const { username, email, hashPassword } = registerData; - - // Verificar si el usuario ya existe - const userExists = await this.authUserRepo.userExists(username, email, transaction); - if (userExists.isSuccess && userExists.data) { - return Result.fail(new Error("Email is already registered")); - } - - const newUserId = UniqueID.generateNewID().data; - - const userOrError = AuthenticatedUser.create( - { - username, - email, - hashPassword, - roles: ["USER"], - }, - newUserId - ); - - if (userOrError.isFailure) { - return Result.fail(userOrError.error); - } - - const createdResult = await this.authUserRepo.createUser(userOrError.data, transaction); - - if (createdResult.isFailure) { - return Result.fail(createdResult.error); - } - - return Result.ok(userOrError.data); - } - - /** - * - * Autentica a un usuario validando su email y contrase帽a. - */ - async loginUser( - loginData: LoginData, - transaction?: any - ): Promise< - Result< - { - user: AuthenticatedUser; - tabContext: TabContext; - tokens: { - accessToken: Token; - refreshToken: Token; - }; - }, - Error - > - > { - let result: any; - const { email, plainPassword, tabId } = loginData; - - // 馃敼 Verificar si el usuario existe en la base de datos - result = await this.authUserRepo.getUserByEmail(email, transaction); - if (result.isFailure) { - return Result.fail(new Error("Invalid email or password")); - } - - const user = result.data; - - // 馃敼 Verificar que la contrase帽a sea correcta - const isValidPassword = await user.verifyPassword(plainPassword); - if (!isValidPassword) { - return Result.fail(new Error("Invalid email or password")); - } - - // Registrar o actualizar el contexto de ese tab ID - const contextOrError = TabContext.create({ - userId: user.id, - tabId: tabId, - }); - - // 馃敼 Generar Access Token y Refresh Token - const payloadOrError = JWTPayload.create({ - userId: user.id, - email: email, - tabId: tabId, - //roles: ["USER"], - }); - - result = Result.combine([contextOrError, payloadOrError]); - if (result.isFailure) { - return Result.fail(new Error("Error on login")); - } - - const tabContext = contextOrError.data; - await this.tabContextRepo.registerContextByTabId(tabContext, transaction); - - const accessTokenOrError = this.generateAccessToken(payloadOrError.data); - const refreshTokenOrError = this.generateRefreshToken(payloadOrError.data); - - result = Result.combine([accessTokenOrError, refreshTokenOrError]); - - if (result.isFailure) { - return Result.fail(result.error); - } - - return Result.ok({ - user, - tabContext, - tokens: { - accessToken: accessTokenOrError.data, - refreshToken: refreshTokenOrError.data, - }, - }); - } - - /** - * - * Autentica a un usuario validando su email y contrase帽a. - */ - async logoutUser( - params: { email: EmailAddress; tabId: UniqueID }, - transaction?: any - ): Promise> { - const { email, tabId } = params; - - // 馃敼 Verificar si el usuario existe en la base de datos - const userResult = await this.authUserRepo.getUserByEmail(email, transaction); - if (userResult.isFailure) { - return Result.fail(new Error("Invalid email or password")); - } - - const user = userResult.data; - - const contextOrError = TabContext.create({ - userId: user.id, - tabId: tabId, - }); - - if (contextOrError.isFailure) { - return Result.fail(new Error("Error creating user context")); - } - - // Desregistrar el contexto de ese tab ID - await this.tabContextRepo.unregisterContextByTabId(contextOrError.data, transaction); - - return Result.ok(); - } - - async getUserByEmail( - email: EmailAddress, - transaction?: any - ): Promise> { - const userResult = await this.authUserRepo.getUserByEmail(email, transaction); - - if (userResult.isFailure || !userResult.data) { - return Result.fail(new Error("Invalid email or password")); - } - - return Result.ok(userResult.data); - } -} diff --git a/apps/server/archive/contexts/auth/domain/services/index.ts b/apps/server/archive/contexts/auth/domain/services/index.ts deleted file mode 100644 index abde394c..00000000 --- a/apps/server/archive/contexts/auth/domain/services/index.ts +++ /dev/null @@ -1,8 +0,0 @@ -export * from "./auth-service.interface"; -export * from "./auth.service"; - -export * from "./tab-context-service.interface"; -export * from "./tab-context.service"; - -export * from "./user-service.interface"; -export * from "./user.service"; diff --git a/apps/server/archive/contexts/auth/domain/services/tab-context-service.interface.ts b/apps/server/archive/contexts/auth/domain/services/tab-context-service.interface.ts deleted file mode 100644 index b262cbfe..00000000 --- a/apps/server/archive/contexts/auth/domain/services/tab-context-service.interface.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { UniqueID } from "@/core/common/domain"; -import { Result } from "@repo/rdx-utils"; -import { TabContext } from "../entities"; - -export interface ITabContextService { - getContextByTabId(tabId: UniqueID, transaction?: any): Promise>; - createContext( - params: { tabId: UniqueID; userId: UniqueID }, - transaction?: any - ): Promise>; - removeContext( - params: { tabId: UniqueID; userId: UniqueID }, - transaction?: any - ): Promise>; -} diff --git a/apps/server/archive/contexts/auth/domain/services/tab-context.service.ts b/apps/server/archive/contexts/auth/domain/services/tab-context.service.ts deleted file mode 100644 index bf3843a3..00000000 --- a/apps/server/archive/contexts/auth/domain/services/tab-context.service.ts +++ /dev/null @@ -1,87 +0,0 @@ -import { UniqueID } from "@/core/common/domain"; -import { Result } from "@repo/rdx-utils"; -import { TabContext } from "../entities"; -import { ITabContextRepository } from "../repositories"; -import { ITabContextService } from "./tab-context-service.interface"; - -export class TabContextService implements ITabContextService { - constructor(private readonly tabContextRepo: ITabContextRepository) {} - - /** - * Obtiene el contexto de una pesta帽a por su ID - */ - async getContextByTabId(tabId: UniqueID, transaction?: any): Promise> { - // Verificar si la pesta帽a existe - const tabContextOrError = await this.tabContextRepo.getContextByTabId(tabId, transaction); - if (tabContextOrError.isSuccess && !tabContextOrError.data) { - return Result.fail(new Error("Invalid or expired Tab ID")); - } - - if (tabContextOrError.isFailure) { - return Result.fail(tabContextOrError.error); - } - - return Result.ok(tabContextOrError.data); - } - - /** - * Registra un nuevo contexto de pesta帽a para un usuario - */ - async createContext( - params: { - tabId: UniqueID; - userId: UniqueID; - }, - transaction?: any - ): Promise> { - const { tabId, userId } = params; - - if (!userId || !tabId) { - return Result.fail(new Error("User ID and Tab ID are required")); - } - - const contextOrError = TabContext.create( - { - userId, - tabId, - }, - UniqueID.generateNewID().data - ); - - if (contextOrError.isFailure) { - return Result.fail(contextOrError.error); - } - - await this.tabContextRepo.registerContextByTabId(contextOrError.data, transaction); - - return Result.ok(contextOrError.data); - } - - /** - * Elimina un contexto de pesta帽a por su ID - */ - async removeContext( - params: { tabId: UniqueID; userId: UniqueID }, - transaction?: any - ): Promise> { - const { tabId, userId } = params; - - if (!userId || !tabId) { - return Result.fail(new Error("User ID and Tab ID are required")); - } - - const contextOrError = TabContext.create( - { - userId, - tabId, - }, - UniqueID.generateNewID().data - ); - - if (contextOrError.isFailure) { - return Result.fail(contextOrError.error); - } - - return await this.tabContextRepo.unregisterContextByTabId(contextOrError.data, transaction); - } -} diff --git a/apps/server/archive/contexts/auth/domain/services/user-service.interface.ts b/apps/server/archive/contexts/auth/domain/services/user-service.interface.ts deleted file mode 100644 index 9bf57819..00000000 --- a/apps/server/archive/contexts/auth/domain/services/user-service.interface.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { UniqueID } from "@/core/common/domain"; -import { Collection, Result } from "@repo/rdx-utils"; -import { User } from "../aggregates"; - -export interface IUserService { - findUsers(transaction?: any): Promise, Error>>; - findUserById(userId: UniqueID, transaction?: any): Promise>; -} diff --git a/apps/server/archive/contexts/auth/domain/services/user.service.ts b/apps/server/archive/contexts/auth/domain/services/user.service.ts deleted file mode 100644 index d098f88a..00000000 --- a/apps/server/archive/contexts/auth/domain/services/user.service.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { UniqueID } from "@/core/common/domain"; -import { Collection, Result } from "@repo/rdx-utils"; -import { IUserRepository, User } from ".."; -import { IUserService } from "./user-service.interface"; - -export class UserService implements IUserService { - constructor(private readonly userRepository: IUserRepository) {} - - async findUsers(transaction?: any): Promise, Error>> { - const usersOrError = await this.userRepository.findAll(transaction); - if (usersOrError.isFailure) { - return Result.fail(usersOrError.error); - } - - // Solo devolver usuarios activos - const activeUsers = usersOrError.data.filter((user) => user.isActive); - return Result.ok(new Collection(activeUsers)); - } - - async findUserById(userId: UniqueID, transaction?: any): Promise> { - return await this.userRepository.findById(userId, transaction); - } - - /*public async createUser( - data: { name: string; email: EmailAddress }, - transaction?: Transaction - ): Promise> { - // Evitar duplicados por email - const existingUser = await this.userRepository.findByEmail(data.email); - if (existingUser.isSuccess) { - return Result.fail(new Error("El correo ya est谩 registrado.")); - } - - const newUser = User.create({ - email, - username - }) - return await this.userRepository.save(newUser, transaction); - }*/ -} diff --git a/apps/server/archive/contexts/auth/domain/value-objects/auth-user-roles.ts b/apps/server/archive/contexts/auth/domain/value-objects/auth-user-roles.ts deleted file mode 100644 index ff328bf4..00000000 --- a/apps/server/archive/contexts/auth/domain/value-objects/auth-user-roles.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { ValueObject } from "@repo/rdx-ddd"; -import { Result } from "@repo/rdx-utils"; -import * as z from "zod/v4"; - -const RoleSchema = z.enum(["Admin", "User", "Manager", "Editor"]); - -interface UserRolesProps { - value: string[]; -} - -export class UserRoles extends ValueObject { - static create(roles: string[]): Result { - const result = UserRoles.validate(roles); - - return result.success - ? Result.ok(new UserRoles({ value: result.data })) - : Result.fail(new Error("Invalid user roles")); - } - - private static validate(roles: string[]) { - return z.array(RoleSchema).safeParse(roles); - } - - hasRole(role: string): boolean { - return this.props.value.includes(role); - } - - getValue() { - return this.props.value; - } - - toPrimitive() { - return this.props.value; - } -} diff --git a/apps/server/archive/contexts/auth/domain/value-objects/hash-password.spec.ts b/apps/server/archive/contexts/auth/domain/value-objects/hash-password.spec.ts deleted file mode 100644 index 55733874..00000000 --- a/apps/server/archive/contexts/auth/domain/value-objects/hash-password.spec.ts +++ /dev/null @@ -1,44 +0,0 @@ -import bcrypt from "bcrypt"; -import { HashPassword } from "./hash-password"; - -describe("HashPassword", () => { - test("debe crear una instancia de HashPassword desde un texto plano v谩lido", () => { - const result = HashPassword.createFromPlainText("securepassword"); - expect(result.isSuccess).toBe(true); - expect(result.data).toBeInstanceOf(HashPassword); - }); - - test("debe fallar al crear una instancia con una contrase帽a demasiado corta", () => { - const result = HashPassword.createFromPlainText("123"); - expect(result.isFailure).toBe(true); - expect(result.error.message).toBe("Password must be at least 6 characters long"); - }); - - test("debe crear una instancia de HashPassword desde un hash v谩lido", () => { - const hashedPassword = bcrypt.hashSync("securepassword", 10); - const result = HashPassword.createFromHash(hashedPassword); - expect(result.isSuccess).toBe(true); - expect(result.data).toBeInstanceOf(HashPassword); - }); - - test("debe verificar correctamente una contrase帽a v谩lida", async () => { - const password = "securepassword"; - const result = HashPassword.createFromPlainText(password); - expect(result.isSuccess).toBe(true); - const hashPasswordInstance = result.data; - - const isValid = await hashPasswordInstance.verifyPassword(password); - expect(isValid).toBe(true); - }); - - test("debe fallar la verificaci贸n con una contrase帽a incorrecta", async () => { - const password = "securepassword"; - const wrongPassword = "wrongpassword"; - const result = HashPassword.createFromPlainText(password); - expect(result.isSuccess).toBe(true); - const hashPasswordInstance = result.data; - - const isValid = await hashPasswordInstance.verifyPassword(wrongPassword); - expect(isValid).toBe(false); - }); -}); diff --git a/apps/server/archive/contexts/auth/domain/value-objects/hash-password.ts b/apps/server/archive/contexts/auth/domain/value-objects/hash-password.ts deleted file mode 100644 index f7c2511d..00000000 --- a/apps/server/archive/contexts/auth/domain/value-objects/hash-password.ts +++ /dev/null @@ -1,48 +0,0 @@ -import { ValueObject } from "@repo/rdx-ddd"; -import { Result } from "@repo/rdx-utils"; -import bcrypt from "bcrypt"; -import * as z from "zod/v4"; - -interface HashPasswordProps { - value: string; -} - -export class HashPassword extends ValueObject { - private static readonly SALT_ROUNDS = 10; - - static createFromPlainText(plainTextPassword: string): Result { - const result = HashPassword.validate(plainTextPassword); - - if (!result.success) { - return Result.fail(new Error(result.error.errors[0].message)); - } - - const hashed = bcrypt.hashSync(result.data, this.SALT_ROUNDS); - return Result.ok(new HashPassword({ value: hashed })); - } - - private static validate(password: string) { - const schema = z.string().min(6, { message: "Password must be at least 6 characters long" }); - return schema.safeParse(password); - } - - static createFromHash(hashedPassword: string): Result { - return Result.ok(new HashPassword({ value: hashedPassword })); - } - - async verifyPassword(plainTextPassword: string): Promise { - return await bcrypt.compare(plainTextPassword, this.props.value); - } - - getValue() { - return this.props.value; - } - - toString() { - return this.props.value; - } - - toPrimitive() { - return this.props.value; - } -} diff --git a/apps/server/archive/contexts/auth/domain/value-objects/index.ts b/apps/server/archive/contexts/auth/domain/value-objects/index.ts deleted file mode 100644 index b3bdb2e3..00000000 --- a/apps/server/archive/contexts/auth/domain/value-objects/index.ts +++ /dev/null @@ -1,5 +0,0 @@ -export * from "./auth-user-roles"; -export * from "./hash-password"; -export * from "./plain-password"; -export * from "./token"; -export * from "./username"; diff --git a/apps/server/archive/contexts/auth/domain/value-objects/plain-password.ts b/apps/server/archive/contexts/auth/domain/value-objects/plain-password.ts deleted file mode 100644 index cdd92a53..00000000 --- a/apps/server/archive/contexts/auth/domain/value-objects/plain-password.ts +++ /dev/null @@ -1,36 +0,0 @@ -import { ValueObject } from "@repo/rdx-ddd"; -import { Result } from "@repo/rdx-utils"; -import * as z from "zod/v4"; - -interface PlainPasswordProps { - value: string; -} - -export class PlainPassword extends ValueObject { - static create(plainTextPassword: string): Result { - const result = PlainPassword.validate(plainTextPassword); - - if (!result.success) { - return Result.fail(new Error(result.error.errors[0].message)); - } - - return Result.ok(new PlainPassword({ value: result.data })); - } - - private static validate(password: string) { - const schema = z.string().min(6, { message: "Password must be at least 6 characters long" }); - return schema.safeParse(password); - } - - getValue() { - return this.props.value; - } - - toString() { - return this.props.value; - } - - toPrimitive() { - return this.props.value; - } -} diff --git a/apps/server/archive/contexts/auth/domain/value-objects/token.ts b/apps/server/archive/contexts/auth/domain/value-objects/token.ts deleted file mode 100644 index d989904b..00000000 --- a/apps/server/archive/contexts/auth/domain/value-objects/token.ts +++ /dev/null @@ -1,36 +0,0 @@ -import { ValueObject } from "@repo/rdx-ddd"; -import { Result } from "@repo/rdx-utils"; -import * as z from "zod/v4"; - -interface TokenProps { - value: string; -} - -export class Token extends ValueObject { - static create(token: string): Result { - const result = Token.validate(token); - - if (!result.success) { - return Result.fail(new Error(result.error.errors[0].message)); - } - - return Result.ok(new Token({ value: result.data })); - } - - private static validate(token: string) { - const schema = z.string().min(1, { message: "Invalid token string" }); - return schema.safeParse(token); - } - - getValue() { - return this.props.value; - } - - toString() { - return this.props.value; - } - - toPrimitive() { - return this.props.value; - } -} diff --git a/apps/server/archive/contexts/auth/domain/value-objects/username.ts b/apps/server/archive/contexts/auth/domain/value-objects/username.ts deleted file mode 100644 index 072e9b4c..00000000 --- a/apps/server/archive/contexts/auth/domain/value-objects/username.ts +++ /dev/null @@ -1,41 +0,0 @@ -import { ValueObject } from "@repo/rdx-ddd"; -import { Result } from "@repo/rdx-utils"; -import * as z from "zod/v4"; - -interface UsernameProps { - value: string; -} - -export class Username extends ValueObject { - static create(username: string): Result { - const result = Username.validate(username); - - return result.success - ? Result.ok(new Username({ value: result.data })) - : Result.fail(new Error(result.error.errors[0].message)); - } - - private static validate(username: string) { - const schema = z - .string() - .min(3, { message: "Username must be at least 3 characters long" }) - .max(30, { message: "Username cannot exceed 30 characters" }) - .regex(/^[a-zA-Z0-9_]+$/, { - message: "Username can only contain letters, numbers, and underscores", - }); - - return schema.safeParse(username); - } - - getValue() { - return this.props.value; - } - - toString() { - return this.props.value; - } - - toPrimitive() { - return this.props.value; - } -} diff --git a/apps/server/archive/contexts/auth/infraestructure/express/types.ts b/apps/server/archive/contexts/auth/infraestructure/express/types.ts deleted file mode 100644 index 1b7a6ff6..00000000 --- a/apps/server/archive/contexts/auth/infraestructure/express/types.ts +++ /dev/null @@ -1,11 +0,0 @@ -import type { Request } from "express"; - -import type { AuthenticatedUser, TabContext } from "../../domain"; - -export interface TabContextRequest extends Request { - tabContext?: TabContext; -} - -export interface AuthenticatedRequest extends Request { - user?: AuthenticatedUser; -} diff --git a/apps/server/archive/contexts/auth/infraestructure/index.ts b/apps/server/archive/contexts/auth/infraestructure/index.ts deleted file mode 100644 index 7e7c2a62..00000000 --- a/apps/server/archive/contexts/auth/infraestructure/index.ts +++ /dev/null @@ -1,4 +0,0 @@ -export * from "../../../../../../modules/auth/src/api/lib/passport"; -export * from "./mappers"; -export * from "./middleware"; -export * from "./sequelize"; diff --git a/apps/server/archive/contexts/auth/infraestructure/mappers/authenticated-user.mapper.ts b/apps/server/archive/contexts/auth/infraestructure/mappers/authenticated-user.mapper.ts deleted file mode 100644 index 4ab87ae2..00000000 --- a/apps/server/archive/contexts/auth/infraestructure/mappers/authenticated-user.mapper.ts +++ /dev/null @@ -1,69 +0,0 @@ -import { - EmailAddress, - ISequelizeMapper, - MapperParamsType, - Result, - SequelizeMapper, - UniqueID, -} from "@/core"; -import { AuthUserCreationAttributes, AuthUserModel } from '../sequelize'; -import { AuthenticatedUser, HashPassword, Username } from '../../domain'; - -export interface IAuthenticatedUserMapper - extends ISequelizeMapper {} - -export class AuthenticatedUserMapper - extends SequelizeMapper - implements IAuthenticatedUserMapper -{ - public mapToDomain( - source: AuthUserModel, - params?: MapperParamsType - ): Result { - // Crear Value Objects asegurando que sean v谩lidos - const uniqueIdResult = UniqueID.create(source.id); - const usernameResult = Username.create(source.username); - const passwordHashResult = HashPassword.createFromHash(source.hash_password); - const emailResult = EmailAddress.create(source.email); - - // Validar que no haya errores en la creaci贸n de los Value Objects - const okOrError = Result.combine([ - uniqueIdResult, - usernameResult, - passwordHashResult, - emailResult, - ]); - if (okOrError.isFailure) { - return Result.fail(okOrError.error.message); - } - - // Crear el agregado de dominio - return AuthenticatedUser.create( - { - username: usernameResult.data!, - email: emailResult.data!, - hashPassword: passwordHashResult.data!, - roles: source.roles || [], - }, - uniqueIdResult.data! - ); - } - - public mapToPersistence( - source: AuthenticatedUser, - params?: MapperParamsType - ): AuthUserCreationAttributes { - return { - id: source.id.toString(), - username: source.username.toString(), - email: source.email.toString(), - hash_password: source.hashPassword.toString(), - roles: source.getRoles().map((role) => role.toString()), - //access_token: source.accessToken, - //refresh_token: source.refreshToken, - }; - } -} - -const authenticatedUserMapper: IAuthenticatedUserMapper = new AuthenticatedUserMapper(); -export { authenticatedUserMapper }; diff --git a/apps/server/archive/contexts/auth/infraestructure/mappers/index.ts b/apps/server/archive/contexts/auth/infraestructure/mappers/index.ts deleted file mode 100644 index fcc87a1f..00000000 --- a/apps/server/archive/contexts/auth/infraestructure/mappers/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -export * from "./authenticated-user.mapper"; -export * from "./tab-context.mapper"; -export * from "./user.mapper"; diff --git a/apps/server/archive/contexts/auth/infraestructure/mappers/tab-context.mapper.ts b/apps/server/archive/contexts/auth/infraestructure/mappers/tab-context.mapper.ts deleted file mode 100644 index add6fd2f..00000000 --- a/apps/server/archive/contexts/auth/infraestructure/mappers/tab-context.mapper.ts +++ /dev/null @@ -1,66 +0,0 @@ -import { UniqueID } from "@/core/common/domain"; -import { - type ISequelizeMapper, - type MapperParamsType, - SequelizeMapper, -} from "@/core/common/infrastructure"; -import { Result } from "@repo/rdx-utils"; -import { TabContext } from "../../domain"; -import { TabContextCreationAttributes, TabContextModel } from "../sequelize"; - -export interface ITabContextMapper - extends ISequelizeMapper {} - -export class TabContextMapper - extends SequelizeMapper - implements ITabContextMapper -{ - public mapToDomain( - source: TabContextModel, - params?: MapperParamsType - ): Result { - // Crear Value Objects asegurando que sean v谩lidos - const uniqueIdResult = UniqueID.create(source.id); - const tabIdResult = UniqueID.create(source.tab_id); - const userIdResult = UniqueID.create(source.user_id); - //const companyIdResult = UniqueID.create(entity.company_id, false); - //const brachIdResult = UniqueID.create(entity.branch_id, false); - - // Validar que no haya errores en la creaci贸n de los Value Objects - const okOrError = Result.combine([ - uniqueIdResult, - tabIdResult, - userIdResult, - //companyIdResult, - //brachIdResult, - ]); - if (okOrError.isFailure) { - return Result.fail(okOrError.error.message); - } - - // Crear el agregado de dominio - return TabContext.create( - { - tabId: tabIdResult.data!, - userId: userIdResult.data!, - //companyId: companyIdResult.data, - //branchId: brachIdResult.data, - }, - uniqueIdResult.data! - ); - } - - public mapToPersistence( - source: TabContext, - params?: MapperParamsType - ): TabContextCreationAttributes { - return { - id: source.id.toString(), - tab_id: source.tabId.toString(), - user_id: source.userId.toString(), - }; - } -} - -const tabContextMapper: ITabContextMapper = new TabContextMapper(); -export { tabContextMapper }; diff --git a/apps/server/archive/contexts/auth/infraestructure/mappers/user.mapper.ts b/apps/server/archive/contexts/auth/infraestructure/mappers/user.mapper.ts deleted file mode 100644 index 82e798b0..00000000 --- a/apps/server/archive/contexts/auth/infraestructure/mappers/user.mapper.ts +++ /dev/null @@ -1,52 +0,0 @@ -import { EmailAddress, UniqueID } from "@/core/common/domain"; -import { - type ISequelizeMapper, - type MapperParamsType, - SequelizeMapper, -} from "@/core/common/infrastructure/sequelize/sequelize-mapper"; -import { Result } from "@repo/rdx-utils"; -import { User, Username } from "../../domain"; -import { UserCreationAttributes, UserModel } from "../sequelize"; - -export interface IUserMapper extends ISequelizeMapper {} - -class UserMapper - extends SequelizeMapper - implements IUserMapper -{ - public mapToDomain(source: UserModel, params?: MapperParamsType): Result { - // Crear Value Objects asegurando que sean v谩lidos - const uniqueIdResult = UniqueID.create(source.id); - const usernameResult = Username.create(source.username); - const emailResult = EmailAddress.create(source.email); - - // Validar que no haya errores en la creaci贸n de los Value Objects - const okOrError = Result.combine([uniqueIdResult, usernameResult, emailResult]); - if (okOrError.isFailure) { - return Result.fail(okOrError.error.message); - } - - // Crear el agregado de dominio - return User.create( - { - username: usernameResult.data!, - email: emailResult.data!, - roles: [], - //roles: entity.roles || [], - }, - uniqueIdResult.data! - ); - } - - public mapToPersistence(source: User, params?: MapperParamsType): UserCreationAttributes { - return { - id: source.id.toString(), - username: source.username.toString(), - email: source.email.toString(), - //roles: source.getRoles().map((role) => role.toString()), - }; - } -} - -const userMapper: IUserMapper = new UserMapper(); -export { userMapper }; diff --git a/apps/server/archive/contexts/auth/infraestructure/middleware/index.ts b/apps/server/archive/contexts/auth/infraestructure/middleware/index.ts deleted file mode 100644 index 5ce1bf32..00000000 --- a/apps/server/archive/contexts/auth/infraestructure/middleware/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from "./passport-auth.middleware"; -export * from "./tab-context.middleware"; diff --git a/apps/server/archive/contexts/auth/infraestructure/middleware/passport-auth.middleware.ts b/apps/server/archive/contexts/auth/infraestructure/middleware/passport-auth.middleware.ts deleted file mode 100644 index 1342c9e8..00000000 --- a/apps/server/archive/contexts/auth/infraestructure/middleware/passport-auth.middleware.ts +++ /dev/null @@ -1,72 +0,0 @@ -//import { authProvider } from "@/contexts/auth/infraestructure"; -import type { NextFunction, Response } from "express"; - -import { UniqueID } from "@/core/common/domain"; -import { ApiError, ExpressController } from "@/core/common/presentation"; - -import { authProvider } from "../../../../../../../modules/auth/src/api/lib/passport"; -import type { AuthenticatedUser } from "../../domain"; -import type { AuthenticatedRequest } from "../express/types"; - -// Comprueba el rol del usuario -const _authorizeUser = (condition: (user: AuthenticatedUser) => boolean) => { - return (req: AuthenticatedRequest, res: Response, next: NextFunction) => { - const user = req.user as AuthenticatedUser; - - if (!(user && condition(user))) { - return ExpressController.errorResponse( - new ApiError({ - status: 401, - title: "Unauthorized", - detail: "You are not authorized to access this resource.", - }), - res - ); - } - - return next(); - }; -}; - -// Verifica que el usuario est茅 autenticado -export const checkUser = [ - authProvider.authenticateJWT(), - _authorizeUser((user) => true /*user.isUser*/), -]; - -// Verifica que el usuario sea administrador -export const checkUserIsAdmin = [ - authProvider.authenticateJWT(), - _authorizeUser((user) => true /*user.isAdmin*/), -]; - -// Middleware para verificar que el usuario sea administrador o el due帽o de los datos (self) -export const checkUserIsAdminOrOwner = [ - (req: AuthenticatedRequest, res: Response, next: NextFunction) => { - const user = req.user as AuthenticatedUser; - const { userId } = req.params; - - // Si el usuario es admin, est谩 autorizado - if (user.isAdmin) { - return next(); - } - - // Si el usuario es s铆 mismo - if (user.isUser && userId) { - const paramIdOrError = UniqueID.create(userId); - if (paramIdOrError.isSuccess && user.id.equals(paramIdOrError.data)) { - return next(); - } - } - - return ExpressController.errorResponse( - new ApiError({ - status: 401, - title: "Unauthorized", - detail: "You are not authorized to access this resource.", - }), - req, - res - ); - }, -]; diff --git a/apps/server/archive/contexts/auth/infraestructure/middleware/tab-context.middleware.ts b/apps/server/archive/contexts/auth/infraestructure/middleware/tab-context.middleware.ts deleted file mode 100644 index 2642ce61..00000000 --- a/apps/server/archive/contexts/auth/infraestructure/middleware/tab-context.middleware.ts +++ /dev/null @@ -1,3 +0,0 @@ -import { authProvider } from "../../../../../../../modules/auth/src/api/lib/passport"; - -export const checkTabContext = [authProvider.authenticateTabId()]; diff --git a/apps/server/archive/contexts/auth/infraestructure/sequelize/auth-user.model.ts b/apps/server/archive/contexts/auth/infraestructure/sequelize/auth-user.model.ts deleted file mode 100644 index 8c4c0eef..00000000 --- a/apps/server/archive/contexts/auth/infraestructure/sequelize/auth-user.model.ts +++ /dev/null @@ -1,74 +0,0 @@ -import { DataTypes, InferAttributes, InferCreationAttributes, Model, Sequelize } from "sequelize"; - -export type AuthUserCreationAttributes = InferCreationAttributes; - -export class AuthUserModel extends Model< - InferAttributes, - InferCreationAttributes -> { - // To avoid table creation - /*static async sync(): Promise { - return Promise.resolve(); - }*/ - - declare id: string; - declare username: string; - declare email: string; - declare hash_password: string; - declare roles: string[]; -} - -export default (sequelize: Sequelize) => { - AuthUserModel.init( - { - id: { - type: DataTypes.UUID, - primaryKey: true, - }, - username: { - type: DataTypes.STRING, - allowNull: false, - }, - email: { - type: DataTypes.STRING, - allowNull: false, - }, - hash_password: { - type: DataTypes.STRING, - allowNull: false, - }, - roles: { - type: DataTypes.STRING, - allowNull: false, - defaultValue: "USER", - get(this: AuthUserModel): string[] { - const rawValue = this.getDataValue("roles") as any; - return String(rawValue).split(";"); - }, - set(this: AuthUserModel, value: string[]) { - const rawValue = value.join(";") as any; - this.setDataValue("roles", rawValue); - }, - }, - }, - { - sequelize, - tableName: "users", - paranoid: true, // softs deletes - timestamps: true, - - createdAt: "created_at", - updatedAt: "updated_at", - deletedAt: "deleted_at", - - indexes: [{ name: "email_idx", fields: ["email"], unique: true }], - - whereMergeStrategy: "and", // <- c贸mo tratar el merge de un scope - - defaultScope: {}, - - scopes: {}, - } - ); - return AuthUserModel; -}; diff --git a/apps/server/archive/contexts/auth/infraestructure/sequelize/authenticated-user.repository.ts b/apps/server/archive/contexts/auth/infraestructure/sequelize/authenticated-user.repository.ts deleted file mode 100644 index b79b7ab3..00000000 --- a/apps/server/archive/contexts/auth/infraestructure/sequelize/authenticated-user.repository.ts +++ /dev/null @@ -1,86 +0,0 @@ -import { EmailAddress } from "@/core/common/domain"; -import { SequelizeRepository } from "@/core/common/infrastructure"; -import { Result } from "@repo/rdx-utils"; -import { Sequelize, Transaction } from "sequelize"; -import { AuthenticatedUser, IAuthenticatedUserRepository, Username } from "../../domain"; -import { IAuthenticatedUserMapper } from "../mappers"; -import { AuthUserModel } from "./auth-user.model"; - -export class AuthenticatedUserRepository - extends SequelizeRepository - implements IAuthenticatedUserRepository -{ - private readonly _mapper!: IAuthenticatedUserMapper; - - /** - * 馃敼 Funci贸n personalizada para mapear errores de unicidad en autenticaci贸n - */ - private _customErrorMapper(error: Error): string | null { - if (error.name === "SequelizeUniqueConstraintError") { - return "User with this email or username already exists"; - } - - return null; - } - - constructor(database: Sequelize, mapper: IAuthenticatedUserMapper) { - super(database); - this._mapper = mapper; - } - - async userExists( - username: Username, - email: EmailAddress, - transaction?: Transaction - ): Promise> { - try { - const userWithEmail = await this._findById( - AuthUserModel, - "email", - email.toString(), - transaction - ); - - const userWithUsername = await this._findById( - AuthUserModel, - "username", - username.toString(), - transaction - ); - - return Result.ok(Boolean(userWithEmail || userWithUsername)); - } catch (error: unknown) { - return this._handleDatabaseError(error, this._customErrorMapper); - } - } - - async getUserByEmail( - email: EmailAddress, - transaction?: Transaction - ): Promise> { - try { - const rawUser = await this._getBy(AuthUserModel, "email", email.toString(), {}, transaction); - - if (!rawUser === true) { - return Result.fail(new Error("User with email not exists")); - } - - return this._mapper.mapToDomain(rawUser); - } catch (error: unknown) { - return this._handleDatabaseError(error, this._customErrorMapper); - } - } - - async createUser( - user: AuthenticatedUser, - transaction?: Transaction - ): Promise> { - try { - const persistenceData = this._mapper.mapToPersistence(user); - await AuthUserModel.create(persistenceData, { transaction }); - return Result.ok(); - } catch (error: unknown) { - return this._handleDatabaseError(error, this._customErrorMapper); - } - } -} diff --git a/apps/server/archive/contexts/auth/infraestructure/sequelize/index.ts b/apps/server/archive/contexts/auth/infraestructure/sequelize/index.ts deleted file mode 100644 index a1153680..00000000 --- a/apps/server/archive/contexts/auth/infraestructure/sequelize/index.ts +++ /dev/null @@ -1,8 +0,0 @@ -export * from "./auth-user.model"; -export * from "./authenticated-user.repository"; - -export * from "./tab-context.model"; -export * from "./tab-context.repository"; - -export * from "./user.model"; -export * from "./user.repository"; diff --git a/apps/server/archive/contexts/auth/infraestructure/sequelize/tab-context.model.ts b/apps/server/archive/contexts/auth/infraestructure/sequelize/tab-context.model.ts deleted file mode 100644 index c6e9dd4c..00000000 --- a/apps/server/archive/contexts/auth/infraestructure/sequelize/tab-context.model.ts +++ /dev/null @@ -1,58 +0,0 @@ -import { DataTypes, InferAttributes, InferCreationAttributes, Model, Sequelize } from "sequelize"; - -export type TabContextCreationAttributes = InferCreationAttributes; - -export class TabContextModel extends Model< - InferAttributes, - InferCreationAttributes -> { - // To avoid table creation - /*static async sync(): Promise { - return Promise.resolve(); - }*/ - static associate(connection: Sequelize) { - const { AuthUserModel } = connection.models; - } - - declare id: string; - declare tab_id: string; - declare user_id: string; -} - -export default (sequelize: Sequelize) => { - TabContextModel.init( - { - id: { - type: DataTypes.UUID, - primaryKey: true, - }, - user_id: { - type: DataTypes.UUID, - allowNull: false, - }, - tab_id: { - type: DataTypes.UUID, - allowNull: false, - }, - }, - { - sequelize, - tableName: "user_tab_contexts", - paranoid: true, // softs deletes - timestamps: true, - - createdAt: "created_at", - updatedAt: "updated_at", - deletedAt: "deleted_at", - - indexes: [{ name: "tab_id_idx", fields: ["tab_id"], unique: true }], - - whereMergeStrategy: "and", // <- c贸mo tratar el merge de un scope - - defaultScope: {}, - - scopes: {}, - } - ); - return TabContextModel; -}; diff --git a/apps/server/archive/contexts/auth/infraestructure/sequelize/tab-context.repository.ts b/apps/server/archive/contexts/auth/infraestructure/sequelize/tab-context.repository.ts deleted file mode 100644 index 5dc885cd..00000000 --- a/apps/server/archive/contexts/auth/infraestructure/sequelize/tab-context.repository.ts +++ /dev/null @@ -1,125 +0,0 @@ -import { UniqueID } from "@/core/common/domain"; -import { SequelizeRepository } from "@/core/common/infrastructure"; -import { Result } from "@repo/rdx-utils"; -import { Op, Sequelize, Transaction } from "sequelize"; -import { ITabContextRepository, TabContext } from "../../domain/"; -import { ITabContextMapper } from "../mappers"; -import { TabContextModel } from "./tab-context.model"; - -export class TabContextRepository - extends SequelizeRepository - implements ITabContextRepository -{ - private readonly _mapper!: ITabContextMapper; - - /** - * 馃敼 Funci贸n personalizada para mapear errores de unicidad en autenticaci贸n - */ - private _customErrorMapper(error: Error): string | null { - if (error.name === "SequelizeUniqueConstraintError") { - return "Tab context already exists"; - } - - return null; - } - - constructor(database: Sequelize, mapper: ITabContextMapper) { - super(database); - this._mapper = mapper; - } - - async getContextByTabId( - tabId: UniqueID, - transaction?: Transaction - ): Promise> { - try { - const rawContext = await this._getBy( - TabContextModel, - "tab_id", - tabId.toString(), - {}, - transaction - ); - - if (!rawContext === true) { - return Result.fail(new Error("Tab context not exists")); - } - - return this._mapper.mapToDomain(rawContext); - } catch (error: unknown) { - return this._handleDatabaseError(error, this._customErrorMapper); - } - } - - async contextExistsByTabId( - tabId: UniqueID, - transaction?: Transaction - ): Promise> { - try { - const result = await this._exists(TabContextModel, "tab_id", tabId.toString(), transaction); - - return Result.ok(Boolean(result)); - } catch (error: unknown) { - return this._handleDatabaseError(error, this._customErrorMapper); - } - } - - /** - * Registra un contexto para un tab id o actualiza si ya existe - * @param context - * @param transaction - * @returns - */ - - async registerContextByTabId( - context: TabContext, - transaction?: Transaction - ): Promise> { - try { - const { userId, tabId } = context; - const persistenceData = this._mapper.mapToPersistence(context); - - // Si existe el contexto de ese tabId, lo actualizo. - - if (await this._exists(TabContextModel, "tab_id", tabId.toString())) { - await TabContextModel.update(persistenceData, { - where: { [Op.and]: [{ tab_id: tabId.toString() }, { user_id: userId.toString() }] }, - transaction, - }); - } else { - await TabContextModel.create(persistenceData, { - include: [{ all: true }], - transaction, - }); - } - - return Result.ok(); - } catch (error: unknown) { - return this._handleDatabaseError(error, this._customErrorMapper); - } - } - - /** - * Desregistra un contexto para un tab id o actualiza si ya existe - * @param context - * @param transaction - * @returns - */ - - async unregisterContextByTabId( - context: TabContext, - transaction?: Transaction - ): Promise> { - try { - const { userId, tabId } = context; - - await TabContextModel.destroy({ - where: { [Op.and]: [{ tab_id: tabId.toString() }, { user_id: userId.toString() }] }, - transaction, - }); - return Result.ok(); - } catch (error: unknown) { - return this._handleDatabaseError(error, this._customErrorMapper); - } - } -} diff --git a/apps/server/archive/contexts/auth/infraestructure/sequelize/user.model.ts b/apps/server/archive/contexts/auth/infraestructure/sequelize/user.model.ts deleted file mode 100644 index a15e58a4..00000000 --- a/apps/server/archive/contexts/auth/infraestructure/sequelize/user.model.ts +++ /dev/null @@ -1,55 +0,0 @@ -import { DataTypes, InferAttributes, InferCreationAttributes, Model, Sequelize } from "sequelize"; - -export type UserCreationAttributes = InferCreationAttributes; - -export class UserModel extends Model< - InferAttributes, - InferCreationAttributes -> { - // To avoid table creation - /*static async sync(): Promise { - return Promise.resolve(); - }*/ - - declare id: string; - declare username: string; - declare email: string; -} - -export default (sequelize: Sequelize) => { - UserModel.init( - { - id: { - type: DataTypes.UUID, - primaryKey: true, - }, - username: { - type: DataTypes.STRING, - allowNull: false, - }, - email: { - type: DataTypes.STRING, - allowNull: false, - }, - }, - { - sequelize, - tableName: "users", - paranoid: true, // softs deletes - timestamps: true, - - createdAt: "created_at", - updatedAt: "updated_at", - deletedAt: "deleted_at", - - indexes: [{ name: "email_idx", fields: ["email"], unique: true }], - - whereMergeStrategy: "and", // <- c贸mo tratar el merge de un scope - - defaultScope: {}, - - scopes: {}, - } - ); - return UserModel; -}; diff --git a/apps/server/archive/contexts/auth/infraestructure/sequelize/user.repository.ts b/apps/server/archive/contexts/auth/infraestructure/sequelize/user.repository.ts deleted file mode 100644 index 3ac3134d..00000000 --- a/apps/server/archive/contexts/auth/infraestructure/sequelize/user.repository.ts +++ /dev/null @@ -1,69 +0,0 @@ -import { EmailAddress, UniqueID } from "@/core/common/domain"; -import { SequelizeRepository } from "@/core/common/infrastructure"; -import { Collection, Result } from "@repo/rdx-utils"; -import { Sequelize, Transaction } from "sequelize"; -import { IUserRepository, User } from "../../domain"; -import { IUserMapper } from "../mappers"; -import { UserModel } from "./user.model"; - -export class UserRepository extends SequelizeRepository implements IUserRepository { - private readonly _mapper!: IUserMapper; - - /** - * 馃敼 Funci贸n personalizada para mapear errores de unicidad en autenticaci贸n - */ - private _customErrorMapper(error: Error): string | null { - if (error.name === "SequelizeUniqueConstraintError") { - return "User with this email or username already exists"; - } - - return null; - } - - constructor(database: Sequelize, mapper: IUserMapper) { - super(database); - this._mapper = mapper; - } - - async findAll(transaction?: Transaction): Promise, Error>> { - try { - const rawUsers = await this._findAll(UserModel, {}, transaction); - - if (!rawUsers === true) { - return Result.fail(new Error("User with email not exists")); - } - - return this._mapper.mapArrayToDomain(rawUsers); - } catch (error: unknown) { - return this._handleDatabaseError(error, this._customErrorMapper); - } - } - - async findById(id: UniqueID, transaction?: Transaction): Promise> { - try { - const rawUser = await this._getById(UserModel, id, {}, transaction); - - if (!rawUser === true) { - return Result.fail(new Error(`User with id ${id.toString()} not exists`)); - } - - return this._mapper.mapToDomain(rawUser); - } catch (error: unknown) { - return this._handleDatabaseError(error, this._customErrorMapper); - } - } - - async findByEmail(email: EmailAddress, transaction?: Transaction): Promise> { - try { - const rawUser = await this._getBy(UserModel, "email", email.toString(), {}, transaction); - - if (!rawUser === true) { - return Result.fail(new Error(`User with email ${email.toString()} not exists`)); - } - - return this._mapper.mapToDomain(rawUser); - } catch (error: unknown) { - return this._handleDatabaseError(error, this._customErrorMapper); - } - } -} diff --git a/apps/server/archive/contexts/auth/presentation/controllers/index.ts b/apps/server/archive/contexts/auth/presentation/controllers/index.ts deleted file mode 100644 index 644a8bb1..00000000 --- a/apps/server/archive/contexts/auth/presentation/controllers/index.ts +++ /dev/null @@ -1,5 +0,0 @@ -export * from "./listUsers"; -export * from "./login"; -export * from "./logout"; -export * from "./refreshToken"; -export * from "./register"; diff --git a/apps/server/archive/contexts/auth/presentation/controllers/listUsers/index.ts b/apps/server/archive/contexts/auth/presentation/controllers/listUsers/index.ts deleted file mode 100644 index 12eccffb..00000000 --- a/apps/server/archive/contexts/auth/presentation/controllers/listUsers/index.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { ListUsersUseCase } from "@/contexts/auth/application/list-users/list-users.use-case"; -import { userRepository } from "@/contexts/auth/infraestructure"; -import { SequelizeTransactionManager } from "@/core/common/infrastructure"; -import { UserService } from "../../domain/services/user.service"; -import { ListUsersController } from "./list-users.controller"; -import { listUsersPresenter } from "./list-users.presenter"; - -export const buildListUsersController = () => { - const transactionManager = new SequelizeTransactionManager(); - const userService = new UserService(userRepository); - - const useCase = new ListUsersUseCase(userService, transactionManager); - const presenter = listUsersPresenter; - - return new ListUsersController(useCase, presenter); -}; diff --git a/apps/server/archive/contexts/auth/presentation/controllers/listUsers/list-users.controller.ts b/apps/server/archive/contexts/auth/presentation/controllers/listUsers/list-users.controller.ts deleted file mode 100644 index d6e727f3..00000000 --- a/apps/server/archive/contexts/auth/presentation/controllers/listUsers/list-users.controller.ts +++ /dev/null @@ -1,37 +0,0 @@ -import { ListUsersUseCase } from "@/contexts/auth/application"; -import { ExpressController } from "@/core/common/presentation"; -import { IListUsersPresenter } from "./list-users.presenter"; - -export class ListUsersController extends ExpressController { - public constructor( - private readonly listUsers: ListUsersUseCase, - private readonly presenter: IListUsersPresenter - ) { - super(); - } - - protected async executeImpl() { - const usersOrError = await this.listUsers.execute(); - - if (usersOrError.isFailure) { - return this.handleError(usersOrError.error); - } - - return this.ok(this.presenter.toDTO(usersOrError.data)); - } - - private handleError(error: Error) { - const message = error.message; - - if ( - message.includes("Database connection lost") || - message.includes("Database request timed out") - ) { - return this.unavailableError( - "Database service is currently unavailable. Please try again later." - ); - } - - return this.conflictError(message); - } -} diff --git a/apps/server/archive/contexts/auth/presentation/controllers/listUsers/list-users.presenter.ts b/apps/server/archive/contexts/auth/presentation/controllers/listUsers/list-users.presenter.ts deleted file mode 100644 index b26d8362..00000000 --- a/apps/server/archive/contexts/auth/presentation/controllers/listUsers/list-users.presenter.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { Collection, ensureString } from "@repo/rdx-utils"; -import { User } from "../../domain"; -import { IListUsersResponseDTO } from "../../dto"; - -export interface IListUsersPresenter { - toDTO: (users: Collection) => IListUsersResponseDTO[]; -} - -export const listUsersPresenter: IListUsersPresenter = { - toDTO: (users: Collection): IListUsersResponseDTO[] => - users.map((user) => ({ - id: ensureString(user.id.toString()), - email: ensureString(user.email.toString()), - username: ensureString(user.username.toString()), - })), -}; diff --git a/apps/server/archive/contexts/auth/presentation/controllers/login/index.ts b/apps/server/archive/contexts/auth/presentation/controllers/login/index.ts deleted file mode 100644 index 9682039d..00000000 --- a/apps/server/archive/contexts/auth/presentation/controllers/login/index.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { LoginUseCase } from "@/contexts/auth/application"; -import { authenticatedUserRepository, tabContextRepository } from "@/contexts/auth/infraestructure"; -import { SequelizeTransactionManager } from "@/core/common/infrastructure"; -import { AuthService } from "../../domain/services"; -import { LoginController } from "./login.controller"; -import { loginPresenter } from "./login.presenter"; - -export const buildLoginController = () => { - const transactionManager = new SequelizeTransactionManager(); - const authService = new AuthService(authenticatedUserRepository, tabContextRepository); - - const useCase = new LoginUseCase(authService, transactionManager); - const presenter = loginPresenter; - - return new LoginController(useCase, presenter); -}; diff --git a/apps/server/archive/contexts/auth/presentation/controllers/login/login.controller.ts b/apps/server/archive/contexts/auth/presentation/controllers/login/login.controller.ts deleted file mode 100644 index d910b4e6..00000000 --- a/apps/server/archive/contexts/auth/presentation/controllers/login/login.controller.ts +++ /dev/null @@ -1,48 +0,0 @@ -import { LoginUseCase } from "@/contexts/auth/application"; -import { ExpressController } from "@/core/common/presentation"; -import { LoginData } from "../../domain"; -import { ILoginPresenter } from "./login.presenter"; - -export class LoginController extends ExpressController { - public constructor( - private readonly login: LoginUseCase, - private readonly presenter: ILoginPresenter - ) { - super(); - } - - async executeImpl() { - const loginDataOrError = LoginData.createFromPrimitives({ - email: this.req.body.email, - plainPassword: this.req.body.password, - tabId: String(this.req.headers["x-tab-id"]), - }); - - if (loginDataOrError.isFailure) { - return this.clientError("Invalid input data", loginDataOrError.error); - } - - const loginResultOrError = await this.login.execute(loginDataOrError.data); - - if (loginResultOrError.isFailure) { - return this.handleError(loginResultOrError.error); - } - - return this.ok(this.presenter.toDTO(loginResultOrError.data)); - } - - private handleError(error: Error) { - const message = error.message; - - if ( - message.includes("Database connection lost") || - message.includes("Database request timed out") - ) { - return this.unavailableError( - "Database service is currently unavailable. Please try again later." - ); - } - - return this.unauthorizedError(message); - } -} diff --git a/apps/server/archive/contexts/auth/presentation/controllers/login/login.presenter.ts b/apps/server/archive/contexts/auth/presentation/controllers/login/login.presenter.ts deleted file mode 100644 index 51be28df..00000000 --- a/apps/server/archive/contexts/auth/presentation/controllers/login/login.presenter.ts +++ /dev/null @@ -1,56 +0,0 @@ -import { AuthenticatedUser, TabContext, Token } from "../../domain"; -import { ILoginUserResponseDTO } from "../../dto"; - -export interface ILoginPresenter { - toDTO: (data: { - user: AuthenticatedUser; - tabContext: TabContext; - tokens: { - accessToken: Token; - refreshToken: Token; - }; - }) => ILoginUserResponseDTO; -} - -export const loginPresenter: ILoginPresenter = { - toDTO: (data: { - user: AuthenticatedUser; - tabContext: TabContext; - tokens: { - accessToken: Token; - refreshToken: Token; - }; - }): ILoginUserResponseDTO => { - const { - user, - tabContext, - tokens: { accessToken, refreshToken }, - } = data; - - const userData = { - id: user.id.toString(), - username: user.username.toString(), - email: user.email.toString(), - //roles: user.getRoles().map((role) => role.toString()), - }; - - const tabContextData = { - id: tabContext.id.toString(), - tab_id: tabContext.tabId.toString(), - user_id: tabContext.userId.toString(), - }; - - return { - user: { - id: userData.id, - email: userData.email, - username: userData.username, - tab_id: tabContextData.tab_id, - }, - tokens: { - access_token: accessToken.toString(), - refresh_token: refreshToken.toString(), - }, - }; - }, -}; diff --git a/apps/server/archive/contexts/auth/presentation/controllers/logout/index.ts b/apps/server/archive/contexts/auth/presentation/controllers/logout/index.ts deleted file mode 100644 index 6c91a987..00000000 --- a/apps/server/archive/contexts/auth/presentation/controllers/logout/index.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { LogoutUseCase } from "@/contexts/auth/application"; -import { authenticatedUserRepository, tabContextRepository } from "@/contexts/auth/infraestructure"; -import { SequelizeTransactionManager } from "@/core/common/infrastructure"; -import { AuthService } from "../../domain/services"; -import { LogoutController } from "./logout.controller"; - -export const buildLogoutController = () => { - const transactionManager = new SequelizeTransactionManager(); - const authService = new AuthService(authenticatedUserRepository, tabContextRepository); - - const useCase = new LogoutUseCase(authService, transactionManager); - - return new LogoutController(useCase); -}; diff --git a/apps/server/archive/contexts/auth/presentation/controllers/logout/logout.controller.ts b/apps/server/archive/contexts/auth/presentation/controllers/logout/logout.controller.ts deleted file mode 100644 index 457bd327..00000000 --- a/apps/server/archive/contexts/auth/presentation/controllers/logout/logout.controller.ts +++ /dev/null @@ -1,49 +0,0 @@ -import { LogoutUseCase } from "@/contexts/auth/application/logout"; -import { TabContextRequest } from "@/contexts/auth/infraestructure/express/types"; -import { ExpressController } from "@/core/common/presentation"; -import { AuthenticatedUser, LogoutData, TabContext } from "../../domain"; - -export class LogoutController extends ExpressController { - public constructor(private readonly logout: LogoutUseCase) { - super(); - } - - async executeImpl() { - const user = this.req.user as AuthenticatedUser; - const tabContext = (this.req as TabContextRequest).tabContext as TabContext; - - const logoutDataOrError = LogoutData.create({ - email: user.email, - tabId: tabContext.tabId, - }); - - if (logoutDataOrError.isFailure) { - return this.clientError("Invalid input data", logoutDataOrError.error); - } - - const logoutOrError = await this.logout.execute(logoutDataOrError.data); - - if (logoutOrError.isFailure) { - return this.handleError(logoutOrError.error); - } - - // Habr铆a que invalidar el token del cliente - - return this.ok(); - } - - private handleError(error: Error) { - const message = error.message; - - if ( - message.includes("Database connection lost") || - message.includes("Database request timed out") - ) { - return this.unavailableError( - "Database service is currently unavailable. Please try again later." - ); - } - - return this.clientError(message); - } -} diff --git a/apps/server/archive/contexts/auth/presentation/controllers/refreshToken/index.ts b/apps/server/archive/contexts/auth/presentation/controllers/refreshToken/index.ts deleted file mode 100644 index 8e82b291..00000000 --- a/apps/server/archive/contexts/auth/presentation/controllers/refreshToken/index.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { RefreshTokenUseCase } from "@/contexts/auth/application"; -import { authenticatedUserRepository, tabContextRepository } from "@/contexts/auth/infraestructure"; -import { SequelizeTransactionManager } from "@/core/common/infrastructure"; -import { AuthService } from "../../domain/services"; -import { RefreshTokenController } from "./refresh-token.controller"; -import { refreshTokenPresenter } from "./refresh-token.presenter"; - -export const buildRefreshTokenController = () => { - const transactionManager = new SequelizeTransactionManager(); - const authService = new AuthService(authenticatedUserRepository, tabContextRepository); - - const useCase = new RefreshTokenUseCase(authService, transactionManager); - const presenter = refreshTokenPresenter; - - return new RefreshTokenController(useCase, presenter); -}; diff --git a/apps/server/archive/contexts/auth/presentation/controllers/refreshToken/refresh-token.controller.ts b/apps/server/archive/contexts/auth/presentation/controllers/refreshToken/refresh-token.controller.ts deleted file mode 100644 index 8c3357a4..00000000 --- a/apps/server/archive/contexts/auth/presentation/controllers/refreshToken/refresh-token.controller.ts +++ /dev/null @@ -1,45 +0,0 @@ -import { RefreshTokenUseCase } from "@/contexts/auth/application"; -import { ExpressController } from "@/core/common/presentation"; -import { Token } from "../../domain"; -import { IRefreshTokenPresenter } from "./refresh-token.presenter"; - -export class RefreshTokenController extends ExpressController { - public constructor( - private readonly refreshToken: RefreshTokenUseCase, - private readonly presenter: IRefreshTokenPresenter - ) { - super(); - } - - async executeImpl() { - //const tabId = String(this.req.headers["x-tab-id"]); - const refreshTokenOrError = Token.create(String(this.req.body.refresh_token)); - - if (refreshTokenOrError.isFailure) { - return this.clientError("Invalid input data", refreshTokenOrError.error); - } - - const newRefreshTokenOrError = await this.refreshToken.execute(refreshTokenOrError.data); - - if (newRefreshTokenOrError.isFailure) { - return this.handleError(newRefreshTokenOrError.error); - } - - return this.created(this.presenter.toDto(newRefreshTokenOrError.data)); - } - - private handleError(error: Error) { - const message = error.message; - - if ( - message.includes("Database connection lost") || - message.includes("Database request timed out") - ) { - return this.unavailableError( - "Database service is currently unavailable. Please try again later." - ); - } - - return this.internalServerError(message); - } -} diff --git a/apps/server/archive/contexts/auth/presentation/controllers/refreshToken/refresh-token.presenter.ts b/apps/server/archive/contexts/auth/presentation/controllers/refreshToken/refresh-token.presenter.ts deleted file mode 100644 index 59c2f9ef..00000000 --- a/apps/server/archive/contexts/auth/presentation/controllers/refreshToken/refresh-token.presenter.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { Token } from "../../domain"; -import { IRefreshTokenResponseDTO } from "../../dto"; - -export interface IRefreshTokenPresenter { - toDto: (refreshToken: Token) => IRefreshTokenResponseDTO; -} - -export const refreshTokenPresenter: IRefreshTokenPresenter = { - toDto: (refreshToken: Token): IRefreshTokenResponseDTO => { - return { - refresh_token: refreshToken.toString(), - }; - }, -}; diff --git a/apps/server/archive/contexts/auth/presentation/controllers/register/index.ts b/apps/server/archive/contexts/auth/presentation/controllers/register/index.ts deleted file mode 100644 index 472e54f0..00000000 --- a/apps/server/archive/contexts/auth/presentation/controllers/register/index.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { RegisterUseCase } from "@/contexts/auth/application/register"; -import { authenticatedUserRepository, tabContextRepository } from "@/contexts/auth/infraestructure"; -import { SequelizeTransactionManager } from "@/core/common/infrastructure"; -import { AuthService } from "../../domain/services"; -import { RegisterController } from "./register.controller"; -import { registerPresenter } from "./register.presenter"; - -export const buildRegisterController = () => { - const transactionManager = new SequelizeTransactionManager(); - const authService = new AuthService(authenticatedUserRepository, tabContextRepository); - - const useCase = new RegisterUseCase(authService, transactionManager); - const presenter = registerPresenter; - - return new RegisterController(useCase, presenter); -}; diff --git a/apps/server/archive/contexts/auth/presentation/controllers/register/register.controller.ts b/apps/server/archive/contexts/auth/presentation/controllers/register/register.controller.ts deleted file mode 100644 index c3c1ea6f..00000000 --- a/apps/server/archive/contexts/auth/presentation/controllers/register/register.controller.ts +++ /dev/null @@ -1,52 +0,0 @@ -import { RegisterUseCase } from "@/contexts/auth/application"; -import { ExpressController } from "@/core/common/presentation"; -import { RegisterData } from "../../domain"; -import { IRegisterPresenter } from "./register.presenter"; - -export class RegisterController extends ExpressController { - public constructor( - private readonly register: RegisterUseCase, - private readonly presenter: IRegisterPresenter - ) { - super(); - } - - async executeImpl() { - const registerDataOrError = RegisterData.createFromPrimitives({ - email: this.req.body.email, - username: this.req.body.username, - plainPassword: this.req.body.password, - }); - - if (registerDataOrError.isFailure) { - return this.clientError("Invalid input data", registerDataOrError.error); - } - - const userOrError = await this.register.execute(registerDataOrError.data); - - if (userOrError.isFailure) { - return this.handleError(userOrError.error); - } - - return this.created(this.presenter.toDto(userOrError.data)); - } - - private handleError(error: Error) { - const message = error.message; - - if (message.includes("User with this email or username already exists")) { - return this.conflictError(message); - } - - if ( - message.includes("Database connection lost") || - message.includes("Database request timed out") - ) { - return this.unavailableError( - "Database service is currently unavailable. Please try again later." - ); - } - - return this.internalServerError(message); - } -} diff --git a/apps/server/archive/contexts/auth/presentation/controllers/register/register.presenter.ts b/apps/server/archive/contexts/auth/presentation/controllers/register/register.presenter.ts deleted file mode 100644 index d5fa5adc..00000000 --- a/apps/server/archive/contexts/auth/presentation/controllers/register/register.presenter.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { AuthenticatedUser } from "../../domain"; -import { IRegisterUserResponseDTO } from "../../dto"; - -export interface IRegisterPresenter { - toDto: (user: AuthenticatedUser) => IRegisterUserResponseDTO; -} - -export const registerPresenter: IRegisterPresenter = { - toDto: (user: AuthenticatedUser): IRegisterUserResponseDTO => { - //const { user, token, refreshToken } = loginUser; - //const roles = user.getRoles()?.map((rol) => rol.toString()) || []; - - const userData = user.toPersistenceData(); - - return { - user_id: userData.id, - email: userData.email, - username: userData.username, - }; - }, -}; diff --git a/apps/server/archive/contexts/auth/presentation/dto/auth.request.dto.ts b/apps/server/archive/contexts/auth/presentation/dto/auth.request.dto.ts deleted file mode 100644 index c41713f5..00000000 --- a/apps/server/archive/contexts/auth/presentation/dto/auth.request.dto.ts +++ /dev/null @@ -1,10 +0,0 @@ -export interface IRegisterUserRequestDTO { - username: string; - email: string; - password: string; -} - -export interface ILoginUserRequestDTO { - email: string; - password: string; -} diff --git a/apps/server/archive/contexts/auth/presentation/dto/auth.response.dto.ts b/apps/server/archive/contexts/auth/presentation/dto/auth.response.dto.ts deleted file mode 100644 index 28ff0dc0..00000000 --- a/apps/server/archive/contexts/auth/presentation/dto/auth.response.dto.ts +++ /dev/null @@ -1,24 +0,0 @@ -export interface IRegisterUserResponseDTO { - user_id: string; - username: string; - email: string; -} - -export interface ILoginUserResponseDTO { - user: { - id: string; - username: string; - email: string; - tab_id: string; - }; - tokens: { - access_token: string; - refresh_token: string; - }; -} - -export type ILogoutResponseDTO = {} - -export interface IRefreshTokenResponseDTO { - refresh_token: string; -} diff --git a/apps/server/archive/contexts/auth/presentation/dto/auth.validation.dto.ts b/apps/server/archive/contexts/auth/presentation/dto/auth.validation.dto.ts deleted file mode 100644 index 4ebccdf5..00000000 --- a/apps/server/archive/contexts/auth/presentation/dto/auth.validation.dto.ts +++ /dev/null @@ -1,16 +0,0 @@ -import * as z from "zod/v4"; - -export const RegisterUserSchema = z.object({ - username: z.string().min(3, "Username must be at least 3 characters long"), - email: z.string().email("Invalid email format"), - password: z.string().min(6, "Password must be at least 6 characters long"), -}); - -export const LoginUserSchema = z.object({ - email: z.string().email("Invalid email format"), - password: z.string().min(6, "Password must be at least 6 characters long"), -}); - -export const RefreshTokenSchema = z.object({ - refresh_token: z.string().min(1, "Refresh token is required"), -}); diff --git a/apps/server/archive/contexts/auth/presentation/dto/index.ts b/apps/server/archive/contexts/auth/presentation/dto/index.ts deleted file mode 100644 index 9e7426a1..00000000 --- a/apps/server/archive/contexts/auth/presentation/dto/index.ts +++ /dev/null @@ -1,7 +0,0 @@ -export * from "./auth.request.dto"; -export * from "./auth.response.dto"; -export * from "./auth.validation.dto"; - -export * from "./user.request.dto"; -export * from "./user.response.dto"; -export * from "./user.validation.dto"; diff --git a/apps/server/archive/contexts/auth/presentation/dto/user.request.dto.ts b/apps/server/archive/contexts/auth/presentation/dto/user.request.dto.ts deleted file mode 100644 index c5e2a01e..00000000 --- a/apps/server/archive/contexts/auth/presentation/dto/user.request.dto.ts +++ /dev/null @@ -1 +0,0 @@ -export type IListUsersRequestDTO = {} diff --git a/apps/server/archive/contexts/auth/presentation/dto/user.response.dto.ts b/apps/server/archive/contexts/auth/presentation/dto/user.response.dto.ts deleted file mode 100644 index 5e68f303..00000000 --- a/apps/server/archive/contexts/auth/presentation/dto/user.response.dto.ts +++ /dev/null @@ -1,5 +0,0 @@ -export interface IListUsersResponseDTO { - id: string; - username: string; - email: string; -} diff --git a/apps/server/archive/contexts/auth/presentation/dto/user.validation.dto.ts b/apps/server/archive/contexts/auth/presentation/dto/user.validation.dto.ts deleted file mode 100644 index f5852158..00000000 --- a/apps/server/archive/contexts/auth/presentation/dto/user.validation.dto.ts +++ /dev/null @@ -1,3 +0,0 @@ -import * as z from "zod/v4"; - -export const ListUsersSchema = z.object({}); diff --git a/apps/server/archive/contexts/auth/presentation/index.ts b/apps/server/archive/contexts/auth/presentation/index.ts deleted file mode 100644 index a123289d..00000000 --- a/apps/server/archive/contexts/auth/presentation/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from "./controllers"; -export * from "./dto"; diff --git a/apps/server/archive/contexts/contacts/application/index.ts b/apps/server/archive/contexts/contacts/application/index.ts deleted file mode 100644 index 2a2e90ae..00000000 --- a/apps/server/archive/contexts/contacts/application/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from "./list-contacts.use-case"; diff --git a/apps/server/archive/contexts/contacts/application/list-contacts.use-case.ts b/apps/server/archive/contexts/contacts/application/list-contacts.use-case.ts deleted file mode 100644 index 7ac3ba52..00000000 --- a/apps/server/archive/contexts/contacts/application/list-contacts.use-case.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { ITransactionManager } from "@/core/common/infrastructure/database"; -import { Collection, Result } from "@repo/rdx-utils"; -import { Contact, IContactService } from "../domain"; - -export class ListContactsUseCase { - constructor( - private readonly contactService: IContactService, - private readonly transactionManager: ITransactionManager - ) {} - - public execute(): Promise, Error>> { - return this.transactionManager.complete((transaction) => { - return this.contactService.findContact(transaction); - }); - } -} diff --git a/apps/server/archive/contexts/contacts/domain/aggregates/contact.ts b/apps/server/archive/contexts/contacts/domain/aggregates/contact.ts deleted file mode 100644 index e69aa3dc..00000000 --- a/apps/server/archive/contexts/contacts/domain/aggregates/contact.ts +++ /dev/null @@ -1,130 +0,0 @@ -import { - AggregateRoot, - type EmailAddress, - type PhoneNumber, - type PostalAddress, - type TINNumber, - UniqueID, -} from "@/core/common/domain"; -import { Maybe, Result } from "@repo/rdx-utils"; - -export interface IContactProps { - reference: string; - isFreelancer: boolean; - name: string; - tin: TINNumber; - address: PostalAddress; - email: EmailAddress; - phone: PhoneNumber; - legalRecord: string; - defaultTax: number; - status: string; - langCode: string; - currencyCode: string; - - tradeName: Maybe; - website: Maybe; - fax: Maybe; -} - -export interface IContact { - id: UniqueID; - reference: string; - name: string; - tin: TINNumber; - address: PostalAddress; - email: EmailAddress; - phone: PhoneNumber; - legalRecord: string; - defaultTax: number; - langCode: string; - currencyCode: string; - - tradeName: Maybe; - fax: Maybe; - website: Maybe; - - isContact: boolean; - isFreelancer: boolean; - isActive: boolean; -} - -export class Contact extends AggregateRoot implements IContact { - static create(props: IContactProps, id?: UniqueID): Result { - const contact = new Contact(props, id); - - // Reglas de negocio / validaciones - // ... - // ... - - // 馃敼 Disparar evento de dominio "ContactAuthenticatedEvent" - //const { contact } = props; - //user.addDomainEvent(new ContactAuthenticatedEvent(id, contact.toString())); - - return Result.ok(contact); - } - - get reference() { - return this.props.reference; - } - - get name() { - return this.props.name; - } - - get tradeName() { - return this.props.tradeName; - } - - get tin(): TINNumber { - return this.props.tin; - } - - get address(): PostalAddress { - return this.props.address; - } - - get email(): EmailAddress { - return this.props.email; - } - - get phone(): PhoneNumber { - return this.props.phone; - } - - get fax(): Maybe { - return this.props.fax; - } - - get website() { - return this.props.website; - } - - get legalRecord() { - return this.props.legalRecord; - } - - get defaultTax() { - return this.props.defaultTax; - } - - get langCode() { - return this.props.langCode; - } - - get currencyCode() { - return this.props.currencyCode; - } - - get isContact(): boolean { - return !this.props.isFreelancer; - } - - get isFreelancer(): boolean { - return this.props.isFreelancer; - } - - get isActive(): boolean { - return this.props.status === "active"; - } -} diff --git a/apps/server/archive/contexts/contacts/domain/aggregates/index.ts b/apps/server/archive/contexts/contacts/domain/aggregates/index.ts deleted file mode 100644 index d191830c..00000000 --- a/apps/server/archive/contexts/contacts/domain/aggregates/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from "./contact"; diff --git a/apps/server/archive/contexts/contacts/domain/index.ts b/apps/server/archive/contexts/contacts/domain/index.ts deleted file mode 100644 index ef023faa..00000000 --- a/apps/server/archive/contexts/contacts/domain/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -export * from "./aggregates"; -export * from "./repositories"; -export * from "./services"; diff --git a/apps/server/archive/contexts/contacts/domain/repositories/contact-repository.interface.ts b/apps/server/archive/contexts/contacts/domain/repositories/contact-repository.interface.ts deleted file mode 100644 index e7fa33d6..00000000 --- a/apps/server/archive/contexts/contacts/domain/repositories/contact-repository.interface.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { EmailAddress, UniqueID } from "@/core/common/domain"; -import { Collection, Result } from "@repo/rdx-utils"; -import { Contact } from "../aggregates"; - -export interface IContactRepository { - findAll(transaction?: any): Promise, Error>>; - findById(id: UniqueID, transaction?: any): Promise>; - findByEmail(email: EmailAddress, transaction?: any): Promise>; -} diff --git a/apps/server/archive/contexts/contacts/domain/repositories/index.ts b/apps/server/archive/contexts/contacts/domain/repositories/index.ts deleted file mode 100644 index fb499b12..00000000 --- a/apps/server/archive/contexts/contacts/domain/repositories/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from "./contact-repository.interface"; diff --git a/apps/server/archive/contexts/contacts/domain/services/contact-service.interface.ts b/apps/server/archive/contexts/contacts/domain/services/contact-service.interface.ts deleted file mode 100644 index 8feaa58f..00000000 --- a/apps/server/archive/contexts/contacts/domain/services/contact-service.interface.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { UniqueID } from "@/core/common/domain"; -import { Collection, Result } from "@repo/rdx-utils"; -import { Contact } from "../aggregates"; - -export interface IContactService { - findContact(transaction?: any): Promise, Error>>; - findContactById(contactId: UniqueID, transaction?: any): Promise>; -} diff --git a/apps/server/archive/contexts/contacts/domain/services/contact.service.ts b/apps/server/archive/contexts/contacts/domain/services/contact.service.ts deleted file mode 100644 index 12404818..00000000 --- a/apps/server/archive/contexts/contacts/domain/services/contact.service.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { UniqueID } from "@/core/common/domain"; -import { Collection, Result } from "@repo/rdx-utils"; -import { Contact } from "../aggregates"; -import { IContactRepository } from "../repositories"; -import { IContactService } from "./contact-service.interface"; - -export class ContactService implements IContactService { - constructor(private readonly contactRepository: IContactRepository) {} - - async findContact(transaction?: any): Promise, Error>> { - const contactsOrError = await this.contactRepository.findAll(transaction); - if (contactsOrError.isFailure) { - return Result.fail(contactsOrError.error); - } - - // Solo devolver usuarios activos - const activeContacts = contactsOrError.data.filter((contact) => contact.isActive); - return Result.ok(new Collection(activeContacts)); - } - - async findContactById(contactId: UniqueID, transaction?: any): Promise> { - return await this.contactRepository.findById(contactId, transaction); - } -} diff --git a/apps/server/archive/contexts/contacts/domain/services/index.ts b/apps/server/archive/contexts/contacts/domain/services/index.ts deleted file mode 100644 index f029fdca..00000000 --- a/apps/server/archive/contexts/contacts/domain/services/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from "./contact-service.interface"; -export * from "./contact.service"; diff --git a/apps/server/archive/contexts/contacts/infraestructure/index.ts b/apps/server/archive/contexts/contacts/infraestructure/index.ts deleted file mode 100644 index 7ccefa3a..00000000 --- a/apps/server/archive/contexts/contacts/infraestructure/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from "./mappers"; -export * from "./sequelize"; diff --git a/apps/server/archive/contexts/contacts/infraestructure/mappers/contact.mapper.ts b/apps/server/archive/contexts/contacts/infraestructure/mappers/contact.mapper.ts deleted file mode 100644 index 6403fc7d..00000000 --- a/apps/server/archive/contexts/contacts/infraestructure/mappers/contact.mapper.ts +++ /dev/null @@ -1,106 +0,0 @@ -import { - EmailAddress, - PhoneNumber, - PostalAddress, - TINNumber, - UniqueID, -} from "@/core/common/domain"; -import { - type ISequelizeMapper, - type MapperParamsType, - SequelizeMapper, -} from "@/core/common/infrastructure/sequelize/sequelize-mapper"; -import { Maybe, Result } from "@repo/rdx-utils"; -import { Contact } from "../../domain"; -import { ContactCreationAttributes, ContactModel } from "../sequelize/contact.model"; - -export interface IContactMapper - extends ISequelizeMapper {} - -export class ContactMapper - extends SequelizeMapper - implements IContactMapper -{ - public mapToDomain(source: ContactModel, params?: MapperParamsType): Result { - const idOrError = UniqueID.create(source.id); - const tinOrError = TINNumber.create(source.tin); - const emailOrError = EmailAddress.create(source.email); - const phoneOrError = PhoneNumber.create(source.phone); - const faxOrError = PhoneNumber.createNullable(source.fax); - const postalAddressOrError = PostalAddress.create({ - street: source.street, - city: source.city, - state: source.state, - postalCode: source.postal_code, - country: source.country, - }); - - const result = Result.combine([ - idOrError, - tinOrError, - emailOrError, - phoneOrError, - faxOrError, - postalAddressOrError, - ]); - - if (result.isFailure) { - return Result.fail(result.error); - } - - return Contact.create( - { - isFreelancer: source.is_companyr, - reference: source.reference, - name: source.name, - tradeName: source.trade_name ? Maybe.some(source.trade_name) : Maybe.none(), - tin: tinOrError.data, - address: postalAddressOrError.data, - email: emailOrError.data, - phone: phoneOrError.data, - fax: faxOrError.data, - website: source.website ? Maybe.some(source.website) : Maybe.none(), - legalRecord: source.legal_record, - defaultTax: source.default_tax, - status: source.status, - langCode: source.language_code, - currencyCode: source.currency_code, - }, - idOrError.data - ); - } - - public mapToPersistence( - source: Contact, - params?: MapperParamsType - ): Result { - return Result.ok({ - id: source.id.toString(), - reference: source.reference, - is_companyr: source.isFreelancer, - name: source.name, - trade_name: source.tradeName.getOrUndefined(), - tin: source.tin.toString(), - - street: source.address.street, - city: source.address.city, - state: source.address.state, - postal_code: source.address.postalCode, - country: source.address.country, - - email: source.email.toString(), - phone: source.phone.toString(), - fax: source.fax.isSome() ? source.fax.getOrUndefined()?.toString() : undefined, - website: source.website.getOrUndefined(), - - legal_record: source.legalRecord, - default_tax: source.defaultTax, - status: source.isActive ? "active" : "inactive", - language_code: source.langCode, - currency_code: source.currencyCode, - }); - } -} - -const contactMapper: ContactMapper = new ContactMapper(); -export { contactMapper }; diff --git a/apps/server/archive/contexts/contacts/infraestructure/mappers/index.ts b/apps/server/archive/contexts/contacts/infraestructure/mappers/index.ts deleted file mode 100644 index f2d160c4..00000000 --- a/apps/server/archive/contexts/contacts/infraestructure/mappers/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from "./contact.mapper"; diff --git a/apps/server/archive/contexts/contacts/infraestructure/sequelize/contact.model.ts b/apps/server/archive/contexts/contacts/infraestructure/sequelize/contact.model.ts deleted file mode 100644 index aa2a7583..00000000 --- a/apps/server/archive/contexts/contacts/infraestructure/sequelize/contact.model.ts +++ /dev/null @@ -1,175 +0,0 @@ -import { - CreationOptional, - DataTypes, - InferAttributes, - InferCreationAttributes, - Model, - Sequelize, -} from "sequelize"; - -export type ContactCreationAttributes = InferCreationAttributes & {}; - -export class ContactModel extends Model< - InferAttributes, - InferCreationAttributes -> { - // To avoid table creation - /*static async sync(): Promise { - return Promise.resolve(); - }*/ - - declare id: string; - declare reference: CreationOptional; - - declare is_companyr: boolean; - declare name: string; - declare trade_name: CreationOptional; - declare tin: string; - - declare street: string; - declare city: string; - declare state: string; - declare postal_code: string; - declare country: string; - - declare email: string; - declare phone: string; - declare fax: CreationOptional; - declare website: CreationOptional; - - declare legal_record: string; - - declare default_tax: number; - declare status: string; - declare language_code: string; - declare currency_code: string; -} - -export default (sequelize: Sequelize) => { - ContactModel.init( - { - id: { - type: DataTypes.UUID, - primaryKey: true, - }, - reference: { - type: DataTypes.STRING, - allowNull: false, - }, - is_companyr: { - type: DataTypes.BOOLEAN, - allowNull: false, - }, - name: { - type: DataTypes.STRING, - allowNull: false, - }, - trade_name: { - type: DataTypes.STRING, - allowNull: true, - defaultValue: null, - }, - tin: { - type: DataTypes.STRING, - allowNull: false, - }, - - street: { - type: DataTypes.STRING, - allowNull: false, - }, - city: { - type: DataTypes.STRING, - allowNull: false, - }, - state: { - type: DataTypes.STRING, - allowNull: false, - }, - postal_code: { - type: DataTypes.STRING, - allowNull: false, - }, - country: { - type: DataTypes.STRING, - allowNull: false, - }, - - email: { - type: DataTypes.STRING, - allowNull: false, - validate: { - isEmail: true, - }, - }, - phone: { - type: DataTypes.STRING, - allowNull: false, - }, - fax: { - type: DataTypes.STRING, - allowNull: true, - defaultValue: null, - }, - website: { - type: DataTypes.STRING, - allowNull: true, - defaultValue: null, - validate: { - isUrl: true, - }, - }, - legal_record: { - type: DataTypes.TEXT, - allowNull: false, - }, - - default_tax: { - type: new DataTypes.SMALLINT(), - allowNull: false, - defaultValue: 2100, - }, - - language_code: { - type: DataTypes.STRING(2), - allowNull: false, - defaultValue: "es", - }, - - currency_code: { - type: new DataTypes.STRING(3), - allowNull: false, - defaultValue: "EUR", - }, - - status: { - type: DataTypes.STRING, - allowNull: false, - defaultValue: "active", - }, - }, - { - sequelize, - tableName: "contacts", - - paranoid: true, // softs deletes - timestamps: true, - - createdAt: "created_at", - updatedAt: "updated_at", - deletedAt: "deleted_at", - - indexes: [ - { name: "email_idx", fields: ["email"], unique: true }, - { name: "reference_idx", fields: ["reference"], unique: true }, - ], - - whereMergeStrategy: "and", // <- c贸mo tratar el merge de un scope - - defaultScope: {}, - - scopes: {}, - } - ); - return ContactModel; -}; diff --git a/apps/server/archive/contexts/contacts/infraestructure/sequelize/contact.repository.ts b/apps/server/archive/contexts/contacts/infraestructure/sequelize/contact.repository.ts deleted file mode 100644 index b9e8fd51..00000000 --- a/apps/server/archive/contexts/contacts/infraestructure/sequelize/contact.repository.ts +++ /dev/null @@ -1,81 +0,0 @@ -import { EmailAddress, UniqueID } from "@/core/common/domain"; -import { SequelizeRepository } from "@/core/common/infrastructure"; -import { Collection, Result } from "@repo/rdx-utils"; -import { Transaction } from "sequelize"; -import { Contact, IContactRepository } from "../../domain"; -import { IContactMapper, contactMapper } from "../mappers"; -import { ContactModel } from "./contact.model"; - -class ContactRepository extends SequelizeRepository implements IContactRepository { - private readonly _mapper!: IContactMapper; - - /** - * 馃敼 Funci贸n personalizada para mapear errores de unicidad en autenticaci贸n - */ - private _customErrorMapper(error: Error): string | null { - if (error.name === "SequelizeUniqueConstraintError") { - return "Contact with this email already exists"; - } - - return null; - } - - constructor(mapper: IContactMapper) { - super(); - this._mapper = mapper; - } - - async findAll(transaction?: Transaction): Promise, Error>> { - try { - const rawContacts: any = await this._findAll(ContactModel, {}, transaction); - - if (!rawContacts === true) { - return Result.fail(new Error("Contact with email not exists")); - } - - return this._mapper.mapArrayToDomain(rawContacts); - } catch (error: any) { - return this._handleDatabaseError(error, this._customErrorMapper); - } - } - - async findById(id: UniqueID, transaction?: Transaction): Promise> { - try { - const rawContact: any = await this._getById(ContactModel, id, {}, transaction); - - if (!rawContact === true) { - return Result.fail(new Error(`Contact with id ${id.toString()} not exists`)); - } - - return this._mapper.mapToDomain(rawContact); - } catch (error: any) { - return this._handleDatabaseError(error, this._customErrorMapper); - } - } - - async findByEmail( - email: EmailAddress, - transaction?: Transaction - ): Promise> { - try { - const rawContact: any = await this._getBy( - ContactModel, - "email", - email.toString(), - {}, - transaction - ); - - if (!rawContact === true) { - return Result.fail(new Error(`Contact with email ${email.toString()} not exists`)); - } - - return this._mapper.mapToDomain(rawContact); - } catch (error: any) { - return this._handleDatabaseError(error, this._customErrorMapper); - } - } -} - -const contactRepository = new ContactRepository(contactMapper); -export { contactRepository }; diff --git a/apps/server/archive/contexts/contacts/infraestructure/sequelize/index.ts b/apps/server/archive/contexts/contacts/infraestructure/sequelize/index.ts deleted file mode 100644 index 09c1257f..00000000 --- a/apps/server/archive/contexts/contacts/infraestructure/sequelize/index.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { IContactRepository } from "../../domain"; -import { contactRepository } from "./contact.repository"; - -export * from "./contact.model"; -export * from "./contact.repository"; - -export const createContactRepository = (): IContactRepository => { - return contactRepository; -}; diff --git a/apps/server/archive/contexts/contacts/presentation/controllers/index.ts b/apps/server/archive/contexts/contacts/presentation/controllers/index.ts deleted file mode 100644 index 491ccf0c..00000000 --- a/apps/server/archive/contexts/contacts/presentation/controllers/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from "./list"; diff --git a/apps/server/archive/contexts/contacts/presentation/controllers/list/index.ts b/apps/server/archive/contexts/contacts/presentation/controllers/list/index.ts deleted file mode 100644 index 070a5ea3..00000000 --- a/apps/server/archive/contexts/contacts/presentation/controllers/list/index.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { SequelizeTransactionManager } from "@/core/common/infrastructure"; -import { ListContactsUseCase } from "../../../application"; -import { ContactService } from "../../../domain"; -import { contactRepository } from "../../../infraestructure"; -import { ListContactsController } from "./list-contacts.controller"; -import { listContactsPresenter } from "./list-contacts.presenter"; - -export const listContactsController = () => { - const transactionManager = new SequelizeTransactionManager(); - const contactService = new ContactService(contactRepository); - - const useCase = new ListContactsUseCase(contactService, transactionManager); - const presenter = listContactsPresenter; - - return new ListContactsController(useCase, presenter); -}; diff --git a/apps/server/archive/contexts/contacts/presentation/controllers/list/list-contacts.controller.ts b/apps/server/archive/contexts/contacts/presentation/controllers/list/list-contacts.controller.ts deleted file mode 100644 index a5f2dcf7..00000000 --- a/apps/server/archive/contexts/contacts/presentation/controllers/list/list-contacts.controller.ts +++ /dev/null @@ -1,37 +0,0 @@ -import { ExpressController } from "@/core/common/presentation"; -import { ListContactsUseCase } from "../../../application"; -import { IListContactsPresenter } from "./list-contacts.presenter"; - -export class ListContactsController extends ExpressController { - public constructor( - private readonly listContacts: ListContactsUseCase, - private readonly presenter: IListContactsPresenter - ) { - super(); - } - - protected async executeImpl() { - const contactsOrError = await this.listContacts.execute(); - - if (contactsOrError.isFailure) { - return this.handleError(contactsOrError.error); - } - - return this.ok(this.presenter.toDTO(contactsOrError.data)); - } - - private handleError(error: Error) { - const message = error.message; - - if ( - message.includes("Database connection lost") || - message.includes("Database request timed out") - ) { - return this.unavailableError( - "Database service is currently unavailable. Please try again later." - ); - } - - return this.conflictError(message); - } -} diff --git a/apps/server/archive/contexts/contacts/presentation/controllers/list/list-contacts.presenter.ts b/apps/server/archive/contexts/contacts/presentation/controllers/list/list-contacts.presenter.ts deleted file mode 100644 index a5b12647..00000000 --- a/apps/server/archive/contexts/contacts/presentation/controllers/list/list-contacts.presenter.ts +++ /dev/null @@ -1,38 +0,0 @@ -import { Collection, ensureBoolean, ensureNumber, ensureString } from "@repo/rdx-utils"; -import { Contact } from "../../../domain"; -import { IListContactsResponseDTO } from "../../dto"; - -export interface IListContactsPresenter { - toDTO: (contacts: Collection) => IListContactsResponseDTO[]; -} - -export const listContactsPresenter: IListContactsPresenter = { - toDTO: (contacts: Collection): IListContactsResponseDTO[] => - contacts.map((contact) => ({ - id: ensureString(contact.id.toString()), - reference: ensureString(contact.reference), - - is_companyr: ensureBoolean(contact.isFreelancer), - name: ensureString(contact.name), - trade_name: ensureString(contact.tradeName.getOrUndefined()), - tin: ensureString(contact.tin.toString()), - - street: ensureString(contact.address.street), - city: ensureString(contact.address.city), - state: ensureString(contact.address.state), - postal_code: ensureString(contact.address.postalCode), - country: ensureString(contact.address.country), - - email: ensureString(contact.email.toString()), - phone: ensureString(contact.phone.toString()), - fax: ensureString(contact.fax.getOrUndefined()?.toString()), - website: ensureString(contact.website.getOrUndefined()), - - legal_record: ensureString(contact.legalRecord), - - default_tax: ensureNumber(contact.defaultTax), - status: ensureString(contact.isActive ? "active" : "inactive"), - language_code: ensureString(contact.langCode), - currency_code: ensureString(contact.currencyCode), - })), -}; diff --git a/apps/server/archive/contexts/contacts/presentation/dto/contacts.request.dto.ts b/apps/server/archive/contexts/contacts/presentation/dto/contacts.request.dto.ts deleted file mode 100644 index 7db50854..00000000 --- a/apps/server/archive/contexts/contacts/presentation/dto/contacts.request.dto.ts +++ /dev/null @@ -1 +0,0 @@ -export type IListContactsRequestDTO = {} diff --git a/apps/server/archive/contexts/contacts/presentation/dto/contacts.response.dto.ts b/apps/server/archive/contexts/contacts/presentation/dto/contacts.response.dto.ts deleted file mode 100644 index 597763db..00000000 --- a/apps/server/archive/contexts/contacts/presentation/dto/contacts.response.dto.ts +++ /dev/null @@ -1,27 +0,0 @@ -export interface IListContactsResponseDTO { - id: string; - reference: string; - - is_companyr: boolean; - name: string; - trade_name: string; - tin: string; - - street: string; - city: string; - state: string; - postal_code: string; - country: string; - - email: string; - phone: string; - fax: string; - website: string; - - legal_record: string; - - default_tax: number; - status: string; - language_code: string; - currency_code: string; -} diff --git a/apps/server/archive/contexts/contacts/presentation/dto/contacts.validation.dto.ts b/apps/server/archive/contexts/contacts/presentation/dto/contacts.validation.dto.ts deleted file mode 100644 index 16b1b220..00000000 --- a/apps/server/archive/contexts/contacts/presentation/dto/contacts.validation.dto.ts +++ /dev/null @@ -1,3 +0,0 @@ -import * as z from "zod/v4"; - -export const ListContactsSchema = z.object({}); diff --git a/apps/server/archive/contexts/contacts/presentation/dto/index.ts b/apps/server/archive/contexts/contacts/presentation/dto/index.ts deleted file mode 100644 index 905cc636..00000000 --- a/apps/server/archive/contexts/contacts/presentation/dto/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -export * from "./contacts.request.dto"; -export * from "./contacts.response.dto"; -export * from "./contacts.validation.dto"; diff --git a/apps/server/archive/contexts/contacts/presentation/index.ts b/apps/server/archive/contexts/contacts/presentation/index.ts deleted file mode 100644 index a123289d..00000000 --- a/apps/server/archive/contexts/contacts/presentation/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from "./controllers"; -export * from "./dto"; diff --git a/modules/customer-invoices/src/api/infrastructure/common/di/index.ts b/modules/customer-invoices/src/api/infrastructure/common/di/index.ts deleted file mode 100644 index dcede61b..00000000 --- a/modules/customer-invoices/src/api/infrastructure/common/di/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from "./repositories.di"; diff --git a/modules/customer-invoices/src/api/infrastructure/common/di/repositories.di.ts b/modules/customer-invoices/src/api/infrastructure/common/di/repositories.di.ts deleted file mode 100644 index 1ac1eef7..00000000 --- a/modules/customer-invoices/src/api/infrastructure/common/di/repositories.di.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { SpainTaxCatalogProvider } from "@erp/core"; -import type { Sequelize } from "sequelize"; - -export const buildIssuedInvoiceRepository = (database: Sequelize) => { - const taxCatalog = SpainTaxCatalogProvider(); - - const domainMapper = new SequelizeIssuedInvoiceDomainMapper({ - taxCatalog, - }); - const listMapper = new SequelizeIssuedInvoiceListMapper(); - - return new IssuedInvoiceRepository(domainMapper, listMapper, database); -}; diff --git a/modules/customer-invoices/src/api/infrastructure/common/index.ts b/modules/customer-invoices/src/api/infrastructure/common/index.ts index 96e04610..4a309c4d 100644 --- a/modules/customer-invoices/src/api/infrastructure/common/index.ts +++ b/modules/customer-invoices/src/api/infrastructure/common/index.ts @@ -1,2 +1 @@ -export * from "./di"; export * from "./persistence"; diff --git a/modules/customer-invoices/src/api/infrastructure/common/persistence/sequelize/mappers/domain/customer-invoice-item.mapper.ts b/modules/customer-invoices/src/api/infrastructure/common/persistence/sequelize/mappers/domain/customer-invoice-item.mapper.ts deleted file mode 100644 index e10675f0..00000000 --- a/modules/customer-invoices/src/api/infrastructure/common/persistence/sequelize/mappers/domain/customer-invoice-item.mapper.ts +++ /dev/null @@ -1,305 +0,0 @@ -import type { JsonTaxCatalogProvider } from "@erp/core"; -import { - DiscountPercentage, - type ISequelizeDomainMapper, - type MapperParamsType, - SequelizeDomainMapper, - Tax, -} from "@erp/core/api"; -import { - UniqueID, - ValidationErrorCollection, - type ValidationErrorDetail, - extractOrPushError, - maybeFromNullableResult, - maybeToNullable, -} from "@repo/rdx-ddd"; -import { Result } from "@repo/rdx-utils"; - -import { - IssuedInvoiceItem, - ItemAmount, - ItemDescription, - ItemQuantity, - type Proforma, - type ProformaCreateProps, -} from "../../../../../../domain"; - -export interface ICustomerInvoiceItemDomainMapper - extends ISequelizeDomainMapper< - CustomerInvoiceItemModel, - CustomerInvoiceItemCreationAttributes, - IssuedInvoiceItem - > {} - -export class CustomerInvoiceItemDomainMapper - extends SequelizeDomainMapper< - CustomerInvoiceItemModel, - CustomerInvoiceItemCreationAttributes, - IssuedInvoiceItem - > - implements ICustomerInvoiceItemDomainMapper -{ - private _taxCatalog!: JsonTaxCatalogProvider; - - constructor(params: MapperParamsType) { - super(); - const { taxCatalog } = params as { - taxCatalog: JsonTaxCatalogProvider; - }; - - if (!taxCatalog) { - throw new Error('taxCatalog not defined ("CustomerInvoiceItemDomainMapper")'); - } - - this._taxCatalog = taxCatalog; - } - - private mapAttributesToDomain( - source: CustomerInvoiceItemModel, - params?: MapperParamsType - ): Partial & { itemId?: UniqueID } { - const { errors, index, attributes } = params as { - index: number; - errors: ValidationErrorDetail[]; - attributes: Partial; - }; - - const itemId = extractOrPushError( - UniqueID.create(source.item_id), - `items[${index}].item_id`, - errors - ); - - const description = extractOrPushError( - maybeFromNullableResult(source.description, (v) => ItemDescription.create(v)), - `items[${index}].description`, - errors - ); - - const quantity = extractOrPushError( - maybeFromNullableResult(source.quantity_value, (v) => ItemQuantity.create({ value: v })), - `items[${index}].quantity`, - errors - ); - - const unitAmount = extractOrPushError( - maybeFromNullableResult(source.unit_amount_value, (value) => - ItemAmount.create({ value, currency_code: attributes.currencyCode?.code }) - ), - `items[${index}].unit_amount`, - errors - ); - - const discountPercentage = extractOrPushError( - maybeFromNullableResult(source.discount_percentage_value, (v) => - DiscountPercentage.create({ value: v }) - ), - `items[${index}].discount_percentage`, - errors - ); - - const globalDiscountPercentage = extractOrPushError( - maybeFromNullableResult(source.global_discount_percentage_value, (v) => - DiscountPercentage.create({ value: v }) - ), - `items[${index}].discount_percentage`, - errors - ); - - const iva = extractOrPushError( - maybeFromNullableResult(source.iva_code, (code) => - Tax.createFromCode(code, this._taxCatalog) - ), - `items[${index}].iva_code`, - errors - ); - - const rec = extractOrPushError( - maybeFromNullableResult(source.rec_code, (code) => - Tax.createFromCode(code, this._taxCatalog) - ), - `items[${index}].rec_code`, - errors - ); - - const retention = extractOrPushError( - maybeFromNullableResult(source.retention_code, (code) => - Tax.createFromCode(code, this._taxCatalog) - ), - `items[${index}].retention_code`, - errors - ); - - return { - itemId, - - languageCode: attributes.languageCode, - currencyCode: attributes.currencyCode, - description, - quantity, - unitAmount, - itemDiscountPercentage: discountPercentage, - globalDiscountPercentage, - - taxes: ItemTaxGroup.create({ - iva: iva!, - rec: rec!, - retention: retention!, - }).data, - }; - } - - public mapToDomain( - source: CustomerInvoiceItemModel, - params?: MapperParamsType - ): Result { - const { errors, index } = params as { - index: number; - errors: ValidationErrorDetail[]; - attributes: Partial; - }; - - // 1) Valores escalares (atributos generales) - const attributes = this.mapAttributesToDomain(source, params); - - // Si hubo errores de mapeo, devolvemos colecci贸n de validaci贸n - if (errors.length > 0) { - return Result.fail( - new ValidationErrorCollection("Customer invoice item mapping failed [mapToDomain]", errors) - ); - } - - // 2) Construcci贸n del elemento de dominio - const createResult = IssuedInvoiceItem.create( - { - languageCode: attributes.languageCode!, - currencyCode: attributes.currencyCode!, - description: attributes.description!, - quantity: attributes.quantity!, - unitAmount: attributes.unitAmount!, - itemDiscountPercentage: attributes.itemDiscountPercentage!, - globalDiscountPercentage: attributes.globalDiscountPercentage!, - taxes: attributes.taxes!, - }, - attributes.itemId - ); - - if (createResult.isFailure) { - return Result.fail( - new ValidationErrorCollection("Invoice item entity creation failed", [ - { path: `items[${index}]`, message: createResult.error.message }, - ]) - ); - } - - return createResult; - } - - public mapToPersistence( - source: IssuedInvoiceItem, - params?: MapperParamsType - ): Result { - const { errors, index, parent } = params as { - index: number; - parent: Proforma; - errors: ValidationErrorDetail[]; - }; - - const allAmounts = source.calculateAllAmounts(); - const taxesAmounts = source.taxes.calculateAmounts(allAmounts.taxableAmount); - - return Result.ok({ - item_id: source.id.toPrimitive(), - invoice_id: parent.id.toPrimitive(), - position: index, - - description: maybeToNullable(source.description, (v) => v.toPrimitive()), - - quantity_value: maybeToNullable(source.quantity, (v) => v.toPrimitive().value), - quantity_scale: - maybeToNullable(source.quantity, (v) => v.toPrimitive().scale) ?? - ItemQuantity.DEFAULT_SCALE, - - unit_amount_value: maybeToNullable(source.unitAmount, (v) => v.toPrimitive().value), - unit_amount_scale: - maybeToNullable(source.unitAmount, (v) => v.toPrimitive().scale) ?? - ItemAmount.DEFAULT_SCALE, - - subtotal_amount_value: allAmounts.subtotalAmount.value, - subtotal_amount_scale: allAmounts.subtotalAmount.scale, - - // - discount_percentage_value: maybeToNullable( - source.itemDiscountPercentage, - (v) => v.toPrimitive().value - ), - discount_percentage_scale: - maybeToNullable(source.itemDiscountPercentage, (v) => v.toPrimitive().scale) ?? - DiscountPercentage.DEFAULT_SCALE, - - discount_amount_value: allAmounts.itemDiscountAmount.value, - discount_amount_scale: allAmounts.itemDiscountAmount.scale, - - // - global_discount_percentage_value: maybeToNullable( - source.globalDiscountPercentage, - (v) => v.toPrimitive().value - ), - - global_discount_percentage_scale: - maybeToNullable(source.globalDiscountPercentage, (v) => v.toPrimitive().scale) ?? - DiscountPercentage.DEFAULT_SCALE, - - global_discount_amount_value: allAmounts.globalDiscountAmount.value, - global_discount_amount_scale: allAmounts.globalDiscountAmount.scale, - - // - total_discount_amount_value: allAmounts.totalDiscountAmount.value, - total_discount_amount_scale: allAmounts.totalDiscountAmount.scale, - - // - taxable_amount_value: allAmounts.taxableAmount.value, - taxable_amount_scale: allAmounts.taxableAmount.scale, - - // IVA - iva_code: maybeToNullable(source.taxes.iva, (v) => v.code), - - iva_percentage_value: maybeToNullable(source.taxes.iva, (v) => v.percentage.value), - iva_percentage_scale: maybeToNullable(source.taxes.iva, (v) => v.percentage.scale) ?? 2, - - iva_amount_value: taxesAmounts.ivaAmount.value, - iva_amount_scale: taxesAmounts.ivaAmount.scale, - - // REC - rec_code: maybeToNullable(source.taxes.rec, (v) => v.code), - - rec_percentage_value: maybeToNullable(source.taxes.rec, (v) => v.percentage.value), - rec_percentage_scale: maybeToNullable(source.taxes.rec, (v) => v.percentage.scale) ?? 2, - - rec_amount_value: taxesAmounts.recAmount.value, - rec_amount_scale: taxesAmounts.recAmount.scale, - - // RET - retention_code: maybeToNullable(source.taxes.retention, (v) => v.code), - - retention_percentage_value: maybeToNullable( - source.taxes.retention, - (v) => v.percentage.value - ), - retention_percentage_scale: - maybeToNullable(source.taxes.retention, (v) => v.percentage.scale) ?? 2, - - retention_amount_value: taxesAmounts.retentionAmount.value, - retention_amount_scale: taxesAmounts.retentionAmount.scale, - - // - taxes_amount_value: allAmounts.taxesAmount.value, - taxes_amount_scale: allAmounts.taxesAmount.scale, - - // - total_amount_value: allAmounts.totalAmount.value, - total_amount_scale: allAmounts.totalAmount.scale, - }); - } -} diff --git a/modules/customer-invoices/src/api/infrastructure/common/persistence/sequelize/mappers/domain/customer-invoice-taxes.mapper.ts b/modules/customer-invoices/src/api/infrastructure/common/persistence/sequelize/mappers/domain/customer-invoice-taxes.mapper.ts deleted file mode 100644 index 33c41ef5..00000000 --- a/modules/customer-invoices/src/api/infrastructure/common/persistence/sequelize/mappers/domain/customer-invoice-taxes.mapper.ts +++ /dev/null @@ -1,151 +0,0 @@ -import type { JsonTaxCatalogProvider } from "@erp/core"; -import { type MapperParamsType, SequelizeDomainMapper } from "@erp/core/api"; -import { UniqueID, type ValidationErrorDetail, maybeToNullable } from "@repo/rdx-ddd"; -import { Result } from "@repo/rdx-utils"; - -import type { InvoiceTaxGroup, Proforma } from "../../../../../../domain"; -import type { - CustomerInvoiceTaxCreationAttributes, - CustomerInvoiceTaxModel, -} from "../../../../sequelize"; - -/** - * Mapper para customer_invoice_taxes - * - * Domina estructuras: - * { - * tax: Tax - * taxableAmount: ItemAmount - * taxesAmount: ItemAmount - * } - * - * Cada fila = un impuesto agregado en toda la factura. - */ -export class CustomerInvoiceTaxesDomainMapper extends SequelizeDomainMapper< - CustomerInvoiceTaxModel, - CustomerInvoiceTaxCreationAttributes, - InvoiceTaxGroup -> { - private _taxCatalog: JsonTaxCatalogProvider; - - constructor(params: MapperParamsType) { - super(); - const { taxCatalog } = params as { - taxCatalog: JsonTaxCatalogProvider; - }; - - if (!taxCatalog) { - throw new Error('taxCatalog not defined ("TaxesMapper")'); - } - - this._taxCatalog = taxCatalog; - } - - public mapToDomain( - source: CustomerInvoiceTaxModel, - params?: MapperParamsType - ): Result { - /*const { attributes, errors, index } = params as { - index: number; - errors: ValidationErrorDetail[]; - attributes: Partial; - }; - - const currency_code = attributes.currencyCode!.code; - - const iva = extractOrPushError( - maybeFromNullableVO(source.iva_code, (code) => Tax.createFromCode(code, this._taxCatalog)), - `taxes[${index}].iva_code`, - errors - ); - - const rec = extractOrPushError( - maybeFromNullableVO(source.rec_code, (code) => Tax.createFromCode(code, this._taxCatalog)), - `items[${index}].rec_code`, - errors - ); - - const retention = extractOrPushError( - maybeFromNullableVO(source.retention_code, (code) => - Tax.createFromCode(code, this._taxCatalog) - ), - `items[${index}].retention_code`, - errors - ); - - // Si hubo errores de mapeo, devolvemos colecci贸n de validaci贸n - if (errors.length > 0) { - return Result.fail( - new ValidationErrorCollection("Customer invoice taxes mapping failed [mapToDomain]", errors) - ); - } - - const createResult = InvoiceTaxGroup.create({ - iva - }) - - return Result.ok();*/ - throw new Error("Se calcula a partir de las l铆neas de detalle"); - } - - public mapToPersistence( - source: InvoiceTaxGroup, - params?: MapperParamsType - ): Result { - const { errors, parent } = params as { - parent: Proforma; - errors: ValidationErrorDetail[]; - }; - - try { - const { ivaAmount, recAmount, retentionAmount } = source.calculateAmounts(); - - const totalTaxes = ivaAmount.add(recAmount).add(retentionAmount); - - const dto: CustomerInvoiceTaxCreationAttributes = { - tax_id: UniqueID.generateNewID().toPrimitive(), - invoice_id: parent.id.toPrimitive(), - - // TAXABLE AMOUNT - taxable_amount_value: source.taxableAmount.value, - taxable_amount_scale: source.taxableAmount.scale, - - // IVA - iva_code: source.iva.code, - - iva_percentage_value: source.iva.value, - iva_percentage_scale: source.iva.scale, - - iva_amount_value: ivaAmount.value, - iva_amount_scale: ivaAmount.scale, - - // REC - rec_code: maybeToNullable(source.rec, (v) => v.code), - - rec_percentage_value: maybeToNullable(source.rec, (v) => v.percentage.value), - rec_percentage_scale: maybeToNullable(source.rec, (v) => v.percentage.scale) ?? 2, - - rec_amount_value: recAmount.value, - rec_amount_scale: recAmount.scale, - - // RET - retention_code: maybeToNullable(source.retention, (v) => v.code), - - retention_percentage_value: maybeToNullable(source.retention, (v) => v.percentage.value), - retention_percentage_scale: - maybeToNullable(source.retention, (v) => v.percentage.scale) ?? 2, - - retention_amount_value: retentionAmount.value, - retention_amount_scale: retentionAmount.scale, - - // TOTAL - taxes_amount_value: totalTaxes.value, - taxes_amount_scale: totalTaxes.scale, - }; - - return Result.ok(dto); - } catch (error: unknown) { - return Result.fail(error as Error); - } - } -} diff --git a/modules/customer-invoices/src/api/infrastructure/common/persistence/sequelize/mappers/domain/customer-invoice.mapper.ts b/modules/customer-invoices/src/api/infrastructure/common/persistence/sequelize/mappers/domain/customer-invoice.mapper.ts deleted file mode 100644 index 42d782ad..00000000 --- a/modules/customer-invoices/src/api/infrastructure/common/persistence/sequelize/mappers/domain/customer-invoice.mapper.ts +++ /dev/null @@ -1,418 +0,0 @@ -import { - type ISequelizeDomainMapper, - type MapperParamsType, - SequelizeDomainMapper, -} from "@erp/core/api"; -import { - CurrencyCode, - LanguageCode, - Percentage, - TextValue, - UniqueID, - UtcDate, - ValidationErrorCollection, - type ValidationErrorDetail, - extractOrPushError, - maybeFromNullableResult, - maybeToNullable, -} from "@repo/rdx-ddd"; -import { Maybe, Result, isNullishOrEmpty } from "@repo/rdx-utils"; - -import { - CustomerInvoiceItems, - InvoiceNumber, - InvoicePaymentMethod, - InvoiceSerie, - InvoiceStatus, - Proforma, - type ProformaCreateProps, -} from "../../../../../../domain"; -import type { - CustomerInvoiceCreationAttributes, - CustomerInvoiceModel, -} from "../../../../sequelize"; - -import { CustomerInvoiceItemDomainMapper } from "./customer-invoice-item.mapper"; -import { CustomerInvoiceTaxesDomainMapper } from "./customer-invoice-taxes.mapper"; -import { InvoiceRecipientDomainMapper } from "./invoice-recipient.mapper"; -import { CustomerInvoiceVerifactuDomainMapper } from "./invoice-verifactu.mapper"; - -export interface ICustomerInvoiceDomainMapper - extends ISequelizeDomainMapper< - CustomerInvoiceModel, - CustomerInvoiceCreationAttributes, - Proforma - > {} - -export class CustomerInvoiceDomainMapper - extends SequelizeDomainMapper - implements ICustomerInvoiceDomainMapper -{ - private _itemsMapper: CustomerInvoiceItemDomainMapper; - private _recipientMapper: InvoiceRecipientDomainMapper; - private _taxesMapper: CustomerInvoiceTaxesDomainMapper; - private _verifactuMapper: CustomerInvoiceVerifactuDomainMapper; - - constructor(params: MapperParamsType) { - super(); - - this._itemsMapper = new CustomerInvoiceItemDomainMapper(params); // Instanciar el mapper de items - this._recipientMapper = new InvoiceRecipientDomainMapper(); - this._taxesMapper = new CustomerInvoiceTaxesDomainMapper(params); - this._verifactuMapper = new CustomerInvoiceVerifactuDomainMapper(); - } - - private _mapAttributesToDomain(source: CustomerInvoiceModel, params?: MapperParamsType) { - const { errors } = params as { - errors: ValidationErrorDetail[]; - }; - - const invoiceId = extractOrPushError(UniqueID.create(source.id), "id", errors); - const companyId = extractOrPushError(UniqueID.create(source.company_id), "company_id", errors); - - const customerId = extractOrPushError( - UniqueID.create(source.customer_id), - "customer_id", - errors - ); - - const isProforma = Boolean(source.is_proforma); - - const proformaId = extractOrPushError( - maybeFromNullableResult(source.proforma_id, (v) => UniqueID.create(v)), - "proforma_id", - errors - ); - - const status = extractOrPushError(InvoiceStatus.create(source.status), "status", errors); - - const series = extractOrPushError( - maybeFromNullableResult(source.series, (v) => InvoiceSerie.create(v)), - "series", - errors - ); - - const invoiceNumber = extractOrPushError( - InvoiceNumber.create(source.invoice_number), - "invoice_number", - errors - ); - - // Fechas - const invoiceDate = extractOrPushError( - UtcDate.createFromISO(source.invoice_date), - "invoice_date", - errors - ); - - const operationDate = extractOrPushError( - maybeFromNullableResult(source.operation_date, (v) => UtcDate.createFromISO(v)), - "operation_date", - errors - ); - - // Idioma / divisa - const languageCode = extractOrPushError( - LanguageCode.create(source.language_code), - "language_code", - errors - ); - - const currencyCode = extractOrPushError( - CurrencyCode.create(source.currency_code), - "currency_code", - errors - ); - - // Textos opcionales - const reference = extractOrPushError( - maybeFromNullableResult(source.reference, (value) => Result.ok(String(value))), - "reference", - errors - ); - - const description = extractOrPushError( - maybeFromNullableResult(source.description, (value) => Result.ok(String(value))), - "description", - errors - ); - - const notes = extractOrPushError( - maybeFromNullableResult(source.notes, (value) => TextValue.create(value)), - "notes", - errors - ); - - // M茅todo de pago (VO opcional con id + descripci贸n) - let paymentMethod = Maybe.none(); - - if (!isNullishOrEmpty(source.payment_method_id)) { - const paymentId = extractOrPushError( - UniqueID.create(String(source.payment_method_id)), - "paymentMethod.id", - errors - ); - - const paymentVO = extractOrPushError( - InvoicePaymentMethod.create( - { paymentDescription: String(source.payment_method_description ?? "") }, - paymentId ?? undefined - ), - "payment_method_description", - errors - ); - - if (paymentVO) { - paymentMethod = Maybe.some(paymentVO); - } - } - - // % descuento (VO) - const discountPercentage = extractOrPushError( - Percentage.create({ - value: Number(source.discount_percentage_value ?? 0), - scale: Number(source.discount_percentage_scale ?? 2), - }), - "discount_percentage_value", - errors - ); - - return { - invoiceId, - companyId, - customerId, - isProforma, - proformaId, - status, - series, - invoiceNumber, - invoiceDate, - operationDate, - reference, - description, - notes, - languageCode, - currencyCode, - discountPercentage, - paymentMethod, - }; - } - - public mapToDomain( - source: CustomerInvoiceModel, - params?: MapperParamsType - ): Result { - try { - const errors: ValidationErrorDetail[] = []; - - // 1) Valores escalares (atributos generales) - const attributes = this._mapAttributesToDomain(source, { errors, ...params }); - - // 2) Recipient (snapshot en la factura o include) - const recipientResult = this._recipientMapper.mapToDomain(source, { - errors, - attributes, - ...params, - }); - - // 3) Verifactu (snapshot en la factura o include) - const verifactuResult = this._verifactuMapper.mapToDomain(source.verifactu, { - errors, - attributes, - ...params, - }); - - // 4) Items (colecci贸n) - const itemsResults = this._itemsMapper.mapToDomainCollection( - source.items, - source.items.length, - { - errors, - attributes, - ...params, - } - ); - - // 5) Si hubo errores de mapeo, devolvemos colecci贸n de validaci贸n - if (errors.length > 0) { - return Result.fail( - new ValidationErrorCollection("Customer invoice mapping failed [mapToDomain]", errors) - ); - } - - // 6) Construcci贸n del agregado (Dominio) - - const items = CustomerInvoiceItems.create({ - languageCode: attributes.languageCode!, - currencyCode: attributes.currencyCode!, - globalDiscountPercentage: attributes.discountPercentage!, - items: itemsResults.data.getAll(), - }); - - const invoiceProps: ProformaCreateProps = { - companyId: attributes.companyId!, - - isProforma: attributes.isProforma, - proformaId: attributes.proformaId!, - status: attributes.status!, - series: attributes.series!, - invoiceNumber: attributes.invoiceNumber!, - invoiceDate: attributes.invoiceDate!, - operationDate: attributes.operationDate!, - - customerId: attributes.customerId!, - recipient: recipientResult.data, - - reference: attributes.reference!, - description: attributes.description!, - notes: attributes.notes!, - - languageCode: attributes.languageCode!, - currencyCode: attributes.currencyCode!, - - discountPercentage: attributes.discountPercentage!, - - paymentMethod: attributes.paymentMethod!, - - items, - verifactu: verifactuResult.data, - }; - - const createResult = Proforma.create(invoiceProps, attributes.invoiceId); - - if (createResult.isFailure) { - return Result.fail( - new ValidationErrorCollection("Customer invoice entity creation failed", [ - { path: "invoice", message: createResult.error.message }, - ]) - ); - } - - return Result.ok(createResult.data); - } catch (err: unknown) { - return Result.fail(err as Error); - } - } - - public mapToPersistence( - source: Proforma, - params?: MapperParamsType - ): Result { - const errors: ValidationErrorDetail[] = []; - - // 1) Items - const itemsResult = this._itemsMapper.mapToPersistenceArray(source.items, { - errors, - parent: source, - ...params, - }); - - if (itemsResult.isFailure) { - errors.push({ - path: "items", - message: itemsResult.error.message, - }); - } - - // 2) Taxes - const taxesResult = this._taxesMapper.mapToPersistenceArray(source.getTaxes(), { - errors, - parent: source, - ...params, - }); - - if (taxesResult.isFailure) { - errors.push({ - path: "taxes", - message: taxesResult.error.message, - }); - } - - // 3) Cliente - const recipient = this._recipientMapper.mapToPersistence(source.recipient, { - errors, - parent: source, - ...params, - }); - - // 4) Verifactu - const verifactuResult = this._verifactuMapper.mapToPersistence(source.verifactu, { - errors, - parent: source, - ...params, - }); - - // 5) Si hubo errores de mapeo, devolvemos colecci贸n de validaci贸n - if (errors.length > 0) { - return Result.fail( - new ValidationErrorCollection("Customer invoice mapping to persistence failed", errors) - ); - } - - const items = itemsResult.data; - const taxes = taxesResult.data; - const verifactu = verifactuResult.data; - - const allAmounts = source.calculateAllAmounts(); // Da los totales ya calculados - - const invoiceValues: Partial = { - // Identificaci贸n - id: source.id.toPrimitive(), - company_id: source.companyId.toPrimitive(), - - // Flags / estado / serie / n煤mero - is_proforma: source.isProforma, - proforma_id: maybeToNullable(source.proformaId, (v) => v.toPrimitive()), - status: source.status.toPrimitive(), - series: maybeToNullable(source.series, (v) => v.toPrimitive()), - invoice_number: source.invoiceNumber.toPrimitive(), - - invoice_date: source.invoiceDate.toPrimitive(), - operation_date: maybeToNullable(source.operationDate, (v) => v.toPrimitive()), - language_code: source.languageCode.toPrimitive(), - currency_code: source.currencyCode.toPrimitive(), - - reference: maybeToNullable(source.reference, (reference) => reference), - description: maybeToNullable(source.description, (description) => description), - notes: maybeToNullable(source.notes, (v) => v.toPrimitive()), - - subtotal_amount_value: allAmounts.subtotalAmount.value, - subtotal_amount_scale: allAmounts.subtotalAmount.scale, - - discount_percentage_value: source.globalDiscountPercentage.toPrimitive().value, - discount_percentage_scale: source.globalDiscountPercentage.toPrimitive().scale, - - discount_amount_value: allAmounts.globalDiscountAmount.value, - discount_amount_scale: allAmounts.globalDiscountAmount.scale, - - taxable_amount_value: allAmounts.taxableAmount.value, - taxable_amount_scale: allAmounts.taxableAmount.scale, - - taxes_amount_value: allAmounts.taxesAmount.value, - taxes_amount_scale: allAmounts.taxesAmount.scale, - - total_amount_value: allAmounts.totalAmount.value, - total_amount_scale: allAmounts.totalAmount.scale, - - payment_method_id: maybeToNullable( - source.paymentMethod, - (payment) => payment.toObjectString().id - ), - payment_method_description: maybeToNullable( - source.paymentMethod, - (payment) => payment.toObjectString().payment_description - ), - - customer_id: source.customerId.toPrimitive(), - ...recipient, - - taxes, - items, - verifactu, - }; - - return Result.ok( - invoiceValues as CustomerInvoiceCreationAttributes - ); - } -} diff --git a/modules/customer-invoices/src/api/infrastructure/common/persistence/sequelize/mappers/domain/index.ts b/modules/customer-invoices/src/api/infrastructure/common/persistence/sequelize/mappers/domain/index.ts deleted file mode 100644 index 5d78e8fc..00000000 --- a/modules/customer-invoices/src/api/infrastructure/common/persistence/sequelize/mappers/domain/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from "./customer-invoice.mapper"; diff --git a/modules/customer-invoices/src/api/infrastructure/common/persistence/sequelize/mappers/domain/invoice-recipient.mapper.ts b/modules/customer-invoices/src/api/infrastructure/common/persistence/sequelize/mappers/domain/invoice-recipient.mapper.ts deleted file mode 100644 index 74e63989..00000000 --- a/modules/customer-invoices/src/api/infrastructure/common/persistence/sequelize/mappers/domain/invoice-recipient.mapper.ts +++ /dev/null @@ -1,182 +0,0 @@ -import type { MapperParamsType } from "@erp/core/api"; -import { - City, - Country, - Name, - PostalCode, - Province, - Street, - TINNumber, - ValidationErrorCollection, - type ValidationErrorDetail, - extractOrPushError, - maybeFromNullableResult, - maybeToNullable, -} from "@repo/rdx-ddd"; -import { Maybe, Result } from "@repo/rdx-utils"; - -import { - InvoiceRecipient, - type Proforma, - type ProformaCreateProps, -} from "../../../../../../domain"; -import type { CustomerInvoiceModel } from "../../../../sequelize"; - -export class InvoiceRecipientDomainMapper { - public mapToDomain( - source: CustomerInvoiceModel, - params?: MapperParamsType - ): Result, Error> { - /** - * - Factura === proforma -> datos de "current_customer" - * - Factura !== proforma -> snapshot de los datos (campos customer_*) - */ - - const { errors, attributes } = params as { - errors: ValidationErrorDetail[]; - attributes: Partial; - }; - - const { isProforma } = attributes; - - if (isProforma && !source.current_customer) { - errors.push({ - path: "current_customer", - message: "Current customer not included in query (InvoiceRecipientMapper)", - }); - } - - const _name = isProforma ? source.current_customer.name : source.customer_name!; - const _tin = isProforma ? source.current_customer.tin : source.customer_tin!; - const _street = isProforma ? source.current_customer.street : source.customer_street!; - const _street2 = isProforma ? source.current_customer.street2 : source.customer_street2!; - const _city = isProforma ? source.current_customer.city : source.customer_city!; - const _postal_code = isProforma - ? source.current_customer.postal_code - : source.customer_postal_code!; - const _province = isProforma ? source.current_customer.province : source.customer_province!; - const _country = isProforma ? source.current_customer.country : source.customer_country!; - - // Customer (snapshot) - const customerName = extractOrPushError(Name.create(_name!), "customer_name", errors); - - const customerTin = extractOrPushError(TINNumber.create(_tin!), "customer_tin", errors); - - const customerStreet = extractOrPushError( - maybeFromNullableResult(_street, (value) => Street.create(value)), - "customer_street", - errors - ); - - const customerStreet2 = extractOrPushError( - maybeFromNullableResult(_street2, (value) => Street.create(value)), - "customer_street2", - errors - ); - - const customerCity = extractOrPushError( - maybeFromNullableResult(_city, (value) => City.create(value)), - "customer_city", - errors - ); - - const customerProvince = extractOrPushError( - maybeFromNullableResult(_province, (value) => Province.create(value)), - "customer_province", - errors - ); - - const customerPostalCode = extractOrPushError( - maybeFromNullableResult(_postal_code, (value) => PostalCode.create(value)), - "customer_postal_code", - errors - ); - - const customerCountry = extractOrPushError( - maybeFromNullableResult(_country, (value) => Country.create(value)), - "customer_country", - errors - ); - - const createResult = InvoiceRecipient.create({ - name: customerName!, - tin: customerTin!, - street: customerStreet!, - street2: customerStreet2!, - city: customerCity!, - postalCode: customerPostalCode!, - province: customerProvince!, - country: customerCountry!, - }); - - if (createResult.isFailure) { - return Result.fail( - new ValidationErrorCollection("Invoice recipient entity creation failed", [ - { path: "recipient", message: createResult.error.message }, - ]) - ); - } - - return Result.ok(Maybe.some(createResult.data)); - } - - /** - * Mapea los datos del destinatario (recipient) de una factura de cliente - * al formato esperado por la capa de persistencia. - * - * Reglas: - * - Si la factura es proforma (`isProforma === true`), todos los campos de recipient son `null`. - * - Si la factura no es proforma (`isProforma === false`), debe existir `recipient`. - * En caso contrario, se agrega un error de validaci贸n. - */ - mapToPersistence(source: Maybe, params?: MapperParamsType) { - const { errors, parent } = params as { - parent: Proforma; - errors: ValidationErrorDetail[]; - }; - - const { isProforma, hasRecipient } = parent; - - // Validaci贸n: facturas emitidas deben tener destinatario. - if (!(isProforma || hasRecipient)) { - errors.push({ - path: "recipient", - message: "[CustomerInvoiceDomainMapper] Issued customer invoice without recipient data", - }); - } - - // Si hay errores previos, devolvemos fallo de validaci贸n inmediatamente. - if (errors.length > 0) { - return Result.fail( - new ValidationErrorCollection("Customer invoice mapping to persistence failed", errors) - ); - } - - // Si es proforma o no hay destinatario, todos los campos deben ser null. - if (isProforma || source.isNone()) { - return { - customer_tin: null, - customer_name: null, - customer_street: null, - customer_street2: null, - customer_city: null, - customer_province: null, - customer_postal_code: null, - customer_country: null, - }; - } - - const recipient = source.unwrap(); - - return { - customer_tin: recipient.tin.toPrimitive(), - customer_name: recipient.name.toPrimitive(), - customer_street: maybeToNullable(recipient.street, (v) => v.toPrimitive()), - customer_street2: maybeToNullable(recipient.street2, (v) => v.toPrimitive()), - customer_city: maybeToNullable(recipient.city, (v) => v.toPrimitive()), - customer_province: maybeToNullable(recipient.province, (v) => v.toPrimitive()), - customer_postal_code: maybeToNullable(recipient.postalCode, (v) => v.toPrimitive()), - customer_country: maybeToNullable(recipient.country, (v) => v.toPrimitive()), - }; - } -} diff --git a/modules/customer-invoices/src/api/infrastructure/common/persistence/sequelize/mappers/domain/invoice-verifactu.mapper.ts b/modules/customer-invoices/src/api/infrastructure/common/persistence/sequelize/mappers/domain/invoice-verifactu.mapper.ts deleted file mode 100644 index bdfe1d90..00000000 --- a/modules/customer-invoices/src/api/infrastructure/common/persistence/sequelize/mappers/domain/invoice-verifactu.mapper.ts +++ /dev/null @@ -1,145 +0,0 @@ -import type { MapperParamsType } from "@erp/core/api"; -import { type ISequelizeDomainMapper, SequelizeDomainMapper } from "@erp/core/api"; -import { - URLAddress, - UniqueID, - ValidationErrorCollection, - type ValidationErrorDetail, - extractOrPushError, - maybeFromNullableResult, - maybeToEmptyString, -} from "@repo/rdx-ddd"; -import { Maybe, Result } from "@repo/rdx-utils"; - -import { - type Proforma, - type ProformaCreateProps, - VerifactuRecord, - VerifactuRecordEstado, -} from "../../../../../../domain"; -import type { - VerifactuRecordCreationAttributes, - VerifactuRecordModel, -} from "../../../../sequelize"; - -export interface ICustomerInvoiceVerifactuDomainMapper - extends ISequelizeDomainMapper< - VerifactuRecordModel, - VerifactuRecordCreationAttributes, - Maybe - > {} - -export class CustomerInvoiceVerifactuDomainMapper - extends SequelizeDomainMapper< - VerifactuRecordModel, - VerifactuRecordCreationAttributes, - Maybe - > - implements ICustomerInvoiceVerifactuDomainMapper -{ - public mapToDomain( - source: VerifactuRecordModel, - params?: MapperParamsType - ): Result, Error> { - const { errors, attributes } = params as { - errors: ValidationErrorDetail[]; - attributes: Partial; - }; - - if (!source) { - return Result.ok(Maybe.none()); - } - - const recordId = extractOrPushError(UniqueID.create(source.id), "id", errors); - const estado = extractOrPushError( - VerifactuRecordEstado.create(source.estado), - "estado", - errors - ); - - const qr = extractOrPushError( - maybeFromNullableResult(source.qr, (value) => Result.ok(String(value))), - "qr", - errors - ); - - const url = extractOrPushError( - maybeFromNullableResult(source.url, (value) => URLAddress.create(value)), - "url", - errors - ); - - const uuid = extractOrPushError( - maybeFromNullableResult(source.uuid, (value) => Result.ok(String(value))), - "uuid", - errors - ); - - const operacion = extractOrPushError( - maybeFromNullableResult(source.operacion, (value) => Result.ok(String(value))), - "operacion", - errors - ); - - if (errors.length > 0) { - return Result.fail( - new ValidationErrorCollection("Verifactu record mapping failed [mapToDTO]", errors) - ); - } - - const createResult = VerifactuRecord.create( - { - estado: estado!, - qrCode: qr!, - url: url!, - uuid: uuid!, - operacion: operacion!, - }, - recordId! - ); - - if (createResult.isFailure) { - return Result.fail( - new ValidationErrorCollection("Invoice verifactu entity creation failed", [ - { path: "verifactu", message: createResult.error.message }, - ]) - ); - } - - return Result.ok(Maybe.some(createResult.data)); - } - - mapToPersistence( - source: Maybe, - params?: MapperParamsType - ): Result { - const { errors, parent } = params as { - parent: Proforma; - errors: ValidationErrorDetail[]; - }; - - if (source.isNone()) { - return Result.ok({ - id: UniqueID.generateNewID().toPrimitive(), - invoice_id: parent.id.toPrimitive(), - estado: VerifactuRecordEstado.createPendiente().toPrimitive(), - qr: "", - url: "", - uuid: "", - operacion: "", - }); - } - - const verifactu = source.unwrap(); - - return Result.ok({ - id: verifactu.id.toPrimitive(), - invoice_id: parent.id.toPrimitive(), - estado: verifactu.estado.toPrimitive(), - qr: maybeToEmptyString(verifactu.qrCode, (v) => v), - url: maybeToEmptyString(verifactu.url, (v) => v.toPrimitive()), - uuid: maybeToEmptyString(verifactu.uuid, (v) => v), - operacion: maybeToEmptyString(verifactu.operacion, (v) => v), - }); - } -} diff --git a/modules/customer-invoices/src/api/infrastructure/common/persistence/sequelize/mappers/index.ts b/modules/customer-invoices/src/api/infrastructure/common/persistence/sequelize/mappers/index.ts deleted file mode 100644 index 9b0ff906..00000000 --- a/modules/customer-invoices/src/api/infrastructure/common/persistence/sequelize/mappers/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from "./domain"; -export * from "./list"; diff --git a/modules/customer-invoices/src/api/infrastructure/common/persistence/sequelize/mappers/list/customer-invoice.list.mapper.ts b/modules/customer-invoices/src/api/infrastructure/common/persistence/sequelize/mappers/list/customer-invoice.list.mapper.ts deleted file mode 100644 index 6038e365..00000000 --- a/modules/customer-invoices/src/api/infrastructure/common/persistence/sequelize/mappers/list/customer-invoice.list.mapper.ts +++ /dev/null @@ -1,293 +0,0 @@ -import { - type ISequelizeQueryMapper, - type MapperParamsType, - SequelizeQueryMapper, -} from "@erp/core/api"; -import { - CurrencyCode, - LanguageCode, - Percentage, - UniqueID, - UtcDate, - ValidationErrorCollection, - type ValidationErrorDetail, - extractOrPushError, - maybeFromNullableResult, -} from "@repo/rdx-ddd"; -import { Maybe, Result } from "@repo/rdx-utils"; - -import { - InvoiceAmount, - InvoiceNumber, - type InvoiceRecipient, - InvoiceSerie, - InvoiceStatus, - type VerifactuRecord, -} from "../../../../../../domain"; -import type { CustomerInvoiceModel } from "../../../../sequelize"; - -import { InvoiceRecipientListMapper } from "./invoice-recipient.list.mapper"; -import { VerifactuRecordListMapper } from "./verifactu-record.list.mapper"; - -export type CustomerInvoiceListDTO = { - id: UniqueID; - companyId: UniqueID; - - isProforma: boolean; - invoiceNumber: InvoiceNumber; - status: InvoiceStatus; - series: Maybe; - - invoiceDate: UtcDate; - operationDate: Maybe; - - reference: Maybe; - description: Maybe; - - customerId: UniqueID; - recipient: InvoiceRecipient; - - languageCode: LanguageCode; - currencyCode: CurrencyCode; - - discountPercentage: Percentage; - - subtotalAmount: InvoiceAmount; - discountAmount: InvoiceAmount; - taxableAmount: InvoiceAmount; - taxesAmount: InvoiceAmount; - totalAmount: InvoiceAmount; - - verifactu: Maybe; -}; - -export interface ICustomerInvoiceListMapper - extends ISequelizeQueryMapper {} - -export class CustomerInvoiceListMapper - extends SequelizeQueryMapper - implements ICustomerInvoiceListMapper -{ - private _recipientMapper: InvoiceRecipientListMapper; - private _verifactuMapper: VerifactuRecordListMapper; - - constructor() { - super(); - this._recipientMapper = new InvoiceRecipientListMapper(); - this._verifactuMapper = new VerifactuRecordListMapper(); - } - - public mapToDTO( - raw: CustomerInvoiceModel, - params?: MapperParamsType - ): Result { - const errors: ValidationErrorDetail[] = []; - - // 1) Valores escalares (atributos generales) - const attributes = this.mapAttributesToDTO(raw, { errors, ...params }); - - // 2) Recipient (snapshot en la factura o include) - const recipientResult = this._recipientMapper.mapToDTO(raw, { - errors, - attributes, - ...params, - }); - - if (recipientResult.isFailure) { - errors.push({ - path: "recipient", - message: recipientResult.error.message, - }); - } - - // 4) Verifactu record - let verifactu: Maybe = Maybe.none(); - if (raw.verifactu) { - const verifactuResult = this._verifactuMapper.mapToDTO(raw.verifactu, { errors, ...params }); - - if (verifactuResult.isFailure) { - errors.push({ - path: "verifactu", - message: verifactuResult.error.message, - }); - } else { - verifactu = Maybe.some(verifactuResult.data); - } - } - - // 5) Si hubo errores de mapeo, devolvemos colecci贸n de validaci贸n - if (errors.length > 0) { - return Result.fail( - new ValidationErrorCollection("Customer invoice mapping failed [mapToDTO]", errors) - ); - } - - return Result.ok({ - id: attributes.invoiceId!, - companyId: attributes.companyId!, - isProforma: attributes.isProforma, - status: attributes.status!, - series: attributes.series!, - invoiceNumber: attributes.invoiceNumber!, - invoiceDate: attributes.invoiceDate!, - operationDate: attributes.operationDate!, - - description: attributes.description!, - reference: attributes.description!, - - customerId: attributes.customerId!, - recipient: recipientResult.data, - - languageCode: attributes.languageCode!, - currencyCode: attributes.currencyCode!, - - discountPercentage: attributes.discountPercentage!, - subtotalAmount: attributes.subtotalAmount!, - discountAmount: attributes.discountAmount!, - taxableAmount: attributes.taxableAmount!, - taxesAmount: attributes.taxesAmount!, - totalAmount: attributes.totalAmount!, - - verifactu, - }); - } - - private mapAttributesToDTO(raw: CustomerInvoiceModel, params?: MapperParamsType) { - const { errors } = params as { - errors: ValidationErrorDetail[]; - }; - - const invoiceId = extractOrPushError(UniqueID.create(raw.id), "id", errors); - const companyId = extractOrPushError(UniqueID.create(raw.company_id), "company_id", errors); - - const customerId = extractOrPushError(UniqueID.create(raw.customer_id), "customer_id", errors); - - const isProforma = Boolean(raw.is_proforma); - - const status = extractOrPushError(InvoiceStatus.create(raw.status), "status", errors); - - const series = extractOrPushError( - maybeFromNullableResult(raw.series, (value) => InvoiceSerie.create(value)), - "serie", - errors - ); - - const invoiceNumber = extractOrPushError( - InvoiceNumber.create(raw.invoice_number), - "invoice_number", - errors - ); - - const invoiceDate = extractOrPushError( - UtcDate.createFromISO(raw.invoice_date), - "invoice_date", - errors - ); - - const operationDate = extractOrPushError( - maybeFromNullableResult(raw.operation_date, (value) => UtcDate.createFromISO(value)), - "operation_date", - errors - ); - - const reference = extractOrPushError( - maybeFromNullableResult(raw.reference, (value) => Result.ok(String(value))), - "description", - errors - ); - - const description = extractOrPushError( - maybeFromNullableResult(raw.description, (value) => Result.ok(String(value))), - "description", - errors - ); - - const languageCode = extractOrPushError( - LanguageCode.create(raw.language_code), - "language_code", - errors - ); - - const currencyCode = extractOrPushError( - CurrencyCode.create(raw.currency_code), - "currency_code", - errors - ); - - const discountPercentage = extractOrPushError( - Percentage.create({ - value: raw.discount_percentage_value, - scale: raw.discount_percentage_scale, - }), - "discount_percentage_value", - errors - ); - - const subtotalAmount = extractOrPushError( - InvoiceAmount.create({ - value: raw.subtotal_amount_value, - currency_code: currencyCode?.code, - }), - "subtotal_amount_value", - errors - ); - - const discountAmount = extractOrPushError( - InvoiceAmount.create({ - value: raw.discount_amount_value, - currency_code: currencyCode?.code, - }), - "discount_amount_value", - errors - ); - - const taxableAmount = extractOrPushError( - InvoiceAmount.create({ - value: raw.taxable_amount_value, - currency_code: currencyCode?.code, - }), - "taxable_amount_value", - errors - ); - - const taxesAmount = extractOrPushError( - InvoiceAmount.create({ - value: raw.taxes_amount_value, - currency_code: currencyCode?.code, - }), - "taxes_amount_value", - errors - ); - - const totalAmount = extractOrPushError( - InvoiceAmount.create({ - value: raw.total_amount_value, - currency_code: currencyCode?.code, - }), - "total_amount_value", - errors - ); - - return { - invoiceId, - companyId, - customerId, - isProforma, - status, - series, - invoiceNumber, - invoiceDate, - operationDate, - reference, - description, - languageCode, - currencyCode, - discountPercentage, - subtotalAmount, - discountAmount, - taxableAmount, - taxesAmount, - totalAmount, - }; - } -} diff --git a/modules/customer-invoices/src/api/infrastructure/common/persistence/sequelize/mappers/list/index.ts b/modules/customer-invoices/src/api/infrastructure/common/persistence/sequelize/mappers/list/index.ts deleted file mode 100644 index 5bbb658a..00000000 --- a/modules/customer-invoices/src/api/infrastructure/common/persistence/sequelize/mappers/list/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from "./customer-invoice.list.mapper"; diff --git a/modules/customer-invoices/src/api/infrastructure/common/persistence/sequelize/mappers/list/invoice-recipient.list.mapper.ts b/modules/customer-invoices/src/api/infrastructure/common/persistence/sequelize/mappers/list/invoice-recipient.list.mapper.ts deleted file mode 100644 index 68abd1a8..00000000 --- a/modules/customer-invoices/src/api/infrastructure/common/persistence/sequelize/mappers/list/invoice-recipient.list.mapper.ts +++ /dev/null @@ -1,116 +0,0 @@ -import { - type IQueryMapperWithBulk, - type MapperParamsType, - SequelizeQueryMapper, -} from "@erp/core/api"; -import { - City, - Country, - Name, - PostalCode, - Province, - Street, - TINNumber, - type ValidationErrorDetail, - extractOrPushError, - maybeFromNullableResult, -} from "@repo/rdx-ddd"; -import type { Result } from "@repo/rdx-utils"; - -import { InvoiceRecipient } from "../../../../../../domain"; -import type { CustomerInvoiceModel } from "../../../../sequelize"; - -import type { CustomerInvoiceListDTO } from "./customer-invoice.list.mapper"; - -interface IInvoiceRecipientListMapper - extends IQueryMapperWithBulk {} - -export class InvoiceRecipientListMapper - extends SequelizeQueryMapper - implements IInvoiceRecipientListMapper -{ - public mapToDTO( - raw: CustomerInvoiceModel, - params?: MapperParamsType - ): Result { - /** - * - Factura === proforma -> datos de "current_customer" - * - Factura !== proforma -> snapshot de los datos (campos customer_*) - */ - - const { errors, attributes } = params as { - errors: ValidationErrorDetail[]; - attributes: Partial; - }; - - const { isProforma } = attributes; - - if (isProforma && !raw.current_customer) { - errors.push({ - path: "current_customer", - message: "Current customer not included in query (InvoiceRecipientListMapper)", - }); - } - - const _name = isProforma ? raw.current_customer.name! : raw.customer_name!; - const _tin = isProforma ? raw.current_customer.tin! : raw.customer_tin!; - const _street = isProforma ? raw.current_customer.street : raw.customer_street; - const _street2 = isProforma ? raw.current_customer.street2 : raw.customer_street2; - const _city = isProforma ? raw.current_customer.city : raw.customer_city; - const _postal_code = isProforma ? raw.current_customer.postal_code : raw.customer_postal_code; - const _province = isProforma ? raw.current_customer.province : raw.customer_province; - const _country = isProforma ? raw.current_customer.country : raw.customer_country; - - // Customer (snapshot) - const customerName = extractOrPushError(Name.create(_name), "customer_name", errors); - - const customerTin = extractOrPushError(TINNumber.create(_tin), "customer_tin", errors); - - const customerStreet = extractOrPushError( - maybeFromNullableResult(_street, (value) => Street.create(value)), - "customer_street", - errors - ); - - const customerStreet2 = extractOrPushError( - maybeFromNullableResult(_street2, (value) => Street.create(value)), - "customer_street2", - errors - ); - - const customerCity = extractOrPushError( - maybeFromNullableResult(_city, (value) => City.create(value)), - "customer_city", - errors - ); - - const customerProvince = extractOrPushError( - maybeFromNullableResult(_province, (value) => Province.create(value)), - "customer_province", - errors - ); - - const customerPostalCode = extractOrPushError( - maybeFromNullableResult(_postal_code, (value) => PostalCode.create(value)), - "customer_postal_code", - errors - ); - - const customerCountry = extractOrPushError( - maybeFromNullableResult(_country, (value) => Country.create(value)), - "customer_country", - errors - ); - - return InvoiceRecipient.create({ - name: customerName!, - tin: customerTin!, - street: customerStreet!, - street2: customerStreet2!, - city: customerCity!, - postalCode: customerPostalCode!, - province: customerProvince!, - country: customerCountry!, - }); - } -} diff --git a/modules/customer-invoices/src/api/infrastructure/common/persistence/sequelize/mappers/list/verifactu-record.list.mapper.ts b/modules/customer-invoices/src/api/infrastructure/common/persistence/sequelize/mappers/list/verifactu-record.list.mapper.ts deleted file mode 100644 index c44fc52b..00000000 --- a/modules/customer-invoices/src/api/infrastructure/common/persistence/sequelize/mappers/list/verifactu-record.list.mapper.ts +++ /dev/null @@ -1,78 +0,0 @@ -import { - type ISequelizeQueryMapper, - type MapperParamsType, - SequelizeQueryMapper, -} from "@erp/core/api"; -import { - URLAddress, - UniqueID, - ValidationErrorCollection, - type ValidationErrorDetail, - extractOrPushError, - maybeFromNullableResult, -} from "@repo/rdx-ddd"; -import { Result } from "@repo/rdx-utils"; - -import { VerifactuRecord, VerifactuRecordEstado } from "../../../../../../domain"; -import type { VerifactuRecordModel } from "../../../../sequelize"; - -export interface IVerifactuRecordListMapper - extends ISequelizeQueryMapper { - // -} - -export class VerifactuRecordListMapper - extends SequelizeQueryMapper - implements IVerifactuRecordListMapper -{ - public mapToDTO( - raw: VerifactuRecordModel, - params?: MapperParamsType - ): Result { - const errors: ValidationErrorDetail[] = []; - - const recordId = extractOrPushError(UniqueID.create(raw.id), "id", errors); - const estado = extractOrPushError(VerifactuRecordEstado.create(raw.estado), "estado", errors); - - const qr = extractOrPushError( - maybeFromNullableResult(raw.qr, (value) => Result.ok(String(value))), - "qr", - errors - ); - - const url = extractOrPushError( - maybeFromNullableResult(raw.url, (value) => URLAddress.create(value)), - "url", - errors - ); - - const uuid = extractOrPushError( - maybeFromNullableResult(raw.uuid, (value) => Result.ok(String(value))), - "uuid", - errors - ); - - const operacion = extractOrPushError( - maybeFromNullableResult(raw.operacion, (value) => Result.ok(String(value))), - "operacion", - errors - ); - - if (errors.length > 0) { - return Result.fail( - new ValidationErrorCollection("Verifactu record mapping failed [mapToDTO]", errors) - ); - } - - return VerifactuRecord.create( - { - estado: estado!, - qrCode: qr!, - url: url!, - uuid: uuid!, - operacion: operacion!, - }, - recordId! - ); - } -}