88 lines
3.0 KiB
TypeScript
88 lines
3.0 KiB
TypeScript
import { UniqueID, type UtcDate } from "@repo/rdx-ddd";
|
|
import { Maybe, Result } from "@repo/rdx-utils";
|
|
|
|
import { CustomerInvoice } from "../aggregates";
|
|
import { VerifactuRecord } from "../entities";
|
|
import { EntityIsNotProformaError, ProformaCannotBeConvertedToInvoiceError } from "../errors";
|
|
import {
|
|
CustomerInvoiceIsProformaSpecification,
|
|
ProformaCanTranstionToIssuedSpecification,
|
|
} from "../specs";
|
|
import {
|
|
type CustomerInvoiceNumber,
|
|
CustomerInvoiceStatus,
|
|
VerifactuRecordEstado,
|
|
} from "../value-objects";
|
|
|
|
/**
|
|
* Servicio de dominio que encapsula la lógica de emisión de factura definitiva desde una proforma.
|
|
*/
|
|
export class IssueCustomerInvoiceDomainService {
|
|
private readonly isProformaSpec = new CustomerInvoiceIsProformaSpecification();
|
|
private readonly isApprovedSpec = new ProformaCanTranstionToIssuedSpecification();
|
|
|
|
/**
|
|
* Convierte una proforma en factura definitiva.
|
|
*
|
|
* @param proforma - Entidad CustomerInvoice en estado proforma aprobada.
|
|
* @param params.issueNumber - Número de la nueva factura.
|
|
* @param params.issueDate - Fecha de emisión.
|
|
* @returns Result<CustomerInvoice, Error> - Nueva factura emitida o error de dominio.
|
|
*/
|
|
public async issueFromProforma(
|
|
proforma: CustomerInvoice,
|
|
params: {
|
|
issueNumber: CustomerInvoiceNumber;
|
|
issueDate: UtcDate;
|
|
}
|
|
): Promise<Result<CustomerInvoice, Error>> {
|
|
const { issueDate, issueNumber } = params;
|
|
|
|
/** 1. Validar que la entidad origen es una proforma */
|
|
if (!(await this.isProformaSpec.isSatisfiedBy(proforma))) {
|
|
return Result.fail(new EntityIsNotProformaError(proforma.id.toString()));
|
|
}
|
|
|
|
/** 2. Validar que la proforma puede emitirse */
|
|
if (!(await this.isApprovedSpec.isSatisfiedBy(proforma))) {
|
|
return Result.fail(new ProformaCannotBeConvertedToInvoiceError(proforma.id.toString()));
|
|
}
|
|
|
|
const verifactuRecordOrError = VerifactuRecord.create(
|
|
{
|
|
estado: VerifactuRecordEstado.createPendiente(),
|
|
qrCode: Maybe.none(),
|
|
url: Maybe.none(),
|
|
uuid: Maybe.none(),
|
|
operacion: Maybe.none(),
|
|
},
|
|
UniqueID.generateNewID()
|
|
);
|
|
|
|
if (verifactuRecordOrError.isFailure) {
|
|
return Result.fail(new ProformaCannotBeConvertedToInvoiceError(proforma.id.toString()));
|
|
}
|
|
|
|
const verifactuRecord = verifactuRecordOrError.data;
|
|
|
|
/** 3. Generar la nueva factura definitiva (inmutable) */
|
|
const proformaProps = proforma.getProps();
|
|
const newInvoiceOrError = CustomerInvoice.create({
|
|
...proformaProps,
|
|
isProforma: false,
|
|
proformaId: Maybe.some(proforma.id),
|
|
status: CustomerInvoiceStatus.createIssued(),
|
|
invoiceNumber: issueNumber,
|
|
invoiceDate: issueDate,
|
|
description: proformaProps.description.isNone() ? Maybe.some(".") : proformaProps.description,
|
|
verifactu: Maybe.some(verifactuRecord),
|
|
});
|
|
|
|
if (newInvoiceOrError.isFailure) {
|
|
return Result.fail(newInvoiceOrError.error);
|
|
}
|
|
|
|
return Result.ok(newInvoiceOrError.data);
|
|
}
|
|
}
|