Facturas de cliente
This commit is contained in:
parent
c7b42fa8ba
commit
d7dc148439
@ -45,17 +45,19 @@ export interface IPresenterRegistry {
|
||||
/**
|
||||
* Obtiene un mapper de dominio por clave de proyección.
|
||||
*/
|
||||
getPresenter<TSource, TOutput>(key: PresenterKey): IPresenter<TSource, TOutput>;
|
||||
getPresenter<TSource = unknown, TOutput = unknown>(
|
||||
key: PresenterKey
|
||||
): IPresenter<TSource, TOutput>;
|
||||
|
||||
/**
|
||||
* Registra un mapper de dominio bajo una clave de proyección.
|
||||
*/
|
||||
registerPresenter<TSource, TOutput>(
|
||||
registerPresenter<TSource = unknown, TOutput = unknown>(
|
||||
key: PresenterKey,
|
||||
presenter: IPresenter<TSource, TOutput>
|
||||
): this;
|
||||
|
||||
registerPresenters(
|
||||
presenters: Array<{ key: PresenterKey; presenter: IPresenter<any, any> }>
|
||||
presenters: Array<{ key: PresenterKey; presenter: IPresenter<unknown, unknown> }>
|
||||
): this;
|
||||
}
|
||||
|
||||
@ -12,6 +12,20 @@ export class InMemoryPresenterRegistry implements IPresenterRegistry {
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 🔹 Construye la clave única para el registro.
|
||||
*/
|
||||
private _buildKey(key: PresenterKey): string {
|
||||
const { resource, projection, format, version, locale } = key;
|
||||
return [
|
||||
resource.toLowerCase(),
|
||||
projection.toLowerCase(),
|
||||
format!.toLowerCase(),
|
||||
version ?? "latest",
|
||||
locale ?? "default",
|
||||
].join("::");
|
||||
}
|
||||
|
||||
private _registerPresenter<TSource, TOutput>(
|
||||
key: PresenterKey,
|
||||
presenter: IPresenter<TSource, TOutput>
|
||||
@ -54,7 +68,9 @@ export class InMemoryPresenterRegistry implements IPresenterRegistry {
|
||||
);
|
||||
}
|
||||
|
||||
throw new ApplicationError(`Error. Presenter ${key.resource} ${key.projection} not registred!`);
|
||||
throw new ApplicationError(
|
||||
`Error. Presenter ${key.resource} / ${key.projection} not registred!`
|
||||
);
|
||||
}
|
||||
|
||||
registerPresenter<TSource, TOutput>(
|
||||
@ -73,18 +89,4 @@ export class InMemoryPresenterRegistry implements IPresenterRegistry {
|
||||
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;
|
||||
return [
|
||||
resource.toLowerCase(),
|
||||
projection.toLowerCase(),
|
||||
format!.toLowerCase(),
|
||||
version ?? "latest",
|
||||
locale ?? "default",
|
||||
].join("::");
|
||||
}
|
||||
}
|
||||
|
||||
@ -5,7 +5,9 @@ export type IPresenterParams = {
|
||||
presenterRegistry: IPresenterRegistry;
|
||||
} & Record<string, unknown>;
|
||||
|
||||
export abstract class Presenter<T, S> implements IPresenter<T, S> {
|
||||
export abstract class Presenter<TSource = unknown, TOutput = unknown>
|
||||
implements IPresenter<TSource, TOutput>
|
||||
{
|
||||
constructor(protected presenterRegistry: IPresenterRegistry) {}
|
||||
abstract toOutput(source: T): S;
|
||||
abstract toOutput(source: TSource): TOutput;
|
||||
}
|
||||
|
||||
@ -61,7 +61,7 @@ export type DomainMapperWithBulk<TPersistence, TDomain> = IDomainMapper<TPersist
|
||||
* - Responsabilidad: transformar registros de persistencia en DTOs para lectura (listados, resúmenes, informes).
|
||||
* - No intenta reconstruir agregados ni validar value objects de dominio.
|
||||
**/
|
||||
export interface IReadModelMapperWithBulk<TPersistence, TDTO> {
|
||||
export interface IQueryMapperWithBulk<TPersistence, TDTO> {
|
||||
/**
|
||||
* Convierte un registro crudo en un DTO de lectura.
|
||||
*/
|
||||
|
||||
@ -1,38 +1,42 @@
|
||||
/**
|
||||
* 🔑 Claves de proyección comunes para seleccionar mappers en lectura.
|
||||
* Puedes extender con otras cadenas según tus necesidades ("SUMMARY", "EXPORT", etc.).
|
||||
* 🔑 Claves de proyección comunes para seleccionar mappers de dominio y de consulta.
|
||||
*/
|
||||
export type MapperProjectionKey = "FULL" | "LIST" | "REPORT" | (string & {});
|
||||
|
||||
export type MapperKey = {
|
||||
resource: string;
|
||||
query: "LIST" | "REPORT" | (string & {}); // "SUMMARY", "EXPORT", etc.
|
||||
};
|
||||
|
||||
export type MapperDomainKey = Pick<MapperKey, "resource">;
|
||||
|
||||
export type MapperQueryKey = MapperKey;
|
||||
|
||||
/**
|
||||
* 🏗️ Registro/Fábrica de mappers (Strategy/Factory)
|
||||
* - Permite resolver diferentes mappers según la proyección (FULL, SUMMARY, etc.)
|
||||
* - Permite resolver diferentes mappers según la consulta (FULL, SUMMARY, etc.)
|
||||
* - Facilita inyección y test (DIP), evitando dependencias duras en implementaciones concretas.
|
||||
*
|
||||
* Ejemplo de uso:
|
||||
* - registry.registerDomainMapper("FULL", customerInvoiceFullMapper);
|
||||
* - registry.registerReadModelMapper("SUMMARY", customerInvoiceSummaryMapper);
|
||||
* - registry.registerReadModelMapper("REPORT", customerInvoiceReportMapper);
|
||||
*/
|
||||
|
||||
export interface IMapperRegistry {
|
||||
/**
|
||||
* Obtiene un mapper de dominio por clave de proyección.
|
||||
*/
|
||||
getDomainMapper<T>(key: MapperProjectionKey): T;
|
||||
getDomainMapper<T>(key: MapperDomainKey): T;
|
||||
|
||||
/**
|
||||
* Obtiene un mapper de read model por clave de proyección.
|
||||
*/
|
||||
getReadModelMapper<T>(key: MapperProjectionKey): T;
|
||||
getQueryMapper<T>(key: MapperQueryKey): T;
|
||||
|
||||
/**
|
||||
* Registra un mapper de dominio bajo una clave de proyección.
|
||||
* Registra mapper de dominio bajo una clave de proyección.
|
||||
*/
|
||||
registerDomainMapper<T>(key: MapperProjectionKey, mapper: T): void;
|
||||
registerDomainMapper<T>(key: MapperDomainKey, mapper: T): this;
|
||||
|
||||
/**
|
||||
* Registra un mapper de read model bajo una clave de proyección.
|
||||
* Registra un mapper de query / read model bajo una clave de proyección.
|
||||
*/
|
||||
registerReadModelMapper<T>(key: MapperProjectionKey, mapper: T): void;
|
||||
registerQueryMapper<T>(key: MapperQueryKey, mapper: T): this;
|
||||
registerQueryMappers(mappers: Array<{ key: MapperQueryKey; mapper: any }>): this;
|
||||
}
|
||||
|
||||
@ -1,30 +1,78 @@
|
||||
import { InfrastructureError } from "../errors";
|
||||
import { IMapperRegistry, MapperProjectionKey } from "./mapper-registry.interface";
|
||||
import {
|
||||
IMapperRegistry,
|
||||
MapperDomainKey,
|
||||
MapperKey,
|
||||
MapperQueryKey,
|
||||
} from "./mapper-registry.interface";
|
||||
|
||||
export class InMemoryMapperRegistry implements IMapperRegistry {
|
||||
private domainMappers: Map<MapperProjectionKey, any> = new Map();
|
||||
private readModelMappers: Map<MapperProjectionKey, any> = new Map();
|
||||
private _mappers: Map<string, any> = new Map();
|
||||
|
||||
getDomainMapper<T>(key: MapperProjectionKey): T {
|
||||
if (!this.domainMappers.has(key)) {
|
||||
throw new InfrastructureError(`Error. Domain model mapper ${key} not registred!`);
|
||||
private _normalizeKey(key: MapperDomainKey | MapperQueryKey): MapperKey {
|
||||
const { resource, query } = key as {
|
||||
resource: string;
|
||||
query?: string;
|
||||
};
|
||||
|
||||
return {
|
||||
resource,
|
||||
query: query ?? "DOMAIN", // 👈 valor por defecto
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 🔹 Construye la clave única para el registro.
|
||||
*/
|
||||
private _buildKey(key: MapperKey): string {
|
||||
const { resource, query } = key as {
|
||||
resource: string;
|
||||
query?: string;
|
||||
};
|
||||
return [resource.toLowerCase(), query ?? "DOMAIN"].join("::");
|
||||
}
|
||||
|
||||
private _getMapper<T>(key: MapperKey): T {
|
||||
const normalizedKey = this._normalizeKey(key);
|
||||
const exactKey = this._buildKey(normalizedKey);
|
||||
|
||||
if (!this._mappers.has(exactKey)) {
|
||||
throw new InfrastructureError(`Error. Mapper ${normalizedKey.resource} not registred!`);
|
||||
}
|
||||
|
||||
return this.domainMappers.get(key);
|
||||
return this._mappers.get(exactKey);
|
||||
}
|
||||
|
||||
getReadModelMapper<T>(key: MapperProjectionKey): T {
|
||||
if (!this.readModelMappers.has(key)) {
|
||||
throw new InfrastructureError(`Error. Read model mapper ${key} not registred!`);
|
||||
}
|
||||
return this.readModelMappers.get(key);
|
||||
getDomainMapper<T>(key: MapperDomainKey): T {
|
||||
const normalizedKey = this._normalizeKey({
|
||||
resource: key.resource,
|
||||
query: "DOMAIN",
|
||||
});
|
||||
return this._getMapper(normalizedKey);
|
||||
}
|
||||
|
||||
registerDomainMapper<T>(key: MapperProjectionKey, mapper: T): void {
|
||||
this.domainMappers.set(key, mapper);
|
||||
getQueryMapper<T>(key: MapperQueryKey): T {
|
||||
const normalizedKey = this._normalizeKey({
|
||||
resource: key.resource,
|
||||
query: "DOMAIN",
|
||||
});
|
||||
return this._getMapper(normalizedKey);
|
||||
}
|
||||
|
||||
registerReadModelMapper<T>(key: MapperProjectionKey, mapper: T): void {
|
||||
this.readModelMappers.set(key, mapper);
|
||||
registerDomainMapper<T>(key: MapperDomainKey, mapper: T) {
|
||||
const exactKey = this._buildKey(this._normalizeKey(key));
|
||||
this._mappers.set(exactKey, mapper);
|
||||
return this;
|
||||
}
|
||||
|
||||
registerQueryMapper<T>(key: MapperQueryKey, mapper: T) {
|
||||
const exactKey = this._buildKey(this._normalizeKey(key));
|
||||
this._mappers.set(exactKey, mapper);
|
||||
return this;
|
||||
}
|
||||
|
||||
registerQueryMappers(mappers: Array<{ key: MapperQueryKey; mapper: any }>): this {
|
||||
mappers.forEach(({ key, mapper }) => this.registerQueryMapper(key, mapper));
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
import { DomainMapperWithBulk, IReadModelMapperWithBulk } from "../../../domain";
|
||||
import { DomainMapperWithBulk, IQueryMapperWithBulk } from "../../../domain";
|
||||
|
||||
export interface ISequelizeDomainMapper<TModel, TModelAttributes, TEntity>
|
||||
extends DomainMapperWithBulk<TModel | TModelAttributes, TEntity> {}
|
||||
|
||||
export interface ISequelizeReadModelMapper<TModel, TDTO>
|
||||
extends IReadModelMapperWithBulk<TModel, TDTO> {}
|
||||
export interface ISequelizeQueryMapper<TModel, TDTO> extends IQueryMapperWithBulk<TModel, TDTO> {}
|
||||
|
||||
@ -1,10 +1,10 @@
|
||||
import { Collection, Result } from "@repo/rdx-utils";
|
||||
import { Model } from "sequelize";
|
||||
import { MapperParamsType } from "../../../domain";
|
||||
import { ISequelizeReadModelMapper } from "./sequelize-mapper.interface";
|
||||
import { ISequelizeQueryMapper } from "./sequelize-mapper.interface";
|
||||
|
||||
export abstract class SequelizeReadModelMapper<TModel extends Model, TEntity>
|
||||
implements ISequelizeReadModelMapper<TModel, TEntity>
|
||||
export abstract class SequelizeQueryMapper<TModel extends Model, TEntity>
|
||||
implements ISequelizeQueryMapper<TModel, TEntity>
|
||||
{
|
||||
public abstract mapToDTO(raw: TModel, params?: MapperParamsType): Result<TEntity, Error>;
|
||||
|
||||
|
||||
@ -1,9 +1,18 @@
|
||||
import { Criteria, CriteriaToSequelizeConverter } from "@repo/rdx-criteria/server";
|
||||
import { IAggregateRootRepository, UniqueID } from "@repo/rdx-ddd";
|
||||
import { Result } from "@repo/rdx-utils";
|
||||
import { FindOptions, ModelDefined, Transaction } from "sequelize";
|
||||
import { FindOptions, ModelDefined, Sequelize, Transaction } from "sequelize";
|
||||
import { IMapperRegistry } from "../mappers";
|
||||
|
||||
export abstract class SequelizeRepository<T> implements IAggregateRootRepository<T> {
|
||||
protected readonly _database!: Sequelize;
|
||||
protected readonly _registry!: IMapperRegistry;
|
||||
|
||||
constructor(params: { mapperRegistry: IMapperRegistry; database: Sequelize }) {
|
||||
this._registry = params.mapperRegistry;
|
||||
this._database = params.database;
|
||||
}
|
||||
|
||||
protected convertCriteria(criteria: Criteria): FindOptions {
|
||||
return new CriteriaToSequelizeConverter().convert(criteria);
|
||||
}
|
||||
|
||||
@ -1,45 +0,0 @@
|
||||
import { toEmptyString } from "@repo/rdx-ddd";
|
||||
import { CreateCustomerInvoiceResponseDTO } from "../../../../common/dto";
|
||||
import { CustomerInvoice } from "../../../domain";
|
||||
|
||||
type CreateCustomerInvoiceItemsByInvoiceIdResponseDTO = CreateCustomerInvoiceResponseDTO["items"];
|
||||
|
||||
export class CreateCustomerInvoiceItemsPresenter {
|
||||
toDTO(invoice: CustomerInvoice): CreateCustomerInvoiceItemsByInvoiceIdResponseDTO {
|
||||
const { items } = invoice;
|
||||
return items.map((item, index) => ({
|
||||
id: item.id.toString(),
|
||||
position: String(index),
|
||||
description: toEmptyString(item.description, (value) => value.toPrimitive()),
|
||||
|
||||
quantity: item.quantity.match(
|
||||
(quantity) => {
|
||||
const { value, scale } = quantity.toPrimitive();
|
||||
return { value: value.toString(), scale: scale.toString() };
|
||||
},
|
||||
() => ({ value: "", scale: "" })
|
||||
),
|
||||
|
||||
unit_amount: item.unitAmount.match(
|
||||
(unitAmount) => {
|
||||
const { value, scale } = unitAmount.toPrimitive();
|
||||
return { value: value.toString(), scale: scale.toString() };
|
||||
},
|
||||
() => ({ value: "", scale: "" })
|
||||
),
|
||||
|
||||
discount_percentage: item.discountPercentage.match(
|
||||
(discountPercentage) => {
|
||||
const { value, scale } = discountPercentage.toPrimitive();
|
||||
return { value: value.toString(), scale: scale.toString() };
|
||||
},
|
||||
() => ({ value: "", scale: "" })
|
||||
),
|
||||
|
||||
total_amount: {
|
||||
value: item.totalAmount.toPrimitive().value.toString(),
|
||||
scale: item.totalAmount.toPrimitive().scale.toString(),
|
||||
},
|
||||
}));
|
||||
}
|
||||
}
|
||||
@ -1,69 +0,0 @@
|
||||
import { UpdateCustomerInvoiceByIdResponseDTO } from "@erp/customer-invoices/common/dto";
|
||||
import { toEmptyString } from "@repo/rdx-ddd";
|
||||
import { CustomerInvoice } from "../../../domain";
|
||||
import { CreateCustomerInvoiceItemsPresenter } from "./create-customer-invoice-items.presenter";
|
||||
|
||||
export class CreateCustomerInvoicePresenter {
|
||||
private _itemsPresenter!: CreateCustomerInvoiceItemsPresenter;
|
||||
|
||||
constructor() {
|
||||
this._itemsPresenter = new CreateCustomerInvoiceItemsPresenter();
|
||||
}
|
||||
|
||||
public toDTO(invoice: CustomerInvoice): UpdateCustomerInvoiceByIdResponseDTO {
|
||||
const items = this._itemsPresenter.toDTO(invoice);
|
||||
|
||||
return {
|
||||
id: invoice.id.toPrimitive(),
|
||||
company_id: invoice.companyId.toPrimitive(),
|
||||
|
||||
invoice_number: invoice.invoiceNumber.toString(),
|
||||
status: invoice.status.toPrimitive(),
|
||||
series: invoice.series.toString(),
|
||||
|
||||
invoice_date: invoice.invoiceDate.toDateString(),
|
||||
operation_date: toEmptyString(invoice.operationDate, (value) => value.toDateString()),
|
||||
|
||||
notes: toEmptyString(invoice.notes, (value) => value.toPrimitive()),
|
||||
|
||||
language_code: invoice.languageCode.toPrimitive(),
|
||||
currency_code: invoice.currencyCode.toPrimitive(),
|
||||
|
||||
subtotal_amount: {
|
||||
value: invoice.subtotalAmount.value.toString(),
|
||||
scale: invoice.subtotalAmount.scale.toString(),
|
||||
},
|
||||
|
||||
discount_percentage: {
|
||||
value: invoice.discountPercentage.value.toString(),
|
||||
scale: invoice.discountPercentage.scale.toString(),
|
||||
},
|
||||
|
||||
discount_amount: {
|
||||
value: invoice.discountAmount.value.toString(),
|
||||
scale: invoice.discountAmount.scale.toString(),
|
||||
},
|
||||
|
||||
taxable_amount: {
|
||||
value: invoice.taxableAmount.value.toString(),
|
||||
scale: invoice.taxableAmount.scale.toString(),
|
||||
},
|
||||
|
||||
tax_amount: {
|
||||
value: invoice.taxAmount.value.toString(),
|
||||
scale: invoice.taxAmount.scale.toString(),
|
||||
},
|
||||
|
||||
total_amount: {
|
||||
value: invoice.totalAmount.value.toString(),
|
||||
scale: invoice.totalAmount.scale.toString(),
|
||||
},
|
||||
|
||||
items,
|
||||
|
||||
metadata: {
|
||||
entity: "customer-invoices",
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
@ -1 +0,0 @@
|
||||
export * from "./create-customer-invoices.presenter";
|
||||
@ -1 +0,0 @@
|
||||
export * from "./delete-customer-invoice.use-case";
|
||||
@ -1,2 +0,0 @@
|
||||
export * from "./presenter";
|
||||
export * from "./get-customer-invoice.use-case";
|
||||
@ -1,16 +0,0 @@
|
||||
import { CustomerInvoiceItem } from "#/server/domain";
|
||||
import { IInvoicingContext } from "#/server/intrastructure";
|
||||
import { Collection } from "@rdx/core";
|
||||
|
||||
export const customerInvoiceItemPresenter = (items: Collection<CustomerInvoiceItem>, context: IInvoicingContext) =>
|
||||
items.totalCount > 0
|
||||
? items.items.map((item: CustomerInvoiceItem) => ({
|
||||
description: item.description.toString(),
|
||||
quantity: item.quantity.toString(),
|
||||
unit_measure: "",
|
||||
unit_price: item.unitPrice.toPrimitive() as IMoney_Response_DTO,
|
||||
subtotal: item.calculateSubtotal().toPrimitive() as IMoney_Response_DTO,
|
||||
tax_amount: item.calculateTaxAmount().toPrimitive() as IMoney_Response_DTO,
|
||||
total: item.calculateTotal().toPrimitive() as IMoney_Response_DTO,
|
||||
}))
|
||||
: [];
|
||||
@ -1,26 +0,0 @@
|
||||
import { ICustomerInvoiceParticipant } from "@/contexts/invoicing/domain";
|
||||
import { IInvoicingContext } from "@/contexts/invoicing/intrastructure/InvoicingContext";
|
||||
import { ICreateCustomerInvoice_Participant_Response_DTO } from "@shared/contexts";
|
||||
import { CustomerInvoiceParticipantAddressPresenter } from "./CustomerInvoiceParticipantAddress.presenter";
|
||||
|
||||
export const CustomerInvoiceParticipantPresenter = async (
|
||||
participant: ICustomerInvoiceParticipant,
|
||||
context: IInvoicingContext,
|
||||
): Promise<ICreateCustomerInvoice_Participant_Response_DTO | undefined> => {
|
||||
return {
|
||||
id: participant.id.toString(),
|
||||
tin: participant.tin.toString(),
|
||||
first_name: participant.firstName.toString(),
|
||||
last_name: participant.lastName.toString(),
|
||||
company_name: participant.companyName.toString(),
|
||||
|
||||
billing_address: await CustomerInvoiceParticipantAddressPresenter(
|
||||
participant.billingAddress!,
|
||||
context,
|
||||
),
|
||||
shipping_address: await CustomerInvoiceParticipantAddressPresenter(
|
||||
participant.shippingAddress!,
|
||||
context,
|
||||
),
|
||||
};
|
||||
};
|
||||
@ -1,19 +0,0 @@
|
||||
import { CustomerInvoiceParticipantAddress } from "@/contexts/invoicing/domain";
|
||||
import { IInvoicingContext } from "@/contexts/invoicing/intrastructure/InvoicingContext";
|
||||
import { ICreateCustomerInvoice_AddressParticipant_Response_DTO } from "@shared/contexts";
|
||||
|
||||
export const CustomerInvoiceParticipantAddressPresenter = async (
|
||||
address: CustomerInvoiceParticipantAddress,
|
||||
context: IInvoicingContext,
|
||||
): Promise<ICreateCustomerInvoice_AddressParticipant_Response_DTO> => {
|
||||
return {
|
||||
id: address.id.toString(),
|
||||
street: address.street.toString(),
|
||||
city: address.city.toString(),
|
||||
postal_code: address.postalCode.toString(),
|
||||
province: address.province.toString(),
|
||||
country: address.country.toString(),
|
||||
email: address.email.toString(),
|
||||
phone: address.phone.toString(),
|
||||
};
|
||||
};
|
||||
@ -1,47 +0,0 @@
|
||||
import { toEmptyString } from "@repo/rdx-ddd";
|
||||
import { GetCustomerInvoiceByIdResponseDTO } from "../../../../common/dto";
|
||||
import { CustomerInvoice } from "../../../domain";
|
||||
|
||||
type GetCustomerInvoiceItemsByInvoiceIdResponseDTO = GetCustomerInvoiceByIdResponseDTO["items"];
|
||||
|
||||
export class GetCustomerInvoiceItemsPresenter {
|
||||
toDTO(invoice: CustomerInvoice): GetCustomerInvoiceItemsByInvoiceIdResponseDTO {
|
||||
const { items } = invoice;
|
||||
|
||||
return items.map((item, index) => {
|
||||
const amounts = item.getAllAmounts();
|
||||
|
||||
return {
|
||||
id: item.id.toString(),
|
||||
position: String(index),
|
||||
description: toEmptyString(item.description, (value) => value.toPrimitive()),
|
||||
|
||||
quantity: item.quantity.match(
|
||||
(quantity) => {
|
||||
const { value, scale } = quantity.toPrimitive();
|
||||
return { value: value.toString(), scale: scale.toString() };
|
||||
},
|
||||
() => ({ value: "", scale: "" })
|
||||
),
|
||||
|
||||
unit_amount: item.unitAmount.match(
|
||||
(unitAmount) => {
|
||||
const { value, scale } = unitAmount.toPrimitive();
|
||||
return { value: value.toString(), scale: scale.toString() };
|
||||
},
|
||||
() => ({ value: "", scale: "" })
|
||||
),
|
||||
|
||||
discount_percentage: item.discountPercentage.match(
|
||||
(discountPercentage) => {
|
||||
const { value, scale } = discountPercentage.toPrimitive();
|
||||
return { value: value.toString(), scale: scale.toString() };
|
||||
},
|
||||
() => ({ value: "", scale: "" })
|
||||
),
|
||||
|
||||
total_amount: amounts.totalAmount.toPrimitive(),
|
||||
};
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -1,76 +0,0 @@
|
||||
import { IPresenter, IPresenterRegistry } from "@erp/core/api";
|
||||
import { toEmptyString } from "@repo/rdx-ddd";
|
||||
import { GetCustomerInvoiceByIdResponseDTO } from "../../../../common/dto";
|
||||
import { CustomerInvoice } from "../../../domain";
|
||||
import { GetCustomerInvoiceItemsPresenter } from "./get-invoice-items.presenter";
|
||||
|
||||
export class GetCustomerInvoicePresentwer implements IPresenter {
|
||||
private _itemsPresenter!: GetCustomerInvoiceItemsPresenter;
|
||||
|
||||
constructor(private presenterRegistry: IPresenterRegistry) {
|
||||
this._itemsPresenter = this.presenterRegistry.getPresenter({
|
||||
resource: "customer-invoice-item",
|
||||
projection: "FULL",
|
||||
});
|
||||
}
|
||||
|
||||
toOutput(params: {
|
||||
invoice: CustomerInvoice;
|
||||
}): GetCustomerInvoiceByIdResponseDTO {
|
||||
const { invoice } = params;
|
||||
const items = this._itemsPresenter.toDTO(invoice);
|
||||
|
||||
return {
|
||||
id: invoice.id.toString(),
|
||||
company_id: invoice.companyId.toString(),
|
||||
|
||||
invoice_number: invoice.invoiceNumber.toString(),
|
||||
status: invoice.status.toPrimitive(),
|
||||
series: toEmptyString(invoice.series, (value) => value.toString()),
|
||||
|
||||
invoice_date: invoice.invoiceDate.toDateString(),
|
||||
operation_date: toEmptyString(invoice.operationDate, (value) => value.toDateString()),
|
||||
|
||||
notes: toEmptyString(invoice.notes, (value) => value.toString()),
|
||||
|
||||
language_code: invoice.languageCode.toString(),
|
||||
currency_code: invoice.currencyCode.toString(),
|
||||
|
||||
/*subtotal_amount: {
|
||||
value: invoice.subtotalAmount.value.toString(),
|
||||
scale: invoice.subtotalAmount.scale.toString(),
|
||||
},
|
||||
|
||||
discount_percentage: {
|
||||
value: invoice.discountPercentage.value.toString(),
|
||||
scale: invoice.discountPercentage.scale.toString(),
|
||||
},
|
||||
|
||||
discount_amount: {
|
||||
value: invoice.discountAmount.value.toString(),
|
||||
scale: invoice.discountAmount.scale.toString(),
|
||||
},
|
||||
|
||||
taxable_amount: {
|
||||
value: invoice.taxableAmount.value.toString(),
|
||||
scale: invoice.taxableAmount.scale.toString(),
|
||||
},
|
||||
|
||||
tax_amount: {
|
||||
value: invoice.taxAmount.value.toString(),
|
||||
scale: invoice.taxAmount.scale.toString(),
|
||||
},
|
||||
|
||||
total_amount: {
|
||||
value: invoice.totalAmount.value.toString(),
|
||||
scale: invoice.totalAmount.scale.toString(),
|
||||
},*/
|
||||
|
||||
items,
|
||||
|
||||
metadata: {
|
||||
entity: "customer-invoices",
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
@ -1 +0,0 @@
|
||||
export * from "./get-invoice.presenter";
|
||||
@ -1,7 +1,2 @@
|
||||
export * from "./create-customer-invoice";
|
||||
export * from "./delete-customer-invoice";
|
||||
export * from "./get-customer-invoice";
|
||||
export * from "./list-customer-invoices";
|
||||
export * from "./report-customer-invoice";
|
||||
//export * from "./update-customer-invoice";
|
||||
export * from "./presenters";
|
||||
export * from "./use-cases";
|
||||
|
||||
@ -1,2 +0,0 @@
|
||||
export * from "./presenter";
|
||||
export * from "./list-customer-invoices.use-case";
|
||||
@ -1,2 +1,2 @@
|
||||
export * from "./full-domain";
|
||||
export * from "./list";
|
||||
export * from "./domain";
|
||||
export * from "./queries";
|
||||
|
||||
@ -1,74 +0,0 @@
|
||||
import { Presenter } 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 CustomerInvoicesListPresenter extends Presenter {
|
||||
protected _map(invoice: CustomerInvoiceListDTO) {
|
||||
const recipientDTO = invoice.recipient.toObjectString();
|
||||
|
||||
const invoiceDTO: ArrayElement<CustomerInvoiceListResponseDTO["items"]> = {
|
||||
id: invoice.id.toString(),
|
||||
company_id: invoice.companyId.toString(),
|
||||
customer_id: invoice.customerId.toString(),
|
||||
|
||||
invoice_number: invoice.invoiceNumber.toString(),
|
||||
status: invoice.status.toPrimitive(),
|
||||
series: toEmptyString(invoice.series, (value) => value.toString()),
|
||||
|
||||
invoice_date: invoice.invoiceDate.toDateString(),
|
||||
operation_date: toEmptyString(invoice.operationDate, (value) => value.toDateString()),
|
||||
|
||||
recipient: {
|
||||
customer_id: invoice.customerId.toString(),
|
||||
...recipientDTO,
|
||||
},
|
||||
|
||||
language_code: invoice.languageCode.code,
|
||||
currency_code: invoice.currencyCode.code,
|
||||
|
||||
taxes: invoice.taxes,
|
||||
|
||||
subtotal_amount: invoice.subtotalAmount.toObjectString(),
|
||||
discount_amount: invoice.discountAmount.toObjectString(),
|
||||
taxable_amount: invoice.taxableAmount.toObjectString(),
|
||||
taxes_amount: invoice.taxesAmount.toObjectString(),
|
||||
total_amount: invoice.totalAmount.toObjectString(),
|
||||
|
||||
metadata: {
|
||||
entity: "customer-invoice",
|
||||
},
|
||||
};
|
||||
|
||||
return invoiceDTO;
|
||||
}
|
||||
|
||||
toOutput(params: {
|
||||
customerInvoices: Collection<CustomerInvoiceListDTO>;
|
||||
criteria: Criteria;
|
||||
}): CustomerInvoiceListResponseDTO {
|
||||
const { customerInvoices, criteria } = params;
|
||||
|
||||
const invoices = customerInvoices.map((invoice) => this._map(invoice));
|
||||
const totalItems = customerInvoices.total();
|
||||
|
||||
return {
|
||||
page: criteria.pageNumber,
|
||||
per_page: criteria.pageSize,
|
||||
total_pages: Math.ceil(totalItems / criteria.pageSize),
|
||||
total_items: totalItems,
|
||||
items: invoices,
|
||||
metadata: {
|
||||
entity: "customer-invoices",
|
||||
criteria: criteria.toJSON(),
|
||||
//links: {
|
||||
// self: `/api/customer-invoices?page=${criteria.pageNumber}&per_page=${criteria.pageSize}`,
|
||||
// first: `/api/customer-invoices?page=1&per_page=${criteria.pageSize}`,
|
||||
// last: `/api/customer-invoices?page=${Math.ceil(totalItems / criteria.pageSize)}&per_page=${criteria.pageSize}`,
|
||||
//},
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
@ -1 +0,0 @@
|
||||
export * from "./customer-invoices.list.presenter";
|
||||
@ -1,2 +0,0 @@
|
||||
export * from "./presenter";
|
||||
export * from "./update-customer-invoice.use-case";
|
||||
@ -1 +0,0 @@
|
||||
export * from "./update-invoice.presenter";
|
||||
@ -1,46 +0,0 @@
|
||||
import { toEmptyString } from "@repo/rdx-ddd";
|
||||
import { UpdateCustomerInvoiceByIdResponseDTO } from "../../../../common/dto";
|
||||
import { CustomerInvoice } from "../../../domain";
|
||||
|
||||
type UpdateCustomerInvoiceItemsByInvoiceIdResponseDTO =
|
||||
UpdateCustomerInvoiceByIdResponseDTO["items"];
|
||||
|
||||
export class UpdateCustomerInvoiceItemsPresenter {
|
||||
toDTO(invoice: CustomerInvoice): UpdateCustomerInvoiceItemsByInvoiceIdResponseDTO {
|
||||
const { items } = invoice;
|
||||
return items.map((item, index) => ({
|
||||
id: item.id.toString(),
|
||||
position: String(index),
|
||||
description: toEmptyString(item.description, (value) => value.toPrimitive()),
|
||||
|
||||
quantity: item.quantity.match(
|
||||
(quantity) => {
|
||||
const { value, scale } = quantity.toPrimitive();
|
||||
return { value: value.toString(), scale: scale.toString() };
|
||||
},
|
||||
() => ({ value: "", scale: "" })
|
||||
),
|
||||
|
||||
unit_amount: item.unitAmount.match(
|
||||
(unitAmount) => {
|
||||
const { value, scale } = unitAmount.toPrimitive();
|
||||
return { value: value.toString(), scale: scale.toString() };
|
||||
},
|
||||
() => ({ value: "", scale: "" })
|
||||
),
|
||||
|
||||
discount_percentage: item.discountPercentage.match(
|
||||
(discountPercentage) => {
|
||||
const { value, scale } = discountPercentage.toPrimitive();
|
||||
return { value: value.toString(), scale: scale.toString() };
|
||||
},
|
||||
() => ({ value: "", scale: "" })
|
||||
),
|
||||
|
||||
total_amount: {
|
||||
value: item.totalAmount.toPrimitive().value.toString(),
|
||||
scale: item.totalAmount.toPrimitive().scale.toString(),
|
||||
},
|
||||
}));
|
||||
}
|
||||
}
|
||||
@ -1,110 +0,0 @@
|
||||
import { toEmptyString } from "@repo/rdx-ddd";
|
||||
import { UpdateCustomerInvoiceByIdResponseDTO } from "../../../../common/dto";
|
||||
import { CustomerInvoice } from "../../../domain";
|
||||
import { UpdateCustomerInvoiceItemsPresenter } from "./update-invoice-items.presenter";
|
||||
|
||||
export class UpdateCustomerInvoicePresenter {
|
||||
private _itemsPresenter!: UpdateCustomerInvoiceItemsPresenter;
|
||||
|
||||
constructor() {
|
||||
this._itemsPresenter = new UpdateCustomerInvoiceItemsPresenter();
|
||||
}
|
||||
|
||||
public toDTO(invoice: CustomerInvoice): UpdateCustomerInvoiceByIdResponseDTO {
|
||||
const items = this._itemsPresenter.toDTO(invoice);
|
||||
|
||||
return {
|
||||
id: invoice.id.toPrimitive(),
|
||||
company_id: invoice.companyId.toPrimitive(),
|
||||
|
||||
invoice_number: invoice.invoiceNumber.toString(),
|
||||
status: invoice.status.toPrimitive(),
|
||||
series: invoice.series.toString(),
|
||||
|
||||
invoice_date: invoice.invoiceDate.toDateString(),
|
||||
operation_date: toEmptyString(invoice.operationDate, (value) => value.toDateString()),
|
||||
|
||||
notes: toEmptyString(invoice.notes, (value) => value.toPrimitive()),
|
||||
|
||||
language_code: invoice.languageCode.toPrimitive(),
|
||||
currency_code: invoice.currencyCode.toPrimitive(),
|
||||
|
||||
subtotal_amount: {
|
||||
value: invoice.subtotalAmount.value.toString(),
|
||||
scale: invoice.subtotalAmount.scale.toString(),
|
||||
},
|
||||
|
||||
discount_percentage: {
|
||||
value: invoice.discountPercentage.value.toString(),
|
||||
scale: invoice.discountPercentage.scale.toString(),
|
||||
},
|
||||
|
||||
discount_amount: {
|
||||
value: invoice.discountAmount.value.toString(),
|
||||
scale: invoice.discountAmount.scale.toString(),
|
||||
},
|
||||
|
||||
taxable_amount: {
|
||||
value: invoice.taxableAmount.value.toString(),
|
||||
scale: invoice.taxableAmount.scale.toString(),
|
||||
},
|
||||
|
||||
tax_amount: {
|
||||
value: invoice.taxAmount.value.toString(),
|
||||
scale: invoice.taxAmount.scale.toString(),
|
||||
},
|
||||
|
||||
total_amount: {
|
||||
value: invoice.totalAmount.value.toString(),
|
||||
scale: invoice.totalAmount.scale.toString(),
|
||||
},
|
||||
|
||||
items,
|
||||
|
||||
metadata: {
|
||||
entity: "customer-invoices",
|
||||
},
|
||||
|
||||
//subtotal: customerInvoice.calculateSubtotal().toPrimitive(),
|
||||
|
||||
//total: customerInvoice.calculateTotal().toPrimitive(),
|
||||
|
||||
/*items:
|
||||
customerInvoice.items.size() > 0
|
||||
? customerInvoice.items.map((item: CustomerInvoiceItem) => ({
|
||||
description: item.description.toString(),
|
||||
quantity: item.quantity.toPrimitive(),
|
||||
unit_measure: "",
|
||||
unit_price: item.unitPrice.toPrimitive(),
|
||||
subtotal: item.calculateSubtotal().toPrimitive(),
|
||||
//tax_amount: item.calculateTaxAmount().toPrimitive(),
|
||||
total: item.calculateTotal().toPrimitive(),
|
||||
}))
|
||||
: [],*/
|
||||
|
||||
//sender: {}, //await CustomerInvoiceParticipantPresenter(customerInvoice.senderId, context),
|
||||
|
||||
/*recipient: await CustomerInvoiceParticipantPresenter(customerInvoice.recipient, context),
|
||||
items: customerInvoiceItemPresenter(customerInvoice.items, context),
|
||||
|
||||
payment_term: {
|
||||
payment_type: "",
|
||||
due_date: "",
|
||||
},
|
||||
|
||||
due_amount: {
|
||||
currency: customerInvoice.currency.toString(),
|
||||
precision: 2,
|
||||
amount: 0,
|
||||
},
|
||||
|
||||
custom_fields: [],
|
||||
|
||||
metadata: {
|
||||
create_time: "",
|
||||
last_updated_time: "",
|
||||
delete_time: "",
|
||||
},*/
|
||||
};
|
||||
}
|
||||
}
|
||||
@ -3,8 +3,8 @@ import { DuplicateEntityError, ITransactionManager } from "@erp/core/api";
|
||||
import { UniqueID } from "@repo/rdx-ddd";
|
||||
import { Result } from "@repo/rdx-utils";
|
||||
import { Transaction } from "sequelize";
|
||||
import { CreateCustomerInvoiceRequestDTO } from "../../../common/dto";
|
||||
import { CustomerInvoiceService } from "../../domain";
|
||||
import { CreateCustomerInvoiceRequestDTO } from "../../../../common/dto";
|
||||
import { CustomerInvoiceService } from "../../../domain";
|
||||
import { CreateCustomerInvoiceAssembler } from "./assembler";
|
||||
import { CreateCustomerInvoicePropsMapper } from "./map-dto-to-create-customer-invoice-props";
|
||||
|
||||
@ -18,8 +18,7 @@ export class CreateCustomerInvoiceUseCase {
|
||||
private readonly service: CustomerInvoiceService,
|
||||
private readonly transactionManager: ITransactionManager,
|
||||
private readonly assembler: CreateCustomerInvoiceAssembler,
|
||||
private readonly taxCatalog: JsonTaxCatalogProvider,
|
||||
|
||||
private readonly taxCatalog: JsonTaxCatalogProvider
|
||||
) {}
|
||||
|
||||
public execute(params: CreateCustomerInvoiceUseCaseInput) {
|
||||
@ -1,2 +1 @@
|
||||
export * from "./presenter";
|
||||
export * from "./create-customer-invoice.use-case";
|
||||
@ -20,7 +20,7 @@ import { Result } from "@repo/rdx-utils";
|
||||
import {
|
||||
CreateCustomerInvoiceItemRequestDTO,
|
||||
CreateCustomerInvoiceRequestDTO,
|
||||
} from "../../../common/dto";
|
||||
} from "../../../../common/dto";
|
||||
import {
|
||||
CustomerInvoiceItem,
|
||||
CustomerInvoiceItemDescription,
|
||||
@ -33,7 +33,7 @@ import {
|
||||
ItemAmount,
|
||||
ItemDiscount,
|
||||
ItemQuantity,
|
||||
} from "../../domain";
|
||||
} from "../../../domain";
|
||||
|
||||
/**
|
||||
* Convierte el DTO a las props validadas (CustomerProps).
|
||||
@ -51,7 +51,7 @@ export class CreateCustomerInvoicePropsMapper {
|
||||
private languageCode?: LanguageCode;
|
||||
private currencyCode?: CurrencyCode;
|
||||
|
||||
constructor(params: {taxCatalog: JsonTaxCatalogProvider}) {
|
||||
constructor(params: { taxCatalog: JsonTaxCatalogProvider }) {
|
||||
this.taxCatalog = params.taxCatalog;
|
||||
this.errors = [];
|
||||
}
|
||||
@ -63,8 +63,16 @@ export class CreateCustomerInvoicePropsMapper {
|
||||
const defaultStatus = CustomerInvoiceStatus.createDraft();
|
||||
|
||||
const invoiceId = extractOrPushError(UniqueID.create(dto.id), "id", this.errors);
|
||||
const companyId = extractOrPushError(UniqueID.create(dto.company_id), "company_id", this.errors);
|
||||
const customerId = extractOrPushError(UniqueID.create(dto.customer_id), "customer_id", this.errors);
|
||||
const companyId = extractOrPushError(
|
||||
UniqueID.create(dto.company_id),
|
||||
"company_id",
|
||||
this.errors
|
||||
);
|
||||
const customerId = extractOrPushError(
|
||||
UniqueID.create(dto.customer_id),
|
||||
"customer_id",
|
||||
this.errors
|
||||
);
|
||||
|
||||
const invoiceNumber = extractOrPushError(
|
||||
CustomerInvoiceNumber.create(dto.invoice_number),
|
||||
@ -230,4 +238,3 @@ export class CreateCustomerInvoicePropsMapper {
|
||||
return taxes;
|
||||
}
|
||||
}
|
||||
|
||||
@ -2,7 +2,7 @@ import { IPresenterRegistry, ITransactionManager } from "@erp/core/api";
|
||||
import { UniqueID } from "@repo/rdx-ddd";
|
||||
import { Result } from "@repo/rdx-utils";
|
||||
import { CustomerInvoiceService } from "../../domain";
|
||||
import { CustomerInvoiceFullPresenter } from "../presenters/full-domain";
|
||||
import { CustomerInvoiceFullPresenter } from "../presenters/domain";
|
||||
|
||||
type GetCustomerInvoiceUseCaseInput = {
|
||||
companyId: UniqueID;
|
||||
@ -0,0 +1,5 @@
|
||||
export * from "./create";
|
||||
export * from "./get-customer-invoice.use-case";
|
||||
export * from "./list-customer-invoices.use-case";
|
||||
export * from "./report";
|
||||
//export * from "./update-customer-invoice.use-case";
|
||||
@ -5,7 +5,7 @@ import { Result } from "@repo/rdx-utils";
|
||||
import { Transaction } from "sequelize";
|
||||
import { CustomerInvoiceListResponseDTO } from "../../../common/dto";
|
||||
import { CustomerInvoiceService } from "../../domain";
|
||||
import { CustomerInvoicesListPresenter } from "../presenters/list";
|
||||
import { ListCustomerInvoicesPresenter } from "../presenters";
|
||||
|
||||
type ListCustomerInvoicesUseCaseInput = {
|
||||
companyId: UniqueID;
|
||||
@ -26,7 +26,7 @@ export class ListCustomerInvoicesUseCase {
|
||||
const presenter = this.presenterRegistry.getPresenter({
|
||||
resource: "customer-invoice",
|
||||
projection: "LIST",
|
||||
}) as CustomerInvoicesListPresenter;
|
||||
}) as ListCustomerInvoicesPresenter;
|
||||
|
||||
return this.transactionManager.complete(async (transaction: Transaction) => {
|
||||
try {
|
||||
@ -0,0 +1,54 @@
|
||||
import { EntityNotFoundError, ITransactionManager } from "@erp/core/api";
|
||||
import { UniqueID } from "@repo/rdx-ddd";
|
||||
import { Result } from "@repo/rdx-utils";
|
||||
import { CustomerInvoiceService } from "../../../domain";
|
||||
|
||||
type DeleteCustomerInvoiceUseCaseInput = {
|
||||
companyId: UniqueID;
|
||||
invoice_id: string;
|
||||
};
|
||||
|
||||
export class DeleteCustomerInvoiceUseCase {
|
||||
constructor(
|
||||
private readonly service: CustomerInvoiceService,
|
||||
private readonly transactionManager: ITransactionManager
|
||||
) {}
|
||||
|
||||
public execute(params: DeleteCustomerInvoiceUseCaseInput) {
|
||||
const { invoice_id, companyId } = params;
|
||||
|
||||
const idOrError = UniqueID.create(invoice_id);
|
||||
|
||||
if (idOrError.isFailure) {
|
||||
return Result.fail(idOrError.error);
|
||||
}
|
||||
|
||||
const invoiceId = idOrError.data;
|
||||
|
||||
return this.transactionManager.complete(async (transaction) => {
|
||||
try {
|
||||
const existsCheck = await this.service.existsByIdInCompany(
|
||||
companyId,
|
||||
invoiceId,
|
||||
transaction
|
||||
);
|
||||
|
||||
if (existsCheck.isFailure) {
|
||||
return Result.fail(existsCheck.error);
|
||||
}
|
||||
|
||||
const invoiceExists = existsCheck.data;
|
||||
|
||||
if (!invoiceExists) {
|
||||
return Result.fail(
|
||||
new EntityNotFoundError("Customer invoice", "id", invoiceId.toString())
|
||||
);
|
||||
}
|
||||
|
||||
return await this.service.deleteInvoiceByIdInCompany(companyId, invoiceId, transaction);
|
||||
} catch (error: unknown) {
|
||||
return Result.fail(error as Error);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -1,7 +1,7 @@
|
||||
import { IPresenterRegistry, ITransactionManager } from "@erp/core/api";
|
||||
import { UniqueID } from "@repo/rdx-ddd";
|
||||
import { Result } from "@repo/rdx-utils";
|
||||
import { CustomerInvoiceService } from "../../domain";
|
||||
import { CustomerInvoiceService } from "../../../domain";
|
||||
import { CustomerInvoiceReportPDFPresenter } from "./reporter";
|
||||
|
||||
type ReportCustomerInvoiceUseCaseInput = {
|
||||
@ -2,7 +2,7 @@ import { Presenter } from "@erp/core/api";
|
||||
import * as handlebars from "handlebars";
|
||||
import { readFileSync } from "node:fs";
|
||||
import path from "node:path";
|
||||
import { CustomerInvoice } from "../../../domain";
|
||||
import { CustomerInvoice } from "../../../../domain";
|
||||
|
||||
export class CustomerInvoiceReportHTMLPresenter extends Presenter {
|
||||
toOutput(customerInvoice: CustomerInvoice): string {
|
||||
@ -1,7 +1,7 @@
|
||||
import { Presenter } from "@erp/core/api";
|
||||
import puppeteer from "puppeteer";
|
||||
import report from "puppeteer-report";
|
||||
import { CustomerInvoice } from "../../../domain";
|
||||
import { CustomerInvoice } from "../../../../domain";
|
||||
import { CustomerInvoiceReportHTMLPresenter } from "./customer-invoice.report.html";
|
||||
|
||||
// https://plnkr.co/edit/lWk6Yd?preview
|
||||
|
Before Width: | Height: | Size: 38 KiB After Width: | Height: | Size: 38 KiB |
|
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 1.8 KiB |
@ -1,28 +1,31 @@
|
||||
import { JsonTaxCatalogProvider, spainTaxCatalogProvider } from "@erp/core";
|
||||
// modules/invoice/infrastructure/invoice-dependencies.factory.ts
|
||||
|
||||
import type { IMapperRegistry, IPresenterRegistry, ModuleParams } from "@erp/core/api";
|
||||
|
||||
import {
|
||||
InMemoryMapperRegistry,
|
||||
InMemoryPresenterRegistry,
|
||||
SequelizeTransactionManager,
|
||||
} from "@erp/core/api";
|
||||
|
||||
import {
|
||||
CreateCustomerInvoiceUseCase,
|
||||
CustomerInvoiceFullPresenter,
|
||||
CustomerInvoiceItemsFullPresenter,
|
||||
CustomerInvoiceReportHTMLPresenter,
|
||||
CustomerInvoiceReportPDFPresenter,
|
||||
DeleteCustomerInvoiceUseCase,
|
||||
GetCustomerInvoiceUseCase,
|
||||
ListCustomerInvoicesPresenter,
|
||||
ListCustomerInvoicesUseCase,
|
||||
ReportCustomerInvoiceUseCase,
|
||||
} from "../application";
|
||||
|
||||
import { JsonTaxCatalogProvider, spainTaxCatalogProvider } from "@erp/core";
|
||||
import { CustomerInvoiceService } from "../domain";
|
||||
import { CustomerInvoiceFullMapper, CustomerInvoiceListMapper } from "./mappers";
|
||||
import { CustomerInvoiceDomainMapper, CustomerInvoiceListMapper } from "./mappers";
|
||||
import { CustomerInvoiceRepository } from "./sequelize";
|
||||
|
||||
type InvoiceDeps = {
|
||||
export type CustomerInvoiceDeps = {
|
||||
transactionManager: SequelizeTransactionManager;
|
||||
mapperRegistry: IMapperRegistry;
|
||||
presenterRegistry: IPresenterRegistry;
|
||||
@ -36,111 +39,97 @@ type InvoiceDeps = {
|
||||
get: () => GetCustomerInvoiceUseCase;
|
||||
create: () => CreateCustomerInvoiceUseCase;
|
||||
//update: () => UpdateCustomerInvoiceUseCase;
|
||||
delete: () => DeleteCustomerInvoiceUseCase;
|
||||
//delete: () => DeleteCustomerInvoiceUseCase;
|
||||
report: () => ReportCustomerInvoiceUseCase;
|
||||
};
|
||||
};
|
||||
|
||||
let _presenterRegistry: IPresenterRegistry | null = null;
|
||||
let _mapperRegistry: IMapperRegistry | null = null;
|
||||
|
||||
let _repo: CustomerInvoiceRepository | null = null;
|
||||
let _service: CustomerInvoiceService | null = null;
|
||||
let _catalogs: InvoiceDeps["catalogs"] | null = null;
|
||||
|
||||
export function getInvoiceDependencies(params: ModuleParams): InvoiceDeps {
|
||||
export function buildCustomerInvoiceDependencies(params: ModuleParams): CustomerInvoiceDeps {
|
||||
const { database } = params;
|
||||
const transactionManager = new SequelizeTransactionManager(database);
|
||||
if (!_catalogs) _catalogs = { taxes: spainTaxCatalogProvider };
|
||||
const catalogs = { taxes: spainTaxCatalogProvider };
|
||||
|
||||
if (!_mapperRegistry) {
|
||||
_mapperRegistry = new InMemoryMapperRegistry();
|
||||
_mapperRegistry.registerDomainMapper(
|
||||
"FULL",
|
||||
new CustomerInvoiceFullMapper({
|
||||
taxCatalog: _catalogs!.taxes,
|
||||
})
|
||||
);
|
||||
_mapperRegistry.registerReadModelMapper("LIST", new CustomerInvoiceListMapper());
|
||||
}
|
||||
if (!_repo) _repo = new CustomerInvoiceRepository({ mapperRegistry: _mapperRegistry, database });
|
||||
if (!_service) _service = new CustomerInvoiceService(_repo);
|
||||
|
||||
if (!_presenterRegistry) {
|
||||
_presenterRegistry = new InMemoryPresenterRegistry();
|
||||
_presenterRegistry.registerPresenters([
|
||||
// Mapper Registry
|
||||
const mapperRegistry = new InMemoryMapperRegistry();
|
||||
mapperRegistry
|
||||
.registerDomainMapper(
|
||||
{ resource: "customer-invoice" },
|
||||
new CustomerInvoiceDomainMapper({ taxCatalog: catalogs.taxes })
|
||||
)
|
||||
.registerQueryMappers([
|
||||
{
|
||||
key: {
|
||||
resource: "customer-invoice-items",
|
||||
projection: "FULL",
|
||||
},
|
||||
presenter: new CustomerInvoiceItemsFullPresenter(_presenterRegistry),
|
||||
},
|
||||
{
|
||||
key: {
|
||||
resource: "customer-invoice",
|
||||
projection: "FULL",
|
||||
},
|
||||
presenter: new CustomerInvoiceFullPresenter(_presenterRegistry),
|
||||
},
|
||||
|
||||
{
|
||||
key: {
|
||||
resource: "customer-invoice",
|
||||
projection: "LIST",
|
||||
},
|
||||
presenter: new ListCustomerInvoicesPresenter(_presenterRegistry),
|
||||
},
|
||||
|
||||
{
|
||||
key: {
|
||||
resource: "customer-invoice",
|
||||
projection: "REPORT",
|
||||
format: "HTML",
|
||||
},
|
||||
presenter: new CustomerInvoiceReportHTMLPresenter(_presenterRegistry),
|
||||
},
|
||||
|
||||
{
|
||||
key: {
|
||||
resource: "customer-invoice",
|
||||
projection: "REPORT",
|
||||
format: "PDF",
|
||||
},
|
||||
presenter: new CustomerInvoiceReportPDFPresenter(_presenterRegistry),
|
||||
key: { resource: "customer-invoice", query: "LIST" },
|
||||
mapper: new CustomerInvoiceListMapper(),
|
||||
},
|
||||
]);
|
||||
}
|
||||
|
||||
// Repository & Services
|
||||
const repo = new CustomerInvoiceRepository({ mapperRegistry, database });
|
||||
const service = new CustomerInvoiceService(repo);
|
||||
|
||||
// Presenter Registry
|
||||
const presenterRegistry = new InMemoryPresenterRegistry();
|
||||
presenterRegistry.registerPresenters([
|
||||
{
|
||||
key: {
|
||||
resource: "customer-invoice-items",
|
||||
projection: "FULL",
|
||||
},
|
||||
presenter: new CustomerInvoiceItemsFullPresenter(presenterRegistry),
|
||||
},
|
||||
{
|
||||
key: {
|
||||
resource: "customer-invoice",
|
||||
projection: "FULL",
|
||||
},
|
||||
presenter: new CustomerInvoiceFullPresenter(presenterRegistry),
|
||||
},
|
||||
{
|
||||
key: {
|
||||
resource: "customer-invoice",
|
||||
projection: "LIST",
|
||||
},
|
||||
presenter: new ListCustomerInvoicesPresenter(presenterRegistry),
|
||||
},
|
||||
{
|
||||
key: {
|
||||
resource: "customer-invoice",
|
||||
projection: "REPORT",
|
||||
format: "HTML",
|
||||
},
|
||||
presenter: new CustomerInvoiceReportHTMLPresenter(presenterRegistry),
|
||||
},
|
||||
{
|
||||
key: {
|
||||
resource: "customer-invoice",
|
||||
projection: "REPORT",
|
||||
format: "PDF",
|
||||
},
|
||||
presenter: new CustomerInvoiceReportPDFPresenter(presenterRegistry),
|
||||
},
|
||||
]);
|
||||
|
||||
return {
|
||||
transactionManager,
|
||||
repo: _repo,
|
||||
mapperRegistry: _mapperRegistry,
|
||||
presenterRegistry: _presenterRegistry,
|
||||
service: _service,
|
||||
catalogs: _catalogs,
|
||||
|
||||
repo,
|
||||
mapperRegistry,
|
||||
presenterRegistry,
|
||||
service,
|
||||
catalogs,
|
||||
build: {
|
||||
list: () =>
|
||||
new ListCustomerInvoicesUseCase(_service!, transactionManager!, _presenterRegistry!),
|
||||
get: () => new GetCustomerInvoiceUseCase(_service!, transactionManager!, _presenterRegistry!),
|
||||
list: () => new ListCustomerInvoicesUseCase(service, transactionManager, presenterRegistry),
|
||||
get: () => new GetCustomerInvoiceUseCase(service, transactionManager, presenterRegistry),
|
||||
create: () =>
|
||||
new CreateCustomerInvoiceUseCase(
|
||||
_service!,
|
||||
transactionManager!,
|
||||
_presenterRegistry!,
|
||||
_catalogs!.taxes
|
||||
service,
|
||||
transactionManager,
|
||||
presenterRegistry,
|
||||
catalogs.taxes
|
||||
),
|
||||
/*update: () =>
|
||||
new UpdateCustomerInvoiceUseCase(
|
||||
_service!,
|
||||
transactionManager!,
|
||||
_presenterRegistry!,
|
||||
_catalogs!.taxes
|
||||
),*/
|
||||
delete: () => new DeleteCustomerInvoiceUseCase(_service!, transactionManager!),
|
||||
// update: () => new UpdateCustomerInvoiceUseCase(service, transactionManager),
|
||||
// delete: () => new DeleteCustomerInvoiceUseCase(service, transactionManager),
|
||||
report: () =>
|
||||
new ReportCustomerInvoiceUseCase(_service!, transactionManager!, _presenterRegistry!),
|
||||
new ReportCustomerInvoiceUseCase(service, transactionManager, presenterRegistry),
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
@ -5,28 +5,26 @@ import { Sequelize } from "sequelize";
|
||||
import {
|
||||
CreateCustomerInvoiceRequestSchema,
|
||||
CustomerInvoiceListRequestSchema,
|
||||
DeleteCustomerInvoiceByIdRequestSchema,
|
||||
GetCustomerInvoiceByIdRequestSchema,
|
||||
ReportCustomerInvoiceByIdRequestSchema,
|
||||
} from "../../../common/dto";
|
||||
import { getInvoiceDependencies } from "../dependencies";
|
||||
import { buildCustomerInvoiceDependencies } from "../dependencies";
|
||||
import {
|
||||
CreateCustomerInvoiceController,
|
||||
DeleteCustomerInvoiceController,
|
||||
GetCustomerInvoiceController,
|
||||
ListCustomerInvoicesController,
|
||||
ReportCustomerInvoiceController,
|
||||
} from "./controllers";
|
||||
|
||||
export const customerInvoicesRouter = (params: ModuleParams) => {
|
||||
const { app, database, baseRoutePath, logger } = params as {
|
||||
const { app, baseRoutePath, logger } = params as {
|
||||
app: Application;
|
||||
database: Sequelize;
|
||||
baseRoutePath: string;
|
||||
logger: ILogger;
|
||||
};
|
||||
|
||||
const deps = getInvoiceDependencies(params);
|
||||
const deps = buildCustomerInvoiceDependencies(params);
|
||||
|
||||
const router: Router = Router({ mergeParams: true });
|
||||
|
||||
@ -94,7 +92,7 @@ export const customerInvoicesRouter = (params: ModuleParams) => {
|
||||
}
|
||||
);*/
|
||||
|
||||
router.delete(
|
||||
/*router.delete(
|
||||
"/:invoice_id",
|
||||
//checkTabContext,
|
||||
|
||||
@ -104,7 +102,7 @@ export const customerInvoicesRouter = (params: ModuleParams) => {
|
||||
const controller = new DeleteCustomerInvoiceController(useCase);
|
||||
return controller.execute(req, res, next);
|
||||
}
|
||||
);
|
||||
);*/
|
||||
|
||||
router.get(
|
||||
"/:invoice_id/report",
|
||||
|
||||
@ -19,28 +19,28 @@ import {
|
||||
ItemTaxes,
|
||||
} from "../../../domain";
|
||||
import { CustomerInvoiceItemCreationAttributes, CustomerInvoiceItemModel } from "../../sequelize";
|
||||
import { ItemTaxesMapper } from "./item-taxes.full.mapper";
|
||||
import { ItemTaxesDomainMapper } from "./item-taxes.mapper";
|
||||
|
||||
export interface ICustomerInvoiceItemMapper
|
||||
export interface ICustomerInvoiceItemDomainMapper
|
||||
extends ISequelizeDomainMapper<
|
||||
CustomerInvoiceItemModel,
|
||||
CustomerInvoiceItemCreationAttributes,
|
||||
CustomerInvoiceItem
|
||||
> {}
|
||||
|
||||
export class CustomerInvoiceItemMapper
|
||||
export class CustomerInvoiceItemDomainMapper
|
||||
extends SequelizeDomainMapper<
|
||||
CustomerInvoiceItemModel,
|
||||
CustomerInvoiceItemCreationAttributes,
|
||||
CustomerInvoiceItem
|
||||
>
|
||||
implements ICustomerInvoiceItemMapper
|
||||
implements ICustomerInvoiceItemDomainMapper
|
||||
{
|
||||
private _taxesMapper: ItemTaxesMapper;
|
||||
private _taxesMapper: ItemTaxesDomainMapper;
|
||||
|
||||
constructor(params: MapperParamsType) {
|
||||
super();
|
||||
this._taxesMapper = new ItemTaxesMapper(params);
|
||||
this._taxesMapper = new ItemTaxesDomainMapper(params);
|
||||
}
|
||||
|
||||
private mapAttributesToDomain(source: CustomerInvoiceItemModel, params?: MapperParamsType) {
|
||||
@ -26,24 +26,24 @@ import {
|
||||
} from "../../../domain";
|
||||
import { InvoiceTaxes } from "../../../domain/entities/invoice-taxes";
|
||||
import { CustomerInvoiceCreationAttributes, CustomerInvoiceModel } from "../../sequelize";
|
||||
import { CustomerInvoiceItemMapper as CustomerInvoiceItemFullMapper } from "./customer-invoice-item.full.mapper";
|
||||
import { InvoiceRecipientMapper as InvoiceRecipientFullMapper } from "./invoice-recipient.full.mapper";
|
||||
import { TaxesMapper as TaxesFullMapper } from "./taxes.full.mapper";
|
||||
import { CustomerInvoiceItemDomainMapper as CustomerInvoiceItemFullMapper } from "./customer-invoice-item.mapper";
|
||||
import { InvoiceRecipientDomainMapper as InvoiceRecipientFullMapper } from "./invoice-recipient.mapper";
|
||||
import { TaxesDomainMapper as TaxesFullMapper } from "./taxes.mapper";
|
||||
|
||||
export interface ICustomerInvoiceFullMapper
|
||||
export interface ICustomerInvoiceDomainMapper
|
||||
extends ISequelizeDomainMapper<
|
||||
CustomerInvoiceModel,
|
||||
CustomerInvoiceCreationAttributes,
|
||||
CustomerInvoice
|
||||
> {}
|
||||
|
||||
export class CustomerInvoiceFullMapper
|
||||
export class CustomerInvoiceDomainMapper
|
||||
extends SequelizeDomainMapper<
|
||||
CustomerInvoiceModel,
|
||||
CustomerInvoiceCreationAttributes,
|
||||
CustomerInvoice
|
||||
>
|
||||
implements ICustomerInvoiceFullMapper
|
||||
implements ICustomerInvoiceDomainMapper
|
||||
{
|
||||
private _itemsMapper: CustomerInvoiceItemFullMapper;
|
||||
private _recipientMapper: InvoiceRecipientFullMapper;
|
||||
@ -0,0 +1 @@
|
||||
export * from "./customer-invoice.mapper";
|
||||
@ -19,7 +19,7 @@ import { Maybe, Result } from "@repo/rdx-utils";
|
||||
import { CustomerInvoiceProps, InvoiceRecipient } from "../../../domain";
|
||||
import { CustomerInvoiceModel } from "../../sequelize";
|
||||
|
||||
export class InvoiceRecipientMapper {
|
||||
export class InvoiceRecipientDomainMapper {
|
||||
public mapToDomain(
|
||||
source: CustomerInvoiceModel,
|
||||
params?: MapperParamsType
|
||||
@ -14,7 +14,7 @@ import {
|
||||
CustomerInvoiceItemTaxModel,
|
||||
} from "../../sequelize";
|
||||
|
||||
export class ItemTaxesMapper extends SequelizeDomainMapper<
|
||||
export class ItemTaxesDomainMapper extends SequelizeDomainMapper<
|
||||
CustomerInvoiceItemTaxModel,
|
||||
CustomerInvoiceItemCreationAttributes,
|
||||
ItemTax
|
||||
@ -62,10 +62,10 @@ export class ItemTaxesMapper extends SequelizeDomainMapper<
|
||||
return createResult;
|
||||
}
|
||||
|
||||
public mapToPersistence(
|
||||
/*public mapToPersistence(
|
||||
source: ItemTax,
|
||||
params?: MapperParamsType
|
||||
): CustomerInvoiceItemCreationAttributes {
|
||||
throw new Error("not implemented");
|
||||
}
|
||||
}*/
|
||||
}
|
||||
@ -12,7 +12,7 @@ import { CustomerInvoiceProps } from "../../../domain";
|
||||
import { InvoiceTax } from "../../../domain/entities/invoice-taxes";
|
||||
import { CustomerInvoiceTaxCreationAttributes, CustomerInvoiceTaxModel } from "../../sequelize";
|
||||
|
||||
export class TaxesMapper extends SequelizeDomainMapper<
|
||||
export class TaxesDomainMapper extends SequelizeDomainMapper<
|
||||
CustomerInvoiceTaxModel,
|
||||
CustomerInvoiceTaxCreationAttributes,
|
||||
InvoiceTax
|
||||
@ -64,10 +64,10 @@ export class TaxesMapper extends SequelizeDomainMapper<
|
||||
return createResult;
|
||||
}
|
||||
|
||||
public mapToPersistence(
|
||||
/*public mapToPersistence(
|
||||
source: InvoiceTax,
|
||||
params?: MapperParamsType
|
||||
): CustomerInvoiceTaxCreationAttributes {
|
||||
throw new Error("not implemented");
|
||||
}
|
||||
}*/
|
||||
}
|
||||
@ -1 +0,0 @@
|
||||
export * from "./customer-invoice.full.mapper";
|
||||
@ -1,2 +1,2 @@
|
||||
export * from "./full-domain";
|
||||
export * from "./list";
|
||||
export * from "./domain";
|
||||
export * from "./queries";
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import {
|
||||
ISequelizeReadModelMapper,
|
||||
ISequelizeQueryMapper,
|
||||
MapperParamsType,
|
||||
SequelizeReadModelMapper,
|
||||
SequelizeQueryMapper,
|
||||
ValidationErrorCollection,
|
||||
ValidationErrorDetail,
|
||||
extractOrPushError,
|
||||
@ -56,10 +56,10 @@ export type CustomerInvoiceListDTO = {
|
||||
};
|
||||
|
||||
export interface ICustomerInvoiceListMapper
|
||||
extends ISequelizeReadModelMapper<CustomerInvoiceModel, CustomerInvoiceListDTO> {}
|
||||
extends ISequelizeQueryMapper<CustomerInvoiceModel, CustomerInvoiceListDTO> {}
|
||||
|
||||
export class CustomerInvoiceListMapper
|
||||
extends SequelizeReadModelMapper<CustomerInvoiceModel, CustomerInvoiceListDTO>
|
||||
extends SequelizeQueryMapper<CustomerInvoiceModel, CustomerInvoiceListDTO>
|
||||
implements ICustomerInvoiceListMapper
|
||||
{
|
||||
private _recipientMapper: InvoiceRecipientListMapper;
|
||||
@ -10,9 +10,9 @@ import {
|
||||
} from "@repo/rdx-ddd";
|
||||
|
||||
import {
|
||||
IReadModelMapperWithBulk,
|
||||
IQueryMapperWithBulk,
|
||||
MapperParamsType,
|
||||
SequelizeReadModelMapper,
|
||||
SequelizeQueryMapper,
|
||||
ValidationErrorDetail,
|
||||
extractOrPushError,
|
||||
} from "@erp/core/api";
|
||||
@ -23,10 +23,10 @@ import { CustomerInvoiceModel } from "../../sequelize";
|
||||
import { CustomerInvoiceListDTO } from "./customer-invoice.list.mapper";
|
||||
|
||||
interface IInvoiceRecipientListMapper
|
||||
extends IReadModelMapperWithBulk<CustomerInvoiceModel, InvoiceRecipient> {}
|
||||
extends IQueryMapperWithBulk<CustomerInvoiceModel, InvoiceRecipient> {}
|
||||
|
||||
export class InvoiceRecipientListMapper
|
||||
extends SequelizeReadModelMapper<CustomerInvoiceModel, InvoiceRecipient>
|
||||
extends SequelizeQueryMapper<CustomerInvoiceModel, InvoiceRecipient>
|
||||
implements IInvoiceRecipientListMapper
|
||||
{
|
||||
public mapToDTO(
|
||||
@ -1,37 +1,23 @@
|
||||
import {
|
||||
EntityNotFoundError,
|
||||
IMapperRegistry,
|
||||
SequelizeRepository,
|
||||
translateSequelizeError,
|
||||
} from "@erp/core/api";
|
||||
import { EntityNotFoundError, SequelizeRepository, translateSequelizeError } from "@erp/core/api";
|
||||
import { Criteria, CriteriaToSequelizeConverter } from "@repo/rdx-criteria/server";
|
||||
import { UniqueID } from "@repo/rdx-ddd";
|
||||
import { Collection, Result } from "@repo/rdx-utils";
|
||||
import { Sequelize, Transaction } from "sequelize";
|
||||
import { Transaction } from "sequelize";
|
||||
import { CustomerInvoice, ICustomerInvoiceRepository } from "../../domain";
|
||||
import {
|
||||
CustomerInvoiceListDTO,
|
||||
ICustomerInvoiceFullMapper,
|
||||
ICustomerInvoiceDomainMapper,
|
||||
ICustomerInvoiceListMapper,
|
||||
} from "../mappers";
|
||||
import { CustomerInvoiceItemTaxModel } from "./customer-invoice-item-tax.model";
|
||||
import { CustomerInvoiceItemModel } from "./customer-invoice-item.model";
|
||||
import { CustomerInvoiceTaxModel } from "./customer-invoice-tax.model";
|
||||
import { CustomerInvoiceModel } from "./customer-invoice.model";
|
||||
import { CustomerInvoiceItemTaxModel } from "./models/customer-invoice-item-tax.model";
|
||||
import { CustomerInvoiceItemModel } from "./models/customer-invoice-item.model";
|
||||
import { CustomerInvoiceTaxModel } from "./models/customer-invoice-tax.model";
|
||||
import { CustomerInvoiceModel } from "./models/customer-invoice.model";
|
||||
|
||||
export class CustomerInvoiceRepository
|
||||
extends SequelizeRepository<CustomerInvoice>
|
||||
implements ICustomerInvoiceRepository
|
||||
{
|
||||
private readonly _database!: Sequelize;
|
||||
private readonly _registry!: IMapperRegistry;
|
||||
|
||||
constructor(params: { mapperRegistry: IMapperRegistry; database: Sequelize }) {
|
||||
super();
|
||||
this._registry = params.mapperRegistry;
|
||||
this._database = params.database;
|
||||
}
|
||||
|
||||
// Listado por tenant con criteria saneada
|
||||
/* async searchInCompany(criteria: any, companyId: string): Promise<{
|
||||
rows: InvoiceListRow[];
|
||||
@ -78,7 +64,9 @@ export class CustomerInvoiceRepository
|
||||
transaction: Transaction
|
||||
): Promise<Result<CustomerInvoice, Error>> {
|
||||
try {
|
||||
const mapper: ICustomerInvoiceFullMapper = this._registry.getDomainMapper("FULL");
|
||||
const mapper: ICustomerInvoiceDomainMapper = this._registry.getDomainMapper({
|
||||
resource: "customer-invoice",
|
||||
});
|
||||
const mapperData = mapper.mapToPersistence(invoice);
|
||||
|
||||
if (mapperData.isFailure) {
|
||||
@ -134,7 +122,7 @@ export class CustomerInvoiceRepository
|
||||
transaction: Transaction
|
||||
): Promise<Result<CustomerInvoice, Error>> {
|
||||
try {
|
||||
const mapper: ICustomerInvoiceFullMapper = this._registry.getDomainMapper("FULL");
|
||||
const mapper: ICustomerInvoiceDomainMapper = this._registry.getDomainMapper("FULL");
|
||||
const { CustomerModel } = this._database.models;
|
||||
|
||||
const row = await CustomerInvoiceModel.findOne({
|
||||
@ -194,7 +182,7 @@ export class CustomerInvoiceRepository
|
||||
transaction: Transaction
|
||||
): Promise<Result<Collection<CustomerInvoiceListDTO>, Error>> {
|
||||
try {
|
||||
const mapper: ICustomerInvoiceListMapper = this._registry.getReadModelMapper("LIST");
|
||||
const mapper: ICustomerInvoiceListMapper = this._registry.getQueryMapper("LIST");
|
||||
const { CustomerModel } = this._database.models;
|
||||
const converter = new CriteriaToSequelizeConverter();
|
||||
const query = converter.convert(criteria);
|
||||
|
||||
@ -1,13 +1,10 @@
|
||||
import customerInvoiceItemTaxesModelInit from "./customer-invoice-item-tax.model";
|
||||
import customerInvoiceItemModelInit from "./customer-invoice-item.model";
|
||||
import customerInvoiceTaxesModelInit from "./customer-invoice-tax.model";
|
||||
import customerInvoiceModelInit from "./customer-invoice.model";
|
||||
import customerInvoiceItemTaxesModelInit from "./models/customer-invoice-item-tax.model";
|
||||
import customerInvoiceItemModelInit from "./models/customer-invoice-item.model";
|
||||
import customerInvoiceTaxesModelInit from "./models/customer-invoice-tax.model";
|
||||
import customerInvoiceModelInit from "./models/customer-invoice.model";
|
||||
|
||||
export * from "./customer-invoice-item-tax.model";
|
||||
export * from "./customer-invoice-item.model";
|
||||
export * from "./customer-invoice-tax.model";
|
||||
export * from "./customer-invoice.model";
|
||||
export * from "./customer-invoice.repository";
|
||||
export * from "./models";
|
||||
|
||||
// Array de inicializadores para que registerModels() lo use
|
||||
export const models = [
|
||||
|
||||
@ -6,7 +6,7 @@ import {
|
||||
NonAttribute,
|
||||
Sequelize,
|
||||
} from "sequelize";
|
||||
import { CustomerInvoiceItem } from "../../domain";
|
||||
import { CustomerInvoiceItem } from "../../../domain";
|
||||
|
||||
export type CustomerInvoiceItemTaxCreationAttributes = InferCreationAttributes<
|
||||
CustomerInvoiceItemTaxModel,
|
||||
@ -6,7 +6,7 @@ import {
|
||||
NonAttribute,
|
||||
Sequelize,
|
||||
} from "sequelize";
|
||||
import { CustomerInvoice } from "../../domain";
|
||||
import { CustomerInvoice } from "../../../domain";
|
||||
|
||||
export type CustomerInvoiceTaxCreationAttributes = InferCreationAttributes<
|
||||
CustomerInvoiceTaxModel,
|
||||
@ -0,0 +1,4 @@
|
||||
export * from "./customer-invoice-item-tax.model";
|
||||
export * from "./customer-invoice-item.model";
|
||||
export * from "./customer-invoice-tax.model";
|
||||
export * from "./customer-invoice.model";
|
||||
@ -1,5 +1,9 @@
|
||||
import type { IMapperRegistry, IPresenterRegistry, ModuleParams } from "@erp/core/api";
|
||||
import { InMemoryMapperRegistry, SequelizeTransactionManager } from "@erp/core/api";
|
||||
import {
|
||||
InMemoryMapperRegistry,
|
||||
InMemoryPresenterRegistry,
|
||||
SequelizeTransactionManager,
|
||||
} from "@erp/core/api";
|
||||
|
||||
import {
|
||||
CreateCustomerUseCase,
|
||||
@ -9,10 +13,10 @@ import {
|
||||
UpdateCustomerUseCase,
|
||||
} from "../application";
|
||||
import { CustomerService } from "../domain";
|
||||
import { CustomerMapper } from "./mappers";
|
||||
import { CustomerDomainMapper } from "./mappers";
|
||||
import { CustomerRepository } from "./sequelize";
|
||||
|
||||
type CustomerDeps = {
|
||||
export type CustomerDeps = {
|
||||
transactionManager: SequelizeTransactionManager;
|
||||
mapperRegistry: IMapperRegistry;
|
||||
presenterRegistry: IPresenterRegistry;
|
||||
@ -27,46 +31,37 @@ type CustomerDeps = {
|
||||
};
|
||||
};
|
||||
|
||||
const _presenterRegistry: IPresenterRegistry | null = null;
|
||||
let _mapperRegistry: IMapperRegistry | null = null;
|
||||
|
||||
let _repo: CustomerRepository | null = null;
|
||||
let _service: CustomerService | null = null;
|
||||
|
||||
export function getCustomerDependencies(params: ModuleParams): CustomerDeps {
|
||||
export function buildCustomerDependencies(params: ModuleParams): CustomerDeps {
|
||||
const { database } = params;
|
||||
const transactionManager = new SequelizeTransactionManager(database);
|
||||
|
||||
if (!_mapperRegistry) {
|
||||
_mapperRegistry = new InMemoryMapperRegistry();
|
||||
_mapperRegistry.registerDomainMapper("FULL", new CustomerMapper());
|
||||
}
|
||||
// Mapper Registry
|
||||
const mapperRegistry = new InMemoryMapperRegistry();
|
||||
mapperRegistry.registerDomainMapper({ resource: "customer" }, new CustomerDomainMapper());
|
||||
|
||||
if (!_repo) _repo = new CustomerRepository({ mapperRegistry: _mapperRegistry });
|
||||
if (!_service) _service = new CustomerService(_repo);
|
||||
// Repository & Services
|
||||
const repo = new CustomerRepository({ mapperRegistry: _mapperRegistry, database });
|
||||
const service = new CustomerService(repo);
|
||||
|
||||
/*if (!_presenterRegistry) {
|
||||
_presenterRegistry = new InMemoryPresenterRegistry();
|
||||
|
||||
_presenterRegistry.registerPresenters([
|
||||
{
|
||||
key: { resource: "customer", projection: "FULL" },
|
||||
presenter: new ListCustomersAssembler(),
|
||||
},
|
||||
{
|
||||
key: { resource: "customer", projection: "LIST" },
|
||||
presenter: new GetCustomerAssembler(),
|
||||
},
|
||||
]);
|
||||
}*/
|
||||
// Presenter Registry
|
||||
const presenterRegistry = new InMemoryPresenterRegistry();
|
||||
presenterRegistry.registerPresenters([
|
||||
{
|
||||
key: { resource: "customer", projection: "FULL" },
|
||||
presenter: new ListCustomersAssembler(),
|
||||
},
|
||||
{
|
||||
key: { resource: "customer", projection: "LIST" },
|
||||
presenter: new GetCustomerAssembler(),
|
||||
},
|
||||
]);
|
||||
|
||||
return {
|
||||
transactionManager,
|
||||
repo: _repo,
|
||||
mapperRegistry: _mapperRegistry,
|
||||
//presenterRegistry: _presenterRegistry,
|
||||
service: _service,
|
||||
|
||||
repo,
|
||||
mapperRegistry,
|
||||
presenterRegistry,
|
||||
service,
|
||||
build: {
|
||||
/*list: () => new ListCustomersUseCase(_service!, transactionManager!, presenterRegistry!),
|
||||
get: () => new GetCustomerUseCase(_service!, transactionManager!, presenterRegistry!),
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import {
|
||||
ISequelizeMapper,
|
||||
ISequelizeDomainMapper,
|
||||
MapperParamsType,
|
||||
SequelizeDomainMapper,
|
||||
ValidationErrorCollection,
|
||||
@ -27,15 +27,15 @@ import {
|
||||
toNullable,
|
||||
} from "@repo/rdx-ddd";
|
||||
import { Collection, Result, isNullishOrEmpty } from "@repo/rdx-utils";
|
||||
import { Customer, CustomerProps, CustomerStatus } from "../../domain";
|
||||
import { CustomerCreationAttributes, CustomerModel } from "../sequelize";
|
||||
import { Customer, CustomerProps, CustomerStatus } from "../../../domain";
|
||||
import { CustomerCreationAttributes, CustomerModel } from "../../sequelize";
|
||||
|
||||
export interface ICustomerMapper
|
||||
extends ISequelizeMapper<CustomerModel, CustomerCreationAttributes, Customer> {}
|
||||
export interface ICustomerDomainMapper
|
||||
extends ISequelizeDomainMapper<CustomerModel, CustomerCreationAttributes, Customer> {}
|
||||
|
||||
export class CustomerMapper
|
||||
export class CustomerDomainMapper
|
||||
extends SequelizeDomainMapper<CustomerModel, CustomerCreationAttributes, Customer>
|
||||
implements ICustomerMapper
|
||||
implements ICustomerDomainMapper
|
||||
{
|
||||
public mapToDomain(source: CustomerModel, params?: MapperParamsType): Result<Customer, Error> {
|
||||
try {
|
||||
@ -0,0 +1 @@
|
||||
export * from "./customer.full.mapper";
|
||||
@ -1 +1,2 @@
|
||||
export * from "./customer.mapper";
|
||||
export * from "./domain";
|
||||
export * from "./queries";
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import customerModelInit from "./customer.model";
|
||||
import customerModelInit from "./models/customer.model";
|
||||
|
||||
export * from "./customer.model";
|
||||
export * from "./customer.repository";
|
||||
export * from "./models";
|
||||
export * from "./repositories";
|
||||
|
||||
// Array de inicializadores para que registerModels() lo use
|
||||
export const models = [customerModelInit];
|
||||
|
||||
@ -0,0 +1 @@
|
||||
export * from "./customer.model";
|
||||
@ -3,21 +3,13 @@ import { Criteria, CriteriaToSequelizeConverter } from "@repo/rdx-criteria/serve
|
||||
import { UniqueID } from "@repo/rdx-ddd";
|
||||
import { Collection, Result } from "@repo/rdx-utils";
|
||||
import { Transaction } from "sequelize";
|
||||
import { Customer, ICustomerRepository } from "../../domain";
|
||||
import { ICustomerMapper } from "../mappers/customer.mapper";
|
||||
import { CustomerModel } from "./customer.model";
|
||||
import { Customer, ICustomerRepository } from "../../../domain";
|
||||
import { CustomerModel } from "../models/customer.model";
|
||||
|
||||
export class CustomerRepository
|
||||
extends SequelizeRepository<Customer>
|
||||
implements ICustomerRepository
|
||||
{
|
||||
private readonly mapper!: ICustomerMapper;
|
||||
|
||||
constructor(mapper: ICustomerMapper) {
|
||||
super();
|
||||
this.mapper = mapper;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Guarda un nuevo cliente o actualiza uno existente.
|
||||
@ -28,9 +20,20 @@ export class CustomerRepository
|
||||
*/
|
||||
async save(customer: Customer, transaction: Transaction): Promise<Result<Customer, Error>> {
|
||||
try {
|
||||
const data = this.mapper.mapToPersistence(customer);
|
||||
const mapper: ICustomerDomainMapper = this._registry.getDomainMapper({
|
||||
resource: "customer",
|
||||
});
|
||||
|
||||
const mapperData = mapper.mapToPersistence(customer);
|
||||
|
||||
if (mapperData.isFailure) {
|
||||
return Result.fail(mapperData.error);
|
||||
}
|
||||
|
||||
const { data } = mapperData;
|
||||
|
||||
const [instance] = await CustomerModel.upsert(data, { transaction, returning: true });
|
||||
const savedCustomer = this.mapper.mapToDomain(instance);
|
||||
const savedCustomer = mapper.mapToDomain(instance);
|
||||
return savedCustomer;
|
||||
} catch (err: unknown) {
|
||||
return Result.fail(translateSequelizeError(err));
|
||||
@ -75,6 +78,10 @@ export class CustomerRepository
|
||||
transaction?: Transaction
|
||||
): Promise<Result<Customer, Error>> {
|
||||
try {
|
||||
const mapper: ICustomerDomainMapper = this._registry.getDomainMapper({
|
||||
resource: "customer",
|
||||
});
|
||||
|
||||
const row = await CustomerModel.findOne({
|
||||
where: { id: id.toString(), company_id: companyId.toString() },
|
||||
transaction,
|
||||
@ -84,7 +91,7 @@ export class CustomerRepository
|
||||
return Result.fail(new EntityNotFoundError("Customer", "id", id.toString()));
|
||||
}
|
||||
|
||||
const customer = this.mapper.mapToDomain(row);
|
||||
const customer = mapper.mapToDomain(row);
|
||||
return customer;
|
||||
} catch (error: any) {
|
||||
return Result.fail(translateSequelizeError(error));
|
||||
@ -107,6 +114,10 @@ export class CustomerRepository
|
||||
transaction?: Transaction
|
||||
): Promise<Result<Collection<Customer>>> {
|
||||
try {
|
||||
const mapper: ICustomerDomainMapper = this._registry.getDomainMapper({
|
||||
resource: "customer",
|
||||
});
|
||||
|
||||
const converter = new CriteriaToSequelizeConverter();
|
||||
const query = converter.convert(criteria);
|
||||
|
||||
@ -120,7 +131,7 @@ export class CustomerRepository
|
||||
transaction,
|
||||
});
|
||||
|
||||
return this.mapper.mapArrayToDomain(instances);
|
||||
return mapper.mapArrayToDomain(instances);
|
||||
} catch (err: unknown) {
|
||||
return Result.fail(translateSequelizeError(err));
|
||||
}
|
||||
@ -0,0 +1 @@
|
||||
export * from "./customer.repository";
|
||||
Loading…
Reference in New Issue
Block a user