Facturas de cliente

This commit is contained in:
David Arranz 2025-09-12 12:40:52 +02:00
parent c8c71cf91c
commit 56b37c4256
48 changed files with 166 additions and 148 deletions

View File

@ -1,2 +1,3 @@
export * from "./presenter-registry";
export * from "./presenter-registry.interface";
export * from "./presenter.interface";

View File

@ -4,9 +4,8 @@ import { IPresenter } from "./presenter.interface";
* 🔑 Claves de proyección comunes para seleccionar presenters
*/
export type PresenterKey = {
resource: string; // "customer-invoice"
projection: string; //"detail" | "summary" | "created" | "status" | "export";
format: string; //"json" | "pdf" | "csv" | "xml";
projection: "FULL" | "LIST" | "REPORT" | (string & {});
format?: "JSON" | "PDF" | "CSV" | (string & {});
version?: number; // 1 | 2
locale?: string; // es | en | fr
};
@ -53,5 +52,9 @@ export interface IPresenterRegistry {
registerPresenter<TSource, TOutput>(
key: PresenterKey,
presenter: IPresenter<TSource, TOutput>
): void;
): this;
registerPresenters(
presenters: Array<{ key: PresenterKey; presenter: IPresenter<any, any> }>
): this;
}

View File

@ -5,8 +5,23 @@ import { IPresenter } from "./presenter.interface";
export class InMemoryPresenterRegistry implements IPresenterRegistry {
private registry: Map<string, IPresenter<any, any>> = new Map();
private _normalizeKey(key: PresenterKey): PresenterKey {
return {
...key,
format: key.format ?? "JSON", // 👈 valor por defecto
};
}
private _registerPresenter<TSource, TOutput>(
key: PresenterKey,
presenter: IPresenter<TSource, TOutput>
): void {
const exactKey = this._buildKey(this._normalizeKey(key));
this.registry.set(exactKey, presenter);
}
getPresenter<TSource, TOutput>(key: PresenterKey): IPresenter<TSource, TOutput> {
const exactKey = this._buildKey(key);
const exactKey = this._buildKey(this._normalizeKey(key));
// 1) Intentar clave exacta
if (this.registry.has(exactKey)) {
@ -43,20 +58,28 @@ export class InMemoryPresenterRegistry implements IPresenterRegistry {
registerPresenter<TSource, TOutput>(
key: PresenterKey,
presenter: IPresenter<TSource, TOutput>
): void {
const exactKey = this._buildKey(key);
this.registry.set(exactKey, presenter);
): this {
this._registerPresenter(key, presenter);
return this;
}
/**
* Registro en lote de presentadores.
*/
registerPresenters(
presenters: Array<{ key: PresenterKey; presenter: IPresenter<any, any> }>
): this {
presenters.forEach(({ key, presenter }) => this._registerPresenter(key, presenter));
return this;
}
/**
* 🔹 Construye la clave única para el registro.
*/
private _buildKey(key: PresenterKey): string {
const { resource, projection, format, version, locale } = key;
const { projection, format, version, locale } = key;
return [
resource.toLowerCase(),
projection.toLowerCase(),
format.toLowerCase(),
format!.toLowerCase(),
version ?? "latest",
locale ?? "default",
].join("::");

View File

@ -1,32 +1,6 @@
export type DTO<T = unknown> = T;
export type BinaryOutput = Buffer; // Puedes ampliar a Readable si usas streams
interface ISyncPresenter<TSource, TOutput = DTO> {
toOutput(source: TSource): TOutput;
export interface IPresenter<TSource = unknown, TOutput = DTO> {
toOutput(source: TSource): TOutput | Promise<TOutput>;
}
interface IAsyncPresenter<TSource, TOutput = DTO> {
toOutput(source: TSource): Promise<TOutput>;
}
/**
* Proyección SINCRÓNICA de colecciones.
* Útil para listados paginados, exportaciones ligeras, etc.
*/
/*export interface ISyncBulkPresenter<TSource, TOutput = BinaryOutput> {
toOutput(source: TSource): TOutput;
}*/
/**
* Proyección ASÍNCRONA de colecciones.
* Útil para generar varios PDFs/CSVs.
*/
/*export interface IAsyncBulkPresenter<TSource, TOutput = BinaryOutput> {
toOutput(source: TSource): Promise<TOutput>;
}*/
export type IPresenter<TSource, TOutput = DTO | BinaryOutput> =
| ISyncPresenter<TSource, TOutput>
| IAsyncPresenter<TSource, TOutput>;
//| ISyncBulkPresenter<TSource, TOutput>
//| IAsyncBulkPresenter<TSource, TOutput>;

View File

@ -2,7 +2,7 @@
* 🔑 Claves de proyección comunes para seleccionar mappers en lectura.
* Puedes extender con otras cadenas según tus necesidades ("SUMMARY", "EXPORT", etc.).
*/
export type MapperProjectionKey = "FULL" | "LIST" | "REPORTS" | (string & {});
export type MapperProjectionKey = "FULL" | "LIST" | "REPORT" | (string & {});
/**
* 🏗 Registro/Fábrica de mappers (Strategy/Factory)

View File

@ -1 +0,0 @@
export * from "./create-customer-invoices.assembler";

View File

@ -1,2 +1,2 @@
export * from "./assembler";
export * from "./presenter";
export * from "./create-customer-invoice.use-case";

View File

@ -4,7 +4,7 @@ import { CustomerInvoice } from "../../../domain";
type CreateCustomerInvoiceItemsByInvoiceIdResponseDTO = CreateCustomerInvoiceResponseDTO["items"];
export class CreateCustomerInvoiceItemsAssembler {
export class CreateCustomerInvoiceItemsPresenter {
toDTO(invoice: CustomerInvoice): CreateCustomerInvoiceItemsByInvoiceIdResponseDTO {
const { items } = invoice;
return items.map((item, index) => ({

View File

@ -1,17 +1,17 @@
import { UpdateCustomerInvoiceByIdResponseDTO } from "@erp/customer-invoices/common/dto";
import { toEmptyString } from "@repo/rdx-ddd";
import { CustomerInvoice } from "../../../domain";
import { CreateCustomerInvoiceItemsAssembler } from "./create-customer-invoice-items.assembler";
import { CreateCustomerInvoiceItemsPresenter } from "./create-customer-invoice-items.presenter";
export class CreateCustomerInvoiceAssembler {
private _itemsAssembler!: CreateCustomerInvoiceItemsAssembler;
export class CreateCustomerInvoicePresenter {
private _itemsPresenter!: CreateCustomerInvoiceItemsPresenter;
constructor() {
this._itemsAssembler = new CreateCustomerInvoiceItemsAssembler();
this._itemsPresenter = new CreateCustomerInvoiceItemsPresenter();
}
public toDTO(invoice: CustomerInvoice): UpdateCustomerInvoiceByIdResponseDTO {
const items = this._itemsAssembler.toDTO(invoice);
const items = this._itemsPresenter.toDTO(invoice);
return {
id: invoice.id.toPrimitive(),

View File

@ -0,0 +1 @@
export * from "./create-customer-invoices.presenter";

View File

@ -1 +0,0 @@
export * from "./get-invoice.assembler";

View File

@ -1,2 +1,2 @@
export * from "./assembler";
export * from "./presenter";
export * from "./get-customer-invoice.use-case";

View File

@ -2,7 +2,7 @@ import { CustomerInvoiceItem } from "#/server/domain";
import { IInvoicingContext } from "#/server/intrastructure";
import { Collection } from "@rdx/core";
export const customerInvoiceItemAssembler = (items: Collection<CustomerInvoiceItem>, context: IInvoicingContext) =>
export const customerInvoiceItemPresenter = (items: Collection<CustomerInvoiceItem>, context: IInvoicingContext) =>
items.totalCount > 0
? items.items.map((item: CustomerInvoiceItem) => ({
description: item.description.toString(),

View File

@ -1,9 +1,9 @@
import { ICustomerInvoiceParticipant } from "@/contexts/invoicing/domain";
import { IInvoicingContext } from "@/contexts/invoicing/intrastructure/InvoicingContext";
import { ICreateCustomerInvoice_Participant_Response_DTO } from "@shared/contexts";
import { CustomerInvoiceParticipantAddressAssembler } from "./CustomerInvoiceParticipantAddress.assembler";
import { CustomerInvoiceParticipantAddressPresenter } from "./CustomerInvoiceParticipantAddress.presenter";
export const CustomerInvoiceParticipantAssembler = async (
export const CustomerInvoiceParticipantPresenter = async (
participant: ICustomerInvoiceParticipant,
context: IInvoicingContext,
): Promise<ICreateCustomerInvoice_Participant_Response_DTO | undefined> => {
@ -14,11 +14,11 @@ export const CustomerInvoiceParticipantAssembler = async (
last_name: participant.lastName.toString(),
company_name: participant.companyName.toString(),
billing_address: await CustomerInvoiceParticipantAddressAssembler(
billing_address: await CustomerInvoiceParticipantAddressPresenter(
participant.billingAddress!,
context,
),
shipping_address: await CustomerInvoiceParticipantAddressAssembler(
shipping_address: await CustomerInvoiceParticipantAddressPresenter(
participant.shippingAddress!,
context,
),

View File

@ -2,7 +2,7 @@ import { CustomerInvoiceParticipantAddress } from "@/contexts/invoicing/domain";
import { IInvoicingContext } from "@/contexts/invoicing/intrastructure/InvoicingContext";
import { ICreateCustomerInvoice_AddressParticipant_Response_DTO } from "@shared/contexts";
export const CustomerInvoiceParticipantAddressAssembler = async (
export const CustomerInvoiceParticipantAddressPresenter = async (
address: CustomerInvoiceParticipantAddress,
context: IInvoicingContext,
): Promise<ICreateCustomerInvoice_AddressParticipant_Response_DTO> => {

View File

@ -4,7 +4,7 @@ import { CustomerInvoice } from "../../../domain";
type GetCustomerInvoiceItemsByInvoiceIdResponseDTO = GetCustomerInvoiceByIdResponseDTO["items"];
export class GetCustomerInvoiceItemsAssembler {
export class GetCustomerInvoiceItemsPresenter {
toDTO(invoice: CustomerInvoice): GetCustomerInvoiceItemsByInvoiceIdResponseDTO {
const { items } = invoice;

View File

@ -1,17 +1,17 @@
import { UpdateCustomerInvoiceByIdResponseDTO } from "@erp/customer-invoices/common/dto";
import { toEmptyString } from "@repo/rdx-ddd";
import { CustomerInvoice } from "../../../domain";
import { GetCustomerInvoiceItemsAssembler } from "./get-invoice-items.assembler";
import { GetCustomerInvoiceItemsPresenter } from "./get-invoice-items.presenter";
export class GetCustomerInvoiceAssembler {
private _itemsAssembler!: GetCustomerInvoiceItemsAssembler;
export class GetCustomerInvoicePresenter {
private _itemsPresenter!: GetCustomerInvoiceItemsPresenter;
constructor() {
this._itemsAssembler = new GetCustomerInvoiceItemsAssembler();
this._itemsPresenter = new GetCustomerInvoiceItemsPresenter();
}
public toDTO(invoice: CustomerInvoice): UpdateCustomerInvoiceByIdResponseDTO {
const items = this._itemsAssembler.toDTO(invoice);
const items = this._itemsPresenter.toDTO(invoice);
return {
id: invoice.id.toString(),

View File

@ -0,0 +1 @@
export * from "./get-invoice.presenter";

View File

@ -1 +0,0 @@
export * from "./list-customer-invoices.assembler";

View File

@ -1,2 +1,2 @@
export * from "./assembler";
export * from "./presenter";
export * from "./list-customer-invoices.use-case";

View File

@ -0,0 +1 @@
export * from "./list-customer-invoices.presenter";

View File

@ -1,14 +1,17 @@
import { IPresenter } from "@erp/core/api";
import { CustomerInvoiceListDTO } from "@erp/customer-invoices/api/infrastructure";
import { Criteria } from "@repo/rdx-criteria/server";
import { toEmptyString } from "@repo/rdx-ddd";
import { ArrayElement, Collection } from "@repo/rdx-utils";
import { CustomerInvoiceListResponseDTO } from "../../../../common/dto";
export class ListCustomerInvoicesAssembler {
toDTO(
customerInvoices: Collection<CustomerInvoiceListDTO>,
criteria: Criteria
): CustomerInvoiceListResponseDTO {
export class ListCustomerInvoicesPresenter implements IPresenter {
toOutput(params: {
customerInvoices: Collection<CustomerInvoiceListDTO>;
criteria: Criteria;
}): CustomerInvoiceListResponseDTO {
const { customerInvoices, criteria } = params;
const invoices = customerInvoices.map((invoice) => {
const recipientDTO = invoice.recipient.toObjectString();

View File

@ -1 +0,0 @@
export * from "./update-invoice.assembler";

View File

@ -1,2 +1,2 @@
export * from "./assembler";
export * from "./presenter";
export * from "./update-customer-invoice.use-case";

View File

@ -0,0 +1 @@
export * from "./update-invoice.presenter";

View File

@ -5,7 +5,7 @@ import { CustomerInvoice } from "../../../domain";
type UpdateCustomerInvoiceItemsByInvoiceIdResponseDTO =
UpdateCustomerInvoiceByIdResponseDTO["items"];
export class UpdateCustomerInvoiceItemsAssembler {
export class UpdateCustomerInvoiceItemsPresenter {
toDTO(invoice: CustomerInvoice): UpdateCustomerInvoiceItemsByInvoiceIdResponseDTO {
const { items } = invoice;
return items.map((item, index) => ({

View File

@ -1,17 +1,17 @@
import { toEmptyString } from "@repo/rdx-ddd";
import { UpdateCustomerInvoiceByIdResponseDTO } from "../../../../common/dto";
import { CustomerInvoice } from "../../../domain";
import { UpdateCustomerInvoiceItemsAssembler } from "./update-invoice-items.assembler";
import { UpdateCustomerInvoiceItemsPresenter } from "./update-invoice-items.presenter";
export class UpdateCustomerInvoiceAssembler {
private _itemsAssembler!: UpdateCustomerInvoiceItemsAssembler;
export class UpdateCustomerInvoicePresenter {
private _itemsPresenter!: UpdateCustomerInvoiceItemsPresenter;
constructor() {
this._itemsAssembler = new UpdateCustomerInvoiceItemsAssembler();
this._itemsPresenter = new UpdateCustomerInvoiceItemsPresenter();
}
public toDTO(invoice: CustomerInvoice): UpdateCustomerInvoiceByIdResponseDTO {
const items = this._itemsAssembler.toDTO(invoice);
const items = this._itemsPresenter.toDTO(invoice);
return {
id: invoice.id.toPrimitive(),
@ -82,10 +82,10 @@ export class UpdateCustomerInvoiceAssembler {
}))
: [],*/
//sender: {}, //await CustomerInvoiceParticipantAssembler(customerInvoice.senderId, context),
//sender: {}, //await CustomerInvoiceParticipantPresenter(customerInvoice.senderId, context),
/*recipient: await CustomerInvoiceParticipantAssembler(customerInvoice.recipient, context),
items: customerInvoiceItemAssembler(customerInvoice.items, context),
/*recipient: await CustomerInvoiceParticipantPresenter(customerInvoice.recipient, context),
items: customerInvoiceItemPresenter(customerInvoice.items, context),
payment_term: {
payment_type: "",

View File

@ -6,15 +6,12 @@ import {
SequelizeTransactionManager,
} from "@erp/core/api";
import {
CreateCustomerInvoiceAssembler,
CreateCustomerInvoiceUseCase,
DeleteCustomerInvoiceUseCase,
GetCustomerInvoiceAssembler,
GetCustomerInvoiceUseCase,
ListCustomerInvoicesAssembler,
ListCustomerInvoicesPresenter,
ListCustomerInvoicesUseCase,
ReportCustomerInvoiceUseCase,
UpdateCustomerInvoiceAssembler,
UpdateCustomerInvoiceUseCase,
} from "../application";
import { CustomerInvoiceService } from "../domain";
@ -24,17 +21,12 @@ import { CustomerInvoiceRepository } from "./sequelize";
type InvoiceDeps = {
transactionManager: SequelizeTransactionManager;
mapperRegistry: IMapperRegistry;
presenterRegistry: IPresenterRegistry;
repo: CustomerInvoiceRepository;
service: CustomerInvoiceService;
catalogs: {
taxes: JsonTaxCatalogProvider;
};
presenters: {
list: ListCustomerInvoicesAssembler;
get: GetCustomerInvoiceAssembler;
create: CreateCustomerInvoiceAssembler;
update: UpdateCustomerInvoiceAssembler;
};
build: {
list: () => ListCustomerInvoicesUseCase;
get: () => GetCustomerInvoiceUseCase;
@ -50,7 +42,6 @@ let _mapperRegistry: IMapperRegistry | null = null;
let _repo: CustomerInvoiceRepository | null = null;
let _service: CustomerInvoiceService | null = null;
const _presenters: InvoiceDeps["presenters"] | null = null;
let _catalogs: InvoiceDeps["catalogs"] | null = null;
export function getInvoiceDependencies(params: ModuleParams): InvoiceDeps {
@ -73,43 +64,56 @@ export function getInvoiceDependencies(params: ModuleParams): InvoiceDeps {
if (!_presenterRegistry) {
_presenterRegistry = new InMemoryPresenterRegistry();
_presenterRegistry.registerPresenter(key, mapper);
/*_presenters = {
list: new ListCustomerInvoicesAssembler(), // transforma domain → ListDTO
get: new GetCustomerInvoiceAssembler(), // transforma domain → DetailDTO
create: new CreateCustomerInvoiceAssembler(), // transforma domain → CreatedDTO
update: new UpdateCustomerInvoiceAssembler(), // transforma domain -> UpdateDTO
};*/
_presenterRegistry.registerPresenter(
{
projection: "LIST",
},
new ListCustomerInvoicesPresenter()
);
}
return {
transactionManager,
repo: _repo,
mapperRegistry: _mapperRegistry,
presenterRegistry: _presenterRegistry,
service: _service,
presenters: _presenters,
catalogs: _catalogs,
build: {
list: () =>
new ListCustomerInvoicesUseCase(_service!, transactionManager!, _presenters!.list),
get: () => new GetCustomerInvoiceUseCase(_service!, transactionManager!, _presenters!.get),
new ListCustomerInvoicesUseCase(
_service!,
transactionManager!,
_presenterRegistry?.getPresenter({ projection: "LIST" })
),
get: () =>
new GetCustomerInvoiceUseCase(
_service!,
transactionManager!,
_presenterRegistry?.getPresenter({ projection: "FULL" })
),
create: () =>
new CreateCustomerInvoiceUseCase(
_service!,
transactionManager!,
_presenters!.create,
_presenterRegistry?.getPresenter({ projection: "FULL" }),
_catalogs!.taxes
),
update: () =>
new UpdateCustomerInvoiceUseCase(
_service!,
transactionManager!,
_presenters!.update,
_presenterRegistry?.getPresenter({ projection: "FULL" }),
_catalogs!.taxes
),
delete: () => new DeleteCustomerInvoiceUseCase(_service!, transactionManager!),
report: () =>
new ReportCustomerInvoiceUseCase(_service!, transactionManager!, _presenters!.get),
new ReportCustomerInvoiceUseCase(
_service!,
transactionManager!,
_presenterRegistry?.getPresenter({ projection: "REPORT" })
),
},
};
}

View File

@ -1 +0,0 @@
export * from "./create-customers.assembler";

View File

@ -1,2 +1,2 @@
export * from "./assembler";
export * from "./presenter";
export * from "./create-customer.use-case";

View File

@ -2,7 +2,7 @@ import { toEmptyString } from "@repo/rdx-ddd";
import { CustomerCreationResponseDTO } from "../../../../common";
import { Customer } from "../../../domain";
export class CreateCustomersAssembler {
export class CreateCustomersPresenter {
public toDTO(customer: Customer): CustomerCreationResponseDTO {
const address = customer.address.toPrimitive();

View File

@ -0,0 +1 @@
export * from "./create-customers.presenter";

View File

@ -1 +0,0 @@
export * from "./get-customer.assembler";

View File

@ -1,2 +1,2 @@
export * from "./assembler";
export * from "./presenter";
export * from "./get-customer.use-case";

View File

@ -2,7 +2,7 @@ import { CustomerItem } from "#/server/domain";
import { IInvoicingContext } from "#/server/intrastructure";
import { Collection } from "@rdx/core";
export const customerItemAssembler = (items: Collection<CustomerItem>, context: IInvoicingContext) =>
export const customerItemPresenter = (items: Collection<CustomerItem>, context: IInvoicingContext) =>
items.totalCount > 0
? items.items.map((item: CustomerItem) => ({
description: item.description.toString(),

View File

@ -1,9 +1,9 @@
import { ICustomerParticipant } from "@/contexts/invoicing/domain";
import { IInvoicingContext } from "@/contexts/invoicing/intrastructure/InvoicingContext";
import { ICreateCustomer_Participant_Response_DTO } from "@shared/contexts";
import { CustomerParticipantAddressAssembler } from "./CustomerParticipantAddress.assembler";
import { CustomerParticipantAddressPresenter } from "./CustomerParticipantAddress.presenter";
export const CustomerParticipantAssembler = async (
export const CustomerParticipantPresenter = async (
participant: ICustomerParticipant,
context: IInvoicingContext,
): Promise<ICreateCustomer_Participant_Response_DTO | undefined> => {
@ -14,11 +14,11 @@ export const CustomerParticipantAssembler = async (
last_name: participant.lastName.toString(),
company_name: participant.companyName.toString(),
billing_address: await CustomerParticipantAddressAssembler(
billing_address: await CustomerParticipantAddressPresenter(
participant.billingAddress!,
context,
),
shipping_address: await CustomerParticipantAddressAssembler(
shipping_address: await CustomerParticipantAddressPresenter(
participant.shippingAddress!,
context,
),

View File

@ -2,7 +2,7 @@ import { CustomerParticipantAddress } from "@/contexts/invoicing/domain";
import { IInvoicingContext } from "@/contexts/invoicing/intrastructure/InvoicingContext";
import { ICreateCustomer_AddressParticipant_Response_DTO } from "@shared/contexts";
export const CustomerParticipantAddressAssembler = async (
export const CustomerParticipantAddressPresenter = async (
address: CustomerParticipantAddress,
context: IInvoicingContext,
): Promise<ICreateCustomer_AddressParticipant_Response_DTO> => {

View File

@ -2,7 +2,7 @@ import { toEmptyString } from "@repo/rdx-ddd";
import { GetCustomerByIdResponseDTO } from "../../../../common/dto";
import { Customer } from "../../../domain";
export class GetCustomerAssembler {
export class GetCustomerPresenter {
toDTO(customer: Customer): GetCustomerByIdResponseDTO {
const address = customer.address.toPrimitive();

View File

@ -0,0 +1 @@
export * from "./get-customer.presenter";

View File

@ -1 +0,0 @@
export * from "./list-customers.assembler";

View File

@ -1,2 +1,2 @@
export * from "./assembler";
export * from "./presenter";
export * from "./list-customers.use-case";

View File

@ -0,0 +1 @@
export * from "./list-customers.presenter";

View File

@ -4,7 +4,7 @@ import { Collection } from "@repo/rdx-utils";
import { CustomerListResponsetDTO } from "../../../../common/dto";
import { Customer } from "../../../domain";
export class ListCustomersAssembler {
export class ListCustomersPresenter {
toDTO(customers: Collection<Customer>, criteria: Criteria): CustomerListResponsetDTO {
const items: CustomerListResponsetDTO["items"] = customers.map((customer) => {
const address = customer.address.toPrimitive();

View File

@ -1 +0,0 @@
export * from "./update-customer.assembler";

View File

@ -1,2 +1,2 @@
export * from "./assembler";
export * from "./presenter";
export * from "./update-customer.use-case";

View File

@ -0,0 +1 @@
export * from "./update-customer.presenter";

View File

@ -2,7 +2,7 @@ import { toEmptyString } from "@repo/rdx-ddd";
import { UpdateCustomerByIdResponseDTO } from "../../../../common/dto";
import { Customer } from "../../../domain";
export class UpdateCustomerAssembler {
export class UpdateCustomerPresenter {
toDTO(customer: Customer): UpdateCustomerByIdResponseDTO {
const address = customer.address.toPrimitive();

View File

@ -1,15 +1,17 @@
import type { ModuleParams } from "@erp/core/api";
import { SequelizeTransactionManager } from "@erp/core/api";
import type { IMapperRegistry, IPresenterRegistry, ModuleParams } from "@erp/core/api";
import {
InMemoryMapperRegistry,
InMemoryPresenterRegistry,
SequelizeTransactionManager,
} from "@erp/core/api";
import {
CreateCustomerUseCase,
CreateCustomersAssembler,
DeleteCustomerUseCase,
GetCustomerAssembler,
GetCustomerUseCase,
ListCustomersAssembler,
ListCustomersUseCase,
UpdateCustomerAssembler,
UpdateCustomerUseCase,
} from "../application";
import { CustomerService } from "../domain";
@ -18,15 +20,10 @@ import { CustomerRepository } from "./sequelize";
type CustomerDeps = {
transactionManager: SequelizeTransactionManager;
mapperRegistry: IMapperRegistry;
presenterRegistry: IPresenterRegistry;
repo: CustomerRepository;
mapper: CustomerMapper;
service: CustomerService;
assemblers: {
list: ListCustomersAssembler;
get: GetCustomerAssembler;
create: CreateCustomersAssembler;
update: UpdateCustomerAssembler;
};
build: {
list: () => ListCustomersUseCase;
get: () => GetCustomerUseCase;
@ -34,39 +31,56 @@ type CustomerDeps = {
update: () => UpdateCustomerUseCase;
delete: () => DeleteCustomerUseCase;
};
presenters: {
// list: <T>(res: Response) => ListPresenter<T>;
};
};
let _presenterRegistry: IPresenterRegistry | null = null;
let _mapperRegistry: IMapperRegistry | null = null;
let _repo: CustomerRepository | null = null;
let _mapper: CustomerMapper | null = null;
let _service: CustomerService | null = null;
let _assemblers: CustomerDeps["assemblers"] | null = null;
export function getCustomerDependencies(params: ModuleParams): CustomerDeps {
const { database } = params;
const transactionManager = new SequelizeTransactionManager(database);
if (!_mapper) _mapper = new CustomerMapper();
if (!_repo) _repo = new CustomerRepository(_mapper);
if (!_mapperRegistry) {
_mapperRegistry = new InMemoryMapperRegistry();
_mapperRegistry.registerDomainMapper("FULL", new CustomerMapper());
}
if (!_repo) _repo = new CustomerRepository({ mapperRegistry: _mapperRegistry });
if (!_service) _service = new CustomerService(_repo);
if (!_assemblers) {
if (!_presenterRegistry) {
_presenterRegistry = new InMemoryPresenterRegistry();
_presenterRegistry.registerPresenters([
{
key: { projection: "FULL" },
presenter: new ListCustomersAssembler(),
},
{
key: { projection: "LIST" },
presenter: new GetCustomerAssembler(),
},
]);
/*if (!_assemblers) {
_assemblers = {
list: new ListCustomersAssembler(), // transforma domain → ListDTO
get: new GetCustomerAssembler(), // transforma domain → DetailDTO
create: new CreateCustomersAssembler(), // transforma domain → CreatedDTO
update: new UpdateCustomerAssembler(), // transforma domain -> UpdateDTO
};
};*/
}
return {
transactionManager,
repo: _repo,
mapper: _mapper,
mapperRegistry: _mapperRegistry,
presenterRegistry: _presenterRegistry,
service: _service,
assemblers: _assemblers,
build: {
list: () => new ListCustomersUseCase(_service!, transactionManager!, _assemblers!.list),
get: () => new GetCustomerUseCase(_service!, transactionManager!, _assemblers!.get),
@ -74,9 +88,5 @@ export function getCustomerDependencies(params: ModuleParams): CustomerDeps {
update: () => new UpdateCustomerUseCase(_service!, transactionManager!, _assemblers!.update),
delete: () => new DeleteCustomerUseCase(_service!, transactionManager!),
},
presenters: {
//list: <T>(res: Response) => createListPresenter<T>(res),
//json: <T>(res: Response, status: number = 200) => createJsonPresenter<T>(res, status),
},
};
}