Presupuestador_web/server/src/contexts/sales/application/Dealer/CreateDealer.useCase.ts
2024-07-15 17:41:42 +02:00

137 lines
4.2 KiB
TypeScript

import { IUseCase, IUseCaseError, UseCaseError } from "@/contexts/common/application";
import { IRepositoryManager } from "@/contexts/common/domain";
import { IInfrastructureError } from "@/contexts/common/infrastructure";
import { ISequelizeAdapter } from "@/contexts/common/infrastructure/sequelize";
import {
CurrencyData,
DomainError,
ICreateDealer_Request_DTO,
IDomainError,
Language,
Name,
Result,
UniqueID,
ensureIdIsValid,
ensureNameIsValid,
} from "@shared/contexts";
import { Dealer, DealerStatus, IDealerRepository } from "../../domain";
export type CreateDealerResponseOrError =
| Result<never, IUseCaseError> // Misc errors (value objects)
| Result<Dealer, never>; // Success!
export class CreateDealerUseCase
implements IUseCase<ICreateDealer_Request_DTO, Promise<CreateDealerResponseOrError>>
{
private _adapter: ISequelizeAdapter;
private _repositoryManager: IRepositoryManager;
constructor(props: { adapter: ISequelizeAdapter; repositoryManager: IRepositoryManager }) {
this._adapter = props.adapter;
this._repositoryManager = props.repositoryManager;
}
async execute(request: ICreateDealer_Request_DTO) {
const { id, name } = request;
// Validaciones de datos
const idOrError = ensureIdIsValid(id);
if (idOrError.isFailure) {
const message = idOrError.error.message; //`Dealer ID ${dealerDTO.id} is not valid`;
return Result.fail(
UseCaseError.create(UseCaseError.INVALID_INPUT_DATA, message, [{ path: "id" }])
);
}
const nameOrError = ensureNameIsValid(name);
if (nameOrError.isFailure) {
const message = nameOrError.error.message; //`Dealer ID ${dealerDTO.id} is not valid`;
return Result.fail(
UseCaseError.create(UseCaseError.INVALID_INPUT_DATA, message, [{ path: "name" }])
);
}
// Comprobar que no existe un usuario previo con esos datos
const dealerRepository = this._getDealerRepository();
const idExists = await dealerRepository().exists(idOrError.object);
if (idExists) {
const message = `Another dealer with same ID exists`;
return Result.fail(
UseCaseError.create(UseCaseError.RESOURCE_ALREADY_EXITS, message, {
path: "id",
})
);
}
// Crear dealer
const dealerOrError = this._tryCreateDealerInstance(request, idOrError.object);
if (dealerOrError.isFailure) {
const { error: domainError } = dealerOrError;
let errorCode = "";
let message = "";
switch (domainError.code) {
case DomainError.INVALID_INPUT_DATA:
errorCode = UseCaseError.INVALID_INPUT_DATA;
message = "El distribuidor tiene algún dato erróneo.";
break;
default:
errorCode = UseCaseError.UNEXCEPTED_ERROR;
message = domainError.message;
break;
}
return Result.fail(UseCaseError.create(errorCode, message, domainError));
}
return this._saveDealer(dealerOrError.object);
}
private async _saveDealer(dealer: Dealer) {
// Guardar el contacto
const transaction = this._adapter.startTransaction();
const dealerRepository = this._getDealerRepository();
let dealerRepo: IDealerRepository;
try {
await transaction.complete(async (t) => {
dealerRepo = dealerRepository({ transaction: t });
await dealerRepo.create(dealer);
});
return Result.ok<Dealer>(dealer);
} catch (error: unknown) {
const _error = error as IInfrastructureError;
return Result.fail(UseCaseError.create(UseCaseError.REPOSITORY_ERROR, _error.message));
}
}
private _tryCreateDealerInstance(
dealerDTO: ICreateDealer_Request_DTO,
dealerId: UniqueID
): Result<Dealer, IDomainError> {
const nameOrError = Name.create(dealerDTO.name);
if (nameOrError.isFailure) {
return Result.fail(nameOrError.error);
}
return Dealer.create(
{
name: nameOrError.object,
currency: CurrencyData.createDefaultCode().object,
language: Language.createDefaultCode().object,
status: DealerStatus.createActive(),
//user_id: user
},
dealerId
);
}
private _getDealerRepository() {
return this._repositoryManager.getRepository<IDealerRepository>("Dealer");
}
}