Presupuestador_web/server/src/contexts/sales/application/Quote/DuplicateQuote.useCase.ts

131 lines
4.1 KiB
TypeScript

import {
IUseCase,
IUseCaseError,
IUseCaseRequest,
UseCaseError,
} from "@/contexts/common/application/useCases";
import { IRepositoryManager } from "@/contexts/common/domain";
import { ISequelizeAdapter } from "@/contexts/common/infrastructure/sequelize";
import { Collection, IDomainError, Result, UniqueID, UTCDateValue } from "@shared/contexts";
import {
Dealer,
IQuoteRepository,
QuoteCustomerReference,
QuoteItem,
QuoteReference,
QuoteStatus,
} from "../../domain";
import { IInfrastructureError } from "@/contexts/common/infrastructure";
import { SequelizeBusinessTransactionType } from "@/contexts/common/infrastructure/sequelize/SequelizeBusinessTransaction";
import { Quote } from "../../domain/entities/Quotes/Quote";
import { ISalesContext } from "../../infrastructure";
import { findQuoteById, generateQuoteReferenceForDealer } from "../services";
export interface IDuplicateQuoteUseCaseRequest extends IUseCaseRequest {
sourceId: UniqueID;
}
export type DuplicateQuoteResponseOrError =
| Result<never, IUseCaseError> // Misc errors (value objects)
| Result<Quote, never>; // Success!
export class DuplicateQuoteUseCase
implements IUseCase<IDuplicateQuoteUseCaseRequest, Promise<DuplicateQuoteResponseOrError>>
{
private _adapter: ISequelizeAdapter;
private _repositoryManager: IRepositoryManager;
private _dealer: Dealer;
private _transaction: SequelizeBusinessTransactionType;
constructor(context: ISalesContext) {
this._adapter = context.adapter;
this._repositoryManager = context.repositoryManager;
this._dealer = context.dealer!;
}
async execute(request: IDuplicateQuoteUseCaseRequest): Promise<DuplicateQuoteResponseOrError> {
const { sourceId } = request;
const targetId = UniqueID.generateNewID().object;
const transaction = this._adapter.startTransaction();
const QuoteRepoBuilder = this._repositoryManager.getRepository<IQuoteRepository>("Quote");
let sourceQuote: Quote | null = null;
let quoteReference: QuoteReference;
let targetQuoteOrError: Result<Quote, IDomainError>;
// Buscar el quote
try {
return await transaction.complete(async (t) => {
const quoteRepo = QuoteRepoBuilder({ transaction: t });
sourceQuote = await findQuoteById(sourceId, quoteRepo);
if (!sourceQuote) {
return Result.fail(UseCaseError.create(UseCaseError.NOT_FOUND_ERROR, "Quote not found"));
}
// Generate Reference
quoteReference = await generateQuoteReferenceForDealer(this._dealer, quoteRepo);
targetQuoteOrError = this._tryDuplicateQuoteInstance(sourceQuote, targetId, quoteReference);
await quoteRepo.create(targetQuoteOrError.object);
return Result.ok<Quote>(targetQuoteOrError.object);
});
} catch (error: unknown) {
const _error = error as IInfrastructureError;
return Result.fail(UseCaseError.create(UseCaseError.REPOSITORY_ERROR, _error.message));
}
}
private _tryDuplicateQuoteInstance(
sourceQuote: Quote,
targetId: UniqueID,
targetReference: QuoteReference
): Result<Quote, IDomainError> {
const dealerId: UniqueID = this._dealer.id;
const status = QuoteStatus.createDraft();
const date = UTCDateValue.createCurrentDate().object;
const customerReference = QuoteCustomerReference.create("").object;
const dateSent = UTCDateValue.create(null).object;
// items
let items: Collection<QuoteItem>;
try {
items = new Collection<QuoteItem>(
sourceQuote.items.toArray().map((item) => QuoteItem.create(item).object)
);
} catch (e: unknown) {
return Result.fail(e as IDomainError);
}
return Quote.create(
{
status,
date,
reference: targetReference,
language: sourceQuote.language,
customerReference,
customer: sourceQuote.customer,
currency: sourceQuote.currency,
paymentMethod: sourceQuote.paymentMethod,
notes: sourceQuote.notes,
validity: sourceQuote.validity,
discount: sourceQuote.discount,
tax: sourceQuote.tax,
items,
dealerId,
dateSent,
},
targetId
);
}
}