Compare commits
2 Commits
5d59598106
...
936c440cf3
| Author | SHA1 | Date | |
|---|---|---|---|
| 936c440cf3 | |||
| dd3f53c2b1 |
@ -96,14 +96,10 @@ export class IssuedInvoice
|
|||||||
}
|
}
|
||||||
|
|
||||||
static create(props: IIssuedInvoiceCreateProps, id?: UniqueID): Result<IssuedInvoice, Error> {
|
static create(props: IIssuedInvoiceCreateProps, id?: UniqueID): Result<IssuedInvoice, Error> {
|
||||||
if (!props.recipient) {
|
const validationResult = IssuedInvoice.validateCreateProps(props);
|
||||||
return Result.fail(
|
|
||||||
new DomainValidationError(
|
if (validationResult.isFailure) {
|
||||||
"MISSING_RECIPIENT",
|
return Result.fail(validationResult.error);
|
||||||
"recipient",
|
|
||||||
"Issued invoice requires recipient"
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const internalItems = IssuedInvoiceItems.create({
|
const internalItems = IssuedInvoiceItems.create({
|
||||||
@ -132,6 +128,20 @@ export class IssuedInvoice
|
|||||||
return Result.ok(issuedInvoice);
|
return Result.ok(issuedInvoice);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static validateCreateProps(props: IIssuedInvoiceCreateProps): Result<void, Error> {
|
||||||
|
if (!props.recipient) {
|
||||||
|
return Result.fail(
|
||||||
|
new DomainValidationError(
|
||||||
|
"MISSING_RECIPIENT",
|
||||||
|
"recipient",
|
||||||
|
"Issued invoice requires recipient"
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Result.ok();
|
||||||
|
}
|
||||||
|
|
||||||
// Rehidratación desde persistencia
|
// Rehidratación desde persistencia
|
||||||
static rehydrate(
|
static rehydrate(
|
||||||
props: InternalIssuedInvoiceProps,
|
props: InternalIssuedInvoiceProps,
|
||||||
|
|||||||
@ -11,15 +11,15 @@ export type IssuedInvoiceItemsProps = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export class IssuedInvoiceItems extends Collection<IssuedInvoiceItem> {
|
export class IssuedInvoiceItems extends Collection<IssuedInvoiceItem> {
|
||||||
private _languageCode!: LanguageCode;
|
private languageCode!: LanguageCode;
|
||||||
private _currencyCode!: CurrencyCode;
|
private currencyCode!: CurrencyCode;
|
||||||
private _globalDiscountPercentage!: Percentage;
|
private globalDiscountPercentage!: Percentage;
|
||||||
|
|
||||||
constructor(props: IssuedInvoiceItemsProps) {
|
constructor(props: IssuedInvoiceItemsProps) {
|
||||||
super(props.items ?? []);
|
super(props.items ?? []);
|
||||||
this._languageCode = props.languageCode;
|
this.languageCode = props.languageCode;
|
||||||
this._currencyCode = props.currencyCode;
|
this.currencyCode = props.currencyCode;
|
||||||
this._globalDiscountPercentage = props.globalDiscountPercentage;
|
this.globalDiscountPercentage = props.globalDiscountPercentage;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static create(props: IssuedInvoiceItemsProps): IssuedInvoiceItems {
|
public static create(props: IssuedInvoiceItemsProps): IssuedInvoiceItems {
|
||||||
@ -40,9 +40,9 @@ export class IssuedInvoiceItems extends Collection<IssuedInvoiceItem> {
|
|||||||
// tiene el mismo "currencyCode" y "languageCode" que la colección de items.
|
// tiene el mismo "currencyCode" y "languageCode" que la colección de items.
|
||||||
if (
|
if (
|
||||||
!(
|
!(
|
||||||
this._languageCode.equals(item.languageCode) &&
|
this.languageCode.equals(item.languageCode) &&
|
||||||
this._currencyCode.equals(item.currencyCode) &&
|
this.currencyCode.equals(item.currencyCode) &&
|
||||||
this._globalDiscountPercentage.equals(item.globalDiscountPercentage)
|
this.globalDiscountPercentage.equals(item.globalDiscountPercentage)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@ -1,6 +1,8 @@
|
|||||||
import type { CurrencyCode, LanguageCode } from "@repo/rdx-ddd";
|
import type { CurrencyCode, LanguageCode } from "@repo/rdx-ddd";
|
||||||
import { Collection } from "@repo/rdx-utils";
|
import { Collection } from "@repo/rdx-utils";
|
||||||
|
|
||||||
|
import { InvoiceAmount } from "../../../common";
|
||||||
|
|
||||||
import type { IssuedInvoiceTax } from "./issued-invoice-tax.entity";
|
import type { IssuedInvoiceTax } from "./issued-invoice-tax.entity";
|
||||||
|
|
||||||
export type IssuedInvoiceTaxesProps = {
|
export type IssuedInvoiceTaxesProps = {
|
||||||
@ -10,16 +12,59 @@ export type IssuedInvoiceTaxesProps = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export class IssuedInvoiceTaxes extends Collection<IssuedInvoiceTax> {
|
export class IssuedInvoiceTaxes extends Collection<IssuedInvoiceTax> {
|
||||||
private _languageCode!: LanguageCode;
|
private languageCode!: LanguageCode;
|
||||||
private _currencyCode!: CurrencyCode;
|
private currencyCode!: CurrencyCode;
|
||||||
|
|
||||||
constructor(props: IssuedInvoiceTaxesProps) {
|
constructor(props: IssuedInvoiceTaxesProps) {
|
||||||
super(props.taxes ?? []);
|
super(props.taxes ?? []);
|
||||||
this._languageCode = props.languageCode;
|
this.languageCode = props.languageCode;
|
||||||
this._currencyCode = props.currencyCode;
|
this.currencyCode = props.currencyCode;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static create(props: IssuedInvoiceTaxesProps): IssuedInvoiceTaxes {
|
public static create(props: IssuedInvoiceTaxesProps): IssuedInvoiceTaxes {
|
||||||
return new IssuedInvoiceTaxes(props);
|
return new IssuedInvoiceTaxes(props);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public getTaxableAmount(): InvoiceAmount {
|
||||||
|
return this.items.reduce(
|
||||||
|
(acc, tax) => acc.add(tax.taxableAmount),
|
||||||
|
InvoiceAmount.zero(this.currencyCode.toString())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public getIvaAmount(): InvoiceAmount {
|
||||||
|
return this.items.reduce(
|
||||||
|
(acc, tax) => acc.add(tax.ivaAmount),
|
||||||
|
InvoiceAmount.zero(this.currencyCode.toString())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public getRecAmount(): InvoiceAmount {
|
||||||
|
return this.items.reduce(
|
||||||
|
(acc, tax) => acc.add(tax.recAmount),
|
||||||
|
InvoiceAmount.zero(this.currencyCode.toString())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public getRetentionAmount(): InvoiceAmount {
|
||||||
|
return this.items.reduce(
|
||||||
|
(acc, tax) => acc.add(tax.retentionAmount),
|
||||||
|
InvoiceAmount.zero(this.currencyCode.toString())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public getTaxesAmount(): InvoiceAmount {
|
||||||
|
return this.items.reduce(
|
||||||
|
(acc, tax) => acc.add(tax.taxesAmount),
|
||||||
|
InvoiceAmount.zero(this.currencyCode.toString())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public getTransferredTaxesAmount(): InvoiceAmount {
|
||||||
|
return this.getIvaAmount().add(this.getRecAmount());
|
||||||
|
}
|
||||||
|
|
||||||
|
public getNetTaxesAmount(): InvoiceAmount {
|
||||||
|
return this.getTransferredTaxesAmount().subtract(this.getRetentionAmount());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -116,6 +116,12 @@ export class Proforma extends AggregateRoot<InternalProformaProps> implements IP
|
|||||||
|
|
||||||
// Creación funcional
|
// Creación funcional
|
||||||
static create(props: IProformaCreateProps, id?: UniqueID): Result<Proforma, Error> {
|
static create(props: IProformaCreateProps, id?: UniqueID): Result<Proforma, Error> {
|
||||||
|
const validationResult = Proforma.validateCreateProps(props);
|
||||||
|
|
||||||
|
if (validationResult.isFailure) {
|
||||||
|
return Result.fail(validationResult.error);
|
||||||
|
}
|
||||||
|
|
||||||
const internalItems = ProformaItems.create({
|
const internalItems = ProformaItems.create({
|
||||||
items: [],
|
items: [],
|
||||||
languageCode: props.languageCode,
|
languageCode: props.languageCode,
|
||||||
@ -141,6 +147,10 @@ export class Proforma extends AggregateRoot<InternalProformaProps> implements IP
|
|||||||
return Result.ok(proforma);
|
return Result.ok(proforma);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static validateCreateProps(props: IProformaCreateProps): Result<void, Error> {
|
||||||
|
return Result.ok();
|
||||||
|
}
|
||||||
|
|
||||||
// Rehidratación desde persistencia
|
// Rehidratación desde persistencia
|
||||||
static rehydrate(props: InternalProformaProps, items: ProformaItems, id: UniqueID): Proforma {
|
static rehydrate(props: InternalProformaProps, items: ProformaItems, id: UniqueID): Proforma {
|
||||||
return new Proforma(props, items, id);
|
return new Proforma(props, items, id);
|
||||||
@ -237,15 +247,17 @@ export class Proforma extends AggregateRoot<InternalProformaProps> implements IP
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Mutabilidad
|
// Mutabilidad
|
||||||
public update(
|
public update(patch: ProformaPatchProps): Result<Proforma, Error> {
|
||||||
partialProforma: Partial<Omit<IProformaCreateProps, "companyId">>
|
const candidateProps: InternalProformaProps = {
|
||||||
): Result<Proforma, Error> {
|
|
||||||
const updatedProps = {
|
|
||||||
...this.props,
|
...this.props,
|
||||||
...partialProforma,
|
...patch,
|
||||||
} as IProformaCreateProps;
|
};
|
||||||
|
|
||||||
return Proforma.create(updatedProps, this.id);
|
// Validacciones
|
||||||
|
|
||||||
|
Object.assign(this.props, candidateProps);
|
||||||
|
|
||||||
|
return Result.ok();
|
||||||
}
|
}
|
||||||
|
|
||||||
public issue(): Result<void, Error> {
|
public issue(): Result<void, Error> {
|
||||||
|
|||||||
@ -99,6 +99,12 @@ type CustomerInternalProps = Omit<ICustomerCreateProps, "address" | "defaultTaxe
|
|||||||
|
|
||||||
export class Customer extends AggregateRoot<CustomerInternalProps> implements ICustomer {
|
export class Customer extends AggregateRoot<CustomerInternalProps> implements ICustomer {
|
||||||
static create(props: ICustomerCreateProps, id?: UniqueID): Result<Customer, Error> {
|
static create(props: ICustomerCreateProps, id?: UniqueID): Result<Customer, Error> {
|
||||||
|
const validationResult = Customer.validateCreateProps(props);
|
||||||
|
|
||||||
|
if (validationResult.isFailure) {
|
||||||
|
return Result.fail(validationResult.error);
|
||||||
|
}
|
||||||
|
|
||||||
const { address, defaultTaxes, ...internalProps } = props;
|
const { address, defaultTaxes, ...internalProps } = props;
|
||||||
|
|
||||||
const postalAddressResult = PostalAddress.create(address);
|
const postalAddressResult = PostalAddress.create(address);
|
||||||
@ -132,6 +138,10 @@ export class Customer extends AggregateRoot<CustomerInternalProps> implements IC
|
|||||||
return Result.ok(contact);
|
return Result.ok(contact);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static validateCreateProps(props: ICustomerCreateProps): Result<void, Error> {
|
||||||
|
return Result.ok();
|
||||||
|
}
|
||||||
|
|
||||||
// Rehidratación desde persistencia
|
// Rehidratación desde persistencia
|
||||||
static rehydrate(props: CustomerInternalProps, id: UniqueID): Customer {
|
static rehydrate(props: CustomerInternalProps, id: UniqueID): Customer {
|
||||||
return new Customer(props, id);
|
return new Customer(props, id);
|
||||||
|
|||||||
@ -1,16 +1,11 @@
|
|||||||
import type { IModuleServer } from "@erp/core/api";
|
import type { IModuleServer } from "@erp/core/api";
|
||||||
|
|
||||||
import { type CustomerPublicServices, customersRouter, models } from "./infrastructure";
|
import type { ICustomerPublicServices } from "./application";
|
||||||
import {
|
import { customersRouter, models } from "./infrastructure";
|
||||||
type CustomersInternalDeps,
|
import { buildCustomerPublicServices, buildCustomersDependencies } from "./infrastructure/di";
|
||||||
buildCustomerPublicServices,
|
|
||||||
buildCustomersDependencies,
|
|
||||||
} from "./infrastructure/di";
|
|
||||||
|
|
||||||
export * from "./infrastructure/sequelize";
|
export * from "./infrastructure/sequelize";
|
||||||
|
|
||||||
export type { CustomerPublicServices };
|
|
||||||
|
|
||||||
export const customersAPIModule: IModuleServer = {
|
export const customersAPIModule: IModuleServer = {
|
||||||
name: "customers",
|
name: "customers",
|
||||||
version: "1.0.0",
|
version: "1.0.0",
|
||||||
@ -30,7 +25,10 @@ export const customersAPIModule: IModuleServer = {
|
|||||||
const internal = buildCustomersDependencies(params);
|
const internal = buildCustomersDependencies(params);
|
||||||
|
|
||||||
// 2) Servicios públicos (Application Services)
|
// 2) Servicios públicos (Application Services)
|
||||||
const customersServices: CustomerPublicServices = buildCustomerPublicServices(params, internal);
|
const customersServices: ICustomerPublicServices = buildCustomerPublicServices(
|
||||||
|
params,
|
||||||
|
internal
|
||||||
|
);
|
||||||
|
|
||||||
logger.info("🚀 Customers module dependencies registered", {
|
logger.info("🚀 Customers module dependencies registered", {
|
||||||
label: this.name,
|
label: this.name,
|
||||||
@ -60,11 +58,8 @@ export const customersAPIModule: IModuleServer = {
|
|||||||
async start(params) {
|
async start(params) {
|
||||||
const { app, baseRoutePath, logger, getInternal } = params;
|
const { app, baseRoutePath, logger, getInternal } = params;
|
||||||
|
|
||||||
// Recuperamos el dominio interno del módulo
|
|
||||||
const customersInternalDeps = getInternal<CustomersInternalDeps>("customers");
|
|
||||||
|
|
||||||
// Registro de rutas HTTP
|
// Registro de rutas HTTP
|
||||||
customersRouter(params, customersInternalDeps);
|
customersRouter(params);
|
||||||
|
|
||||||
logger.info("🚀 Customers module started", {
|
logger.info("🚀 Customers module started", {
|
||||||
label: this.name,
|
label: this.name,
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import { mockUser, requireAuthenticated, requireCompanyContext } from "@erp/auth/api";
|
import { mockUser, requireAuthenticated, requireCompanyContext } from "@erp/auth/api";
|
||||||
import { type ModuleParams, type RequestWithAuth, validateRequest } from "@erp/core/api";
|
import { type RequestWithAuth, type StartParams, validateRequest } from "@erp/core/api";
|
||||||
import { type NextFunction, type Request, type Response, Router } from "express";
|
import { type NextFunction, type Request, type Response, Router } from "express";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
@ -18,11 +18,16 @@ import {
|
|||||||
UpdateCustomerController,
|
UpdateCustomerController,
|
||||||
} from "./controllers";
|
} from "./controllers";
|
||||||
|
|
||||||
export const customersRouter = (params: ModuleParams, deps: CustomersInternalDeps) => {
|
export const customersRouter = (params: StartParams) => {
|
||||||
const { app, config } = params;
|
const { app, config, getInternal } = params;
|
||||||
|
|
||||||
|
// Recuperamos el dominio interno del módulo
|
||||||
|
const deps = getInternal<CustomersInternalDeps>("customers");
|
||||||
|
|
||||||
const router: Router = Router({ mergeParams: true });
|
const router: Router = Router({ mergeParams: true });
|
||||||
|
|
||||||
|
// ----------------------------------------------
|
||||||
|
|
||||||
// 🔐 Autenticación + Tenancy para TODO el router
|
// 🔐 Autenticación + Tenancy para TODO el router
|
||||||
if (process.env.NODE_ENV === "development" || process.env.NODE_ENV === "production") {
|
if (process.env.NODE_ENV === "development" || process.env.NODE_ENV === "production") {
|
||||||
router.use(
|
router.use(
|
||||||
|
|||||||
@ -46,7 +46,7 @@ export const factugesAPIModule: IModuleServer = {
|
|||||||
* - NO construye dominio
|
* - NO construye dominio
|
||||||
*/
|
*/
|
||||||
async start(params) {
|
async start(params) {
|
||||||
const { app, baseRoutePath, logger, getInternal, getService, listServices } = params;
|
const { logger } = params;
|
||||||
|
|
||||||
// Registro de rutas HTTP
|
// Registro de rutas HTTP
|
||||||
factugesRouter(params);
|
factugesRouter(params);
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user