Facturas de cliente
This commit is contained in:
parent
484f0119a7
commit
7bf24c8f91
@ -42,7 +42,7 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@erp/core": "workspace:*",
|
"@erp/core": "workspace:*",
|
||||||
"@erp/auth": "workspace:*",
|
"@erp/auth": "workspace:*",
|
||||||
"@erp/invoices": "workspace:*",
|
"@erp/customer-invoices": "workspace:*",
|
||||||
"bcrypt": "^5.1.1",
|
"bcrypt": "^5.1.1",
|
||||||
"cls-rtracer": "^2.6.3",
|
"cls-rtracer": "^2.6.3",
|
||||||
"cors": "^2.8.5",
|
"cors": "^2.8.5",
|
||||||
|
|||||||
@ -134,7 +134,6 @@ process.on("uncaughtException", (error: Error) => {
|
|||||||
|
|
||||||
await initModules({ app, database, baseRoutePath: API_BASE_PATH, logger });
|
await initModules({ app, database, baseRoutePath: API_BASE_PATH, logger });
|
||||||
|
|
||||||
logger.info("holaaaaaaaaaaaaaaaaa");
|
|
||||||
console.log(listRoutes(app._router, API_BASE_PATH));
|
console.log(listRoutes(app._router, API_BASE_PATH));
|
||||||
|
|
||||||
server.listen(currentState.port, () => {
|
server.listen(currentState.port, () => {
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import { authAPIModule } from "@erp/auth/api";
|
import { authAPIModule } from "@erp/auth/api";
|
||||||
import { invoicesAPIModule } from "@erp/invoices/api";
|
import { invoicesAPIModule } from "@erp/customer-invoices/api";
|
||||||
import { registerModule } from "./lib";
|
import { registerModule } from "./lib";
|
||||||
|
|
||||||
export const registerModules = () => {
|
export const registerModules = () => {
|
||||||
|
|||||||
@ -31,7 +31,7 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@erp/auth": "workspace:*",
|
"@erp/auth": "workspace:*",
|
||||||
"@erp/core": "workspace:*",
|
"@erp/core": "workspace:*",
|
||||||
"@erp/invoices": "workspace:*",
|
"@erp/customer-invoices": "workspace:*",
|
||||||
"@repo/rdx-criteria": "workspace:*",
|
"@repo/rdx-criteria": "workspace:*",
|
||||||
"@repo/rdx-ui": "workspace:*",
|
"@repo/rdx-ui": "workspace:*",
|
||||||
"@repo/shadcn-ui": "workspace:*",
|
"@repo/shadcn-ui": "workspace:*",
|
||||||
|
|||||||
@ -45,7 +45,7 @@ export const App = () => {
|
|||||||
getAccessToken,
|
getAccessToken,
|
||||||
setAccessToken,
|
setAccessToken,
|
||||||
clearAccessToken,
|
clearAccessToken,
|
||||||
authService: createAuthService(dataSource),
|
authService: createAuthService(),
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<TooltipProvider delayDuration={0}>
|
<TooltipProvider delayDuration={0}>
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import { AuthModuleManifiest } from "@erp/auth/client";
|
import { AuthModuleManifiest } from "@erp/auth/client";
|
||||||
import { IModuleClient } from "@erp/core/client";
|
import { IModuleClient } from "@erp/core/client";
|
||||||
import { InvoicesModuleManifiest } from "@erp/invoices/client";
|
import { CustomerInvoicesModuleManifiest } from "@erp/customer-invoices/client";
|
||||||
|
|
||||||
export const modules: IModuleClient[] = [AuthModuleManifiest, InvoicesModuleManifiest];
|
export const modules: IModuleClient[] = [AuthModuleManifiest, CustomerInvoicesModuleManifiest];
|
||||||
|
|||||||
@ -1,13 +1,14 @@
|
|||||||
import { IDataSource } from "@erp/core/client";
|
import { useDataSource } from "@erp/core/client";
|
||||||
import { ILoginRequestDTO, ILoginResponseDTO } from "../../common";
|
import { ILoginRequestDTO, ILoginResponseDTO } from "../../common";
|
||||||
|
|
||||||
export interface IAuthService {
|
export interface IAuthService {
|
||||||
login: (credentials: ILoginRequestDTO) => Promise<ILoginResponseDTO>;
|
login: (credentials: ILoginRequestDTO) => Promise<ILoginResponseDTO>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const createAuthService = (dataSource: IDataSource): IAuthService => {
|
export const createAuthService = (): IAuthService => {
|
||||||
return {
|
return {
|
||||||
login: async (credentials: ILoginRequestDTO) => {
|
login: async (credentials: ILoginRequestDTO) => {
|
||||||
|
const dataSource = useDataSource();
|
||||||
const data = await dataSource.custom<ILoginResponseDTO>({
|
const data = await dataSource.custom<ILoginResponseDTO>({
|
||||||
path: "login",
|
path: "login",
|
||||||
method: "post",
|
method: "post",
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"name": "@erp/invoices",
|
"name": "@erp/customer-invoices",
|
||||||
"version": "0.0.1",
|
"version": "0.0.1",
|
||||||
"main": "src/index.ts",
|
"main": "src/index.ts",
|
||||||
"types": "src/index.ts",
|
"types": "src/index.ts",
|
||||||
@ -23,6 +23,7 @@
|
|||||||
"@repo/rdx-utils": "workspace:*",
|
"@repo/rdx-utils": "workspace:*",
|
||||||
"@repo/rdx-ui": "workspace:*",
|
"@repo/rdx-ui": "workspace:*",
|
||||||
"@repo/shadcn-ui": "workspace:*",
|
"@repo/shadcn-ui": "workspace:*",
|
||||||
|
"@tanstack/react-query": "^5.74.11",
|
||||||
"ag-grid-community": "^33.3.0",
|
"ag-grid-community": "^33.3.0",
|
||||||
"ag-grid-react": "^33.3.0",
|
"ag-grid-react": "^33.3.0",
|
||||||
"express": "^4.18.2",
|
"express": "^4.18.2",
|
||||||
@ -0,0 +1,147 @@
|
|||||||
|
import { UniqueID, UtcDate } from "@/core/common/domain";
|
||||||
|
|
||||||
|
import {
|
||||||
|
type ICustomerInvoiceProps,
|
||||||
|
type ICustomerInvoiceService,
|
||||||
|
type CustomerInvoice,
|
||||||
|
CustomerInvoiceNumber,
|
||||||
|
CustomerInvoiceSerie,
|
||||||
|
CustomerInvoiceStatus,
|
||||||
|
} from "@/contexts/customerCustomerInvoices/domain";
|
||||||
|
import { ITransactionManager } from "@/core/common/infrastructure/database";
|
||||||
|
import { logger } from "@/core/logger";
|
||||||
|
import { Result } from "@repo/rdx-utils";
|
||||||
|
import { ICreateCustomerInvoiceRequestDTO } from "../../common/dto";
|
||||||
|
|
||||||
|
export class CreateCustomerInvoiceUseCase {
|
||||||
|
constructor(
|
||||||
|
private readonly customerCustomerInvoiceService: ICustomerInvoiceService,
|
||||||
|
private readonly transactionManager: ITransactionManager
|
||||||
|
) {}
|
||||||
|
|
||||||
|
public execute(
|
||||||
|
customerCustomerInvoiceID: UniqueID,
|
||||||
|
dto: ICreateCustomerInvoiceRequestDTO
|
||||||
|
): Promise<Result<CustomerInvoice, Error>> {
|
||||||
|
return this.transactionManager.complete(async (transaction) => {
|
||||||
|
try {
|
||||||
|
const validOrErrors = this.validateCustomerInvoiceData(dto);
|
||||||
|
if (validOrErrors.isFailure) {
|
||||||
|
return Result.fail(validOrErrors.error);
|
||||||
|
}
|
||||||
|
|
||||||
|
const data = validOrErrors.data;
|
||||||
|
|
||||||
|
// Update customerCustomerInvoice with dto
|
||||||
|
return await this.customerCustomerInvoiceService.createCustomerInvoice(customerCustomerInvoiceID, data, transaction);
|
||||||
|
} catch (error: unknown) {
|
||||||
|
logger.error(error as Error);
|
||||||
|
return Result.fail(error as Error);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private validateCustomerInvoiceData(dto: ICreateCustomerInvoiceRequestDTO): Result<ICustomerInvoiceProps, Error> {
|
||||||
|
const errors: Error[] = [];
|
||||||
|
|
||||||
|
const customerCustomerInvoiceNumerOrError = CustomerInvoiceNumber.create(dto.customerCustomerInvoice_number);
|
||||||
|
const customerCustomerInvoiceSeriesOrError = CustomerInvoiceSerie.create(dto.customerCustomerInvoice_series);
|
||||||
|
const issueDateOrError = UtcDate.create(dto.issue_date);
|
||||||
|
const operationDateOrError = UtcDate.create(dto.operation_date);
|
||||||
|
|
||||||
|
const result = Result.combine([
|
||||||
|
customerCustomerInvoiceNumerOrError,
|
||||||
|
customerCustomerInvoiceSeriesOrError,
|
||||||
|
issueDateOrError,
|
||||||
|
operationDateOrError,
|
||||||
|
]);
|
||||||
|
|
||||||
|
if (result.isFailure) {
|
||||||
|
return Result.fail(result.error);
|
||||||
|
}
|
||||||
|
|
||||||
|
const validatedData: ICustomerInvoiceProps = {
|
||||||
|
status: CustomerInvoiceStatus.createDraft(),
|
||||||
|
customerCustomerInvoiceNumber: customerCustomerInvoiceNumerOrError.data,
|
||||||
|
customerCustomerInvoiceSeries: customerCustomerInvoiceSeriesOrError.data,
|
||||||
|
issueDate: issueDateOrError.data,
|
||||||
|
operationDate: operationDateOrError.data,
|
||||||
|
customerCustomerInvoiceCurrency: dto.currency,
|
||||||
|
};
|
||||||
|
|
||||||
|
/*if (errors.length > 0) {
|
||||||
|
const message = errors.map((err) => err.message).toString();
|
||||||
|
return Result.fail(new Error(message));
|
||||||
|
}*/
|
||||||
|
return Result.ok(validatedData);
|
||||||
|
|
||||||
|
/*let customerCustomerInvoice_status = CustomerInvoiceStatus.create(dto.status).object;
|
||||||
|
if (customerCustomerInvoice_status.isEmpty()) {
|
||||||
|
customerCustomerInvoice_status = CustomerInvoiceStatus.createDraft();
|
||||||
|
}
|
||||||
|
|
||||||
|
let customerCustomerInvoice_series = CustomerInvoiceSeries.create(dto.customerCustomerInvoice_series).object;
|
||||||
|
if (customerCustomerInvoice_series.isEmpty()) {
|
||||||
|
customerCustomerInvoice_series = CustomerInvoiceSeries.create(dto.customerCustomerInvoice_series).object;
|
||||||
|
}
|
||||||
|
|
||||||
|
let issue_date = CustomerInvoiceDate.create(dto.issue_date).object;
|
||||||
|
if (issue_date.isEmpty()) {
|
||||||
|
issue_date = CustomerInvoiceDate.createCurrentDate().object;
|
||||||
|
}
|
||||||
|
|
||||||
|
let operation_date = CustomerInvoiceDate.create(dto.operation_date).object;
|
||||||
|
if (operation_date.isEmpty()) {
|
||||||
|
operation_date = CustomerInvoiceDate.createCurrentDate().object;
|
||||||
|
}
|
||||||
|
|
||||||
|
let customerCustomerInvoiceCurrency = Currency.createFromCode(dto.currency).object;
|
||||||
|
|
||||||
|
if (customerCustomerInvoiceCurrency.isEmpty()) {
|
||||||
|
customerCustomerInvoiceCurrency = Currency.createDefaultCode().object;
|
||||||
|
}
|
||||||
|
|
||||||
|
let customerCustomerInvoiceLanguage = Language.createFromCode(dto.language_code).object;
|
||||||
|
|
||||||
|
if (customerCustomerInvoiceLanguage.isEmpty()) {
|
||||||
|
customerCustomerInvoiceLanguage = Language.createDefaultCode().object;
|
||||||
|
}
|
||||||
|
|
||||||
|
const items = new Collection<CustomerInvoiceItem>(
|
||||||
|
dto.items?.map(
|
||||||
|
(item) =>
|
||||||
|
CustomerInvoiceSimpleItem.create({
|
||||||
|
description: Description.create(item.description).object,
|
||||||
|
quantity: Quantity.create(item.quantity).object,
|
||||||
|
unitPrice: UnitPrice.create({
|
||||||
|
amount: item.unit_price.amount,
|
||||||
|
currencyCode: item.unit_price.currency,
|
||||||
|
precision: item.unit_price.precision,
|
||||||
|
}).object,
|
||||||
|
}).object
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!customerCustomerInvoice_status.isDraft()) {
|
||||||
|
throw Error("Error al crear una factura que no es borrador");
|
||||||
|
}
|
||||||
|
|
||||||
|
return DraftCustomerInvoice.create(
|
||||||
|
{
|
||||||
|
customerCustomerInvoiceSeries: customerCustomerInvoice_series,
|
||||||
|
issueDate: issue_date,
|
||||||
|
operationDate: operation_date,
|
||||||
|
customerCustomerInvoiceCurrency,
|
||||||
|
language: customerCustomerInvoiceLanguage,
|
||||||
|
customerCustomerInvoiceNumber: CustomerInvoiceNumber.create(undefined).object,
|
||||||
|
//notes: Note.create(customerCustomerInvoiceDTO.notes).object,
|
||||||
|
|
||||||
|
//senderId: UniqueID.create(null).object,
|
||||||
|
recipient,
|
||||||
|
|
||||||
|
items,
|
||||||
|
},
|
||||||
|
customerCustomerInvoiceId
|
||||||
|
);*/
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -2,18 +2,18 @@ import { UniqueID } from "@/core/common/domain";
|
|||||||
import { ITransactionManager } from "@/core/common/infrastructure/database";
|
import { ITransactionManager } from "@/core/common/infrastructure/database";
|
||||||
import { logger } from "@/core/logger";
|
import { logger } from "@/core/logger";
|
||||||
import { Result } from "@repo/rdx-utils";
|
import { Result } from "@repo/rdx-utils";
|
||||||
import { IInvoiceService } from "../domain";
|
import { ICustomerInvoiceService } from "../domain";
|
||||||
|
|
||||||
export class DeleteInvoiceUseCase {
|
export class DeleteCustomerInvoiceUseCase {
|
||||||
constructor(
|
constructor(
|
||||||
private readonly invoiceService: IInvoiceService,
|
private readonly customerCustomerInvoiceService: ICustomerInvoiceService,
|
||||||
private readonly transactionManager: ITransactionManager
|
private readonly transactionManager: ITransactionManager
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
public execute(invoiceID: UniqueID): Promise<Result<boolean, Error>> {
|
public execute(customerCustomerInvoiceID: UniqueID): Promise<Result<boolean, Error>> {
|
||||||
return this.transactionManager.complete(async (transaction) => {
|
return this.transactionManager.complete(async (transaction) => {
|
||||||
try {
|
try {
|
||||||
return await this.invoiceService.deleteInvoiceById(invoiceID, transaction);
|
return await this.customerCustomerInvoiceService.deleteCustomerInvoiceById(customerCustomerInvoiceID, transaction);
|
||||||
} catch (error: unknown) {
|
} catch (error: unknown) {
|
||||||
logger.error(error as Error);
|
logger.error(error as Error);
|
||||||
return Result.fail(error as Error);
|
return Result.fail(error as Error);
|
||||||
@ -2,18 +2,18 @@ import { UniqueID } from "@/core/common/domain";
|
|||||||
import { ITransactionManager } from "@/core/common/infrastructure/database";
|
import { ITransactionManager } from "@/core/common/infrastructure/database";
|
||||||
import { logger } from "@/lib/logger";
|
import { logger } from "@/lib/logger";
|
||||||
import { Result } from "@repo/rdx-utils";
|
import { Result } from "@repo/rdx-utils";
|
||||||
import { IInvoiceService, Invoice } from "../domain";
|
import { ICustomerInvoiceService, CustomerInvoice } from "../domain";
|
||||||
|
|
||||||
export class GetInvoiceUseCase {
|
export class GetCustomerInvoiceUseCase {
|
||||||
constructor(
|
constructor(
|
||||||
private readonly invoiceService: IInvoiceService,
|
private readonly customerCustomerInvoiceService: ICustomerInvoiceService,
|
||||||
private readonly transactionManager: ITransactionManager
|
private readonly transactionManager: ITransactionManager
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
public execute(invoiceID: UniqueID): Promise<Result<Invoice, Error>> {
|
public execute(customerCustomerInvoiceID: UniqueID): Promise<Result<CustomerInvoice, Error>> {
|
||||||
return this.transactionManager.complete(async (transaction) => {
|
return this.transactionManager.complete(async (transaction) => {
|
||||||
try {
|
try {
|
||||||
return await this.invoiceService.findInvoiceById(invoiceID, transaction);
|
return await this.customerCustomerInvoiceService.findCustomerInvoiceById(customerCustomerInvoiceID, transaction);
|
||||||
} catch (error: unknown) {
|
} catch (error: unknown) {
|
||||||
logger.error(error as Error);
|
logger.error(error as Error);
|
||||||
return Result.fail(error as Error);
|
return Result.fail(error as Error);
|
||||||
5
modules/customer-invoices/src/api/application/index.ts
Normal file
5
modules/customer-invoices/src/api/application/index.ts
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
//export * from "./create-customer-invoice.use-case";
|
||||||
|
//export * from "./delete-customer-invoice.use-case";
|
||||||
|
export * from "./get-customer-invoice.use-case";
|
||||||
|
export * from "./list-customer-invoices.use-case";
|
||||||
|
//export * from "./update-customer-invoice.use-case";
|
||||||
@ -2,18 +2,18 @@ import { ITransactionManager } from "@erp/core/api";
|
|||||||
import { Criteria } from "@repo/rdx-criteria/server";
|
import { Criteria } from "@repo/rdx-criteria/server";
|
||||||
import { Collection, Result } from "@repo/rdx-utils";
|
import { Collection, Result } from "@repo/rdx-utils";
|
||||||
import { Transaction } from "sequelize";
|
import { Transaction } from "sequelize";
|
||||||
import { IInvoiceService, Invoice } from "../domain";
|
import { ICustomerInvoiceService, CustomerInvoice } from "../domain";
|
||||||
|
|
||||||
export class ListInvoicesUseCase {
|
export class ListCustomerInvoicesUseCase {
|
||||||
constructor(
|
constructor(
|
||||||
private readonly invoiceService: IInvoiceService,
|
private readonly customerCustomerInvoiceService: ICustomerInvoiceService,
|
||||||
private readonly transactionManager: ITransactionManager
|
private readonly transactionManager: ITransactionManager
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
public execute(criteria: Criteria): Promise<Result<Collection<Invoice>, Error>> {
|
public execute(criteria: Criteria): Promise<Result<Collection<CustomerInvoice>, Error>> {
|
||||||
return this.transactionManager.complete(async (transaction: Transaction) => {
|
return this.transactionManager.complete(async (transaction: Transaction) => {
|
||||||
try {
|
try {
|
||||||
return await this.invoiceService.findInvoices(criteria, transaction);
|
return await this.customerCustomerInvoiceService.findCustomerInvoices(criteria, transaction);
|
||||||
} catch (error: unknown) {
|
} catch (error: unknown) {
|
||||||
return Result.fail(error as Error);
|
return Result.fail(error as Error);
|
||||||
}
|
}
|
||||||
@ -5,12 +5,12 @@
|
|||||||
import { IAdapter, RepositoryBuilder } from "@/contexts/common/domain";
|
import { IAdapter, RepositoryBuilder } from "@/contexts/common/domain";
|
||||||
import { Result, UniqueID } from "@shared/contexts";
|
import { Result, UniqueID } from "@shared/contexts";
|
||||||
import { NullOr } from "@shared/utilities";
|
import { NullOr } from "@shared/utilities";
|
||||||
import { IInvoiceParticipantAddress, IInvoiceParticipantAddressRepository } from "../../domain";
|
import { ICustomerInvoiceParticipantAddress, ICustomerInvoiceParticipantAddressRepository } from "../../domain";
|
||||||
|
|
||||||
export const participantAddressFinder = async (
|
export const participantAddressFinder = async (
|
||||||
addressId: UniqueID,
|
addressId: UniqueID,
|
||||||
adapter: IAdapter,
|
adapter: IAdapter,
|
||||||
repository: RepositoryBuilder<IInvoiceParticipantAddressRepository>
|
repository: RepositoryBuilder<ICustomerInvoiceParticipantAddressRepository>
|
||||||
) => {
|
) => {
|
||||||
if (addressId.isNull()) {
|
if (addressId.isNull()) {
|
||||||
return Result.fail<IApplicationServiceError>(
|
return Result.fail<IApplicationServiceError>(
|
||||||
@ -22,7 +22,7 @@ export const participantAddressFinder = async (
|
|||||||
}
|
}
|
||||||
|
|
||||||
const transaction = adapter.startTransaction();
|
const transaction = adapter.startTransaction();
|
||||||
let address: NullOr<IInvoiceParticipantAddress> = null;
|
let address: NullOr<ICustomerInvoiceParticipantAddress> = null;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await transaction.complete(async (t) => {
|
await transaction.complete(async (t) => {
|
||||||
@ -38,7 +38,7 @@ export const participantAddressFinder = async (
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return Result.ok<IInvoiceParticipantAddress>(address);
|
return Result.ok<ICustomerInvoiceParticipantAddress>(address);
|
||||||
} catch (error: unknown) {
|
} catch (error: unknown) {
|
||||||
const _error = error as Error;
|
const _error = error as Error;
|
||||||
|
|
||||||
@ -1,13 +1,13 @@
|
|||||||
/* import { IAdapter, RepositoryBuilder } from "@/contexts/common/domain";
|
/* import { IAdapter, RepositoryBuilder } from "@/contexts/common/domain";
|
||||||
import { UniqueID } from "@shared/contexts";
|
import { UniqueID } from "@shared/contexts";
|
||||||
import { IInvoiceParticipantRepository } from "../../domain";
|
import { ICustomerInvoiceParticipantRepository } from "../../domain";
|
||||||
import { InvoiceCustomer } from "../../domain/entities/invoice-customer/invoice-customer";
|
import { CustomerInvoiceCustomer } from "../../domain/entities/customerCustomerInvoice-customer/customerCustomerInvoice-customer";
|
||||||
|
|
||||||
export const participantFinder = async (
|
export const participantFinder = async (
|
||||||
participantId: UniqueID,
|
participantId: UniqueID,
|
||||||
adapter: IAdapter,
|
adapter: IAdapter,
|
||||||
repository: RepositoryBuilder<IInvoiceParticipantRepository>
|
repository: RepositoryBuilder<ICustomerInvoiceParticipantRepository>
|
||||||
): Promise<InvoiceCustomer | undefined> => {
|
): Promise<CustomerInvoiceCustomer | undefined> => {
|
||||||
if (!participantId || (participantId && participantId.isNull())) {
|
if (!participantId || (participantId && participantId.isNull())) {
|
||||||
return Promise.resolve(undefined);
|
return Promise.resolve(undefined);
|
||||||
}
|
}
|
||||||
@ -0,0 +1,401 @@
|
|||||||
|
import { UniqueID } from "@/core/common/domain";
|
||||||
|
import { ITransactionManager } from "@/core/common/infrastructure/database";
|
||||||
|
import { Result } from "@repo/rdx-utils";
|
||||||
|
import { IUpdateCustomerInvoiceRequestDTO } from "../../common/dto";
|
||||||
|
import { ICustomerInvoiceService, CustomerInvoice } from "../domain";
|
||||||
|
|
||||||
|
export class CreateCustomerInvoiceUseCase {
|
||||||
|
constructor(
|
||||||
|
private readonly customerCustomerInvoiceService: ICustomerInvoiceService,
|
||||||
|
private readonly transactionManager: ITransactionManager
|
||||||
|
) {}
|
||||||
|
|
||||||
|
public execute(
|
||||||
|
customerCustomerInvoiceID: UniqueID,
|
||||||
|
dto: Partial<IUpdateCustomerInvoiceRequestDTO>
|
||||||
|
): Promise<Result<CustomerInvoice, Error>> {
|
||||||
|
return this.transactionManager.complete(async (transaction) => {
|
||||||
|
return Result.fail(new Error("No implementado"));
|
||||||
|
/*
|
||||||
|
try {
|
||||||
|
const validOrErrors = this.validateCustomerInvoiceData(dto);
|
||||||
|
if (validOrErrors.isFailure) {
|
||||||
|
return Result.fail(validOrErrors.error);
|
||||||
|
}
|
||||||
|
|
||||||
|
const data = validOrErrors.data;
|
||||||
|
|
||||||
|
// Update customerCustomerInvoice with dto
|
||||||
|
return await this.customerCustomerInvoiceService.updateCustomerInvoiceById(customerCustomerInvoiceID, data, transaction);
|
||||||
|
} catch (error: unknown) {
|
||||||
|
logger.error(error as Error);
|
||||||
|
return Result.fail(error as Error);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/* private validateCustomerInvoiceData(
|
||||||
|
dto: Partial<IUpdateCustomerInvoiceRequestDTO>
|
||||||
|
): Result<Partial<ICustomerInvoiceProps>, Error> {
|
||||||
|
const errors: Error[] = [];
|
||||||
|
const validatedData: Partial<ICustomerInvoiceProps> = {};
|
||||||
|
|
||||||
|
// Create customerCustomerInvoice
|
||||||
|
let customerCustomerInvoice_status = CustomerInvoiceStatus.create(customerCustomerInvoiceDTO.status).object;
|
||||||
|
if (customerCustomerInvoice_status.isEmpty()) {
|
||||||
|
customerCustomerInvoice_status = CustomerInvoiceStatus.createDraft();
|
||||||
|
}
|
||||||
|
|
||||||
|
let customerCustomerInvoice_series = CustomerInvoiceSeries.create(customerCustomerInvoiceDTO.customerCustomerInvoice_series).object;
|
||||||
|
if (customerCustomerInvoice_series.isEmpty()) {
|
||||||
|
customerCustomerInvoice_series = CustomerInvoiceSeries.create(customerCustomerInvoiceDTO.customerCustomerInvoice_series).object;
|
||||||
|
}
|
||||||
|
|
||||||
|
let issue_date = CustomerInvoiceDate.create(customerCustomerInvoiceDTO.issue_date).object;
|
||||||
|
if (issue_date.isEmpty()) {
|
||||||
|
issue_date = CustomerInvoiceDate.createCurrentDate().object;
|
||||||
|
}
|
||||||
|
|
||||||
|
let operation_date = CustomerInvoiceDate.create(customerCustomerInvoiceDTO.operation_date).object;
|
||||||
|
if (operation_date.isEmpty()) {
|
||||||
|
operation_date = CustomerInvoiceDate.createCurrentDate().object;
|
||||||
|
}
|
||||||
|
|
||||||
|
let customerCustomerInvoiceCurrency = Currency.createFromCode(customerCustomerInvoiceDTO.currency).object;
|
||||||
|
|
||||||
|
if (customerCustomerInvoiceCurrency.isEmpty()) {
|
||||||
|
customerCustomerInvoiceCurrency = Currency.createDefaultCode().object;
|
||||||
|
}
|
||||||
|
|
||||||
|
let customerCustomerInvoiceLanguage = Language.createFromCode(customerCustomerInvoiceDTO.language_code).object;
|
||||||
|
|
||||||
|
if (customerCustomerInvoiceLanguage.isEmpty()) {
|
||||||
|
customerCustomerInvoiceLanguage = Language.createDefaultCode().object;
|
||||||
|
}
|
||||||
|
|
||||||
|
const items = new Collection<CustomerInvoiceItem>(
|
||||||
|
customerCustomerInvoiceDTO.items?.map(
|
||||||
|
(item) =>
|
||||||
|
CustomerInvoiceSimpleItem.create({
|
||||||
|
description: Description.create(item.description).object,
|
||||||
|
quantity: Quantity.create(item.quantity).object,
|
||||||
|
unitPrice: UnitPrice.create({
|
||||||
|
amount: item.unit_price.amount,
|
||||||
|
currencyCode: item.unit_price.currency,
|
||||||
|
precision: item.unit_price.precision,
|
||||||
|
}).object,
|
||||||
|
}).object
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!customerCustomerInvoice_status.isDraft()) {
|
||||||
|
throw Error("Error al crear una factura que no es borrador");
|
||||||
|
}
|
||||||
|
|
||||||
|
return DraftCustomerInvoice.create(
|
||||||
|
{
|
||||||
|
customerCustomerInvoiceSeries: customerCustomerInvoice_series,
|
||||||
|
issueDate: issue_date,
|
||||||
|
operationDate: operation_date,
|
||||||
|
customerCustomerInvoiceCurrency,
|
||||||
|
language: customerCustomerInvoiceLanguage,
|
||||||
|
customerCustomerInvoiceNumber: CustomerInvoiceNumber.create(undefined).object,
|
||||||
|
//notes: Note.create(customerCustomerInvoiceDTO.notes).object,
|
||||||
|
|
||||||
|
//senderId: UniqueID.create(null).object,
|
||||||
|
recipient,
|
||||||
|
|
||||||
|
items,
|
||||||
|
},
|
||||||
|
customerCustomerInvoiceId
|
||||||
|
);
|
||||||
|
} */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* export type UpdateCustomerInvoiceResponseOrError =
|
||||||
|
| Result<never, IUseCaseError> // Misc errors (value objects)
|
||||||
|
| Result<CustomerInvoice, never>; // Success!
|
||||||
|
|
||||||
|
export class UpdateCustomerInvoiceUseCase2
|
||||||
|
implements
|
||||||
|
IUseCase<{ id: UniqueID; data: IUpdateCustomerInvoice_DTO }, Promise<UpdateCustomerInvoiceResponseOrError>>
|
||||||
|
{
|
||||||
|
private _context: IInvoicingContext;
|
||||||
|
private _adapter: ISequelizeAdapter;
|
||||||
|
private _repositoryManager: IRepositoryManager;
|
||||||
|
|
||||||
|
constructor(context: IInvoicingContext) {
|
||||||
|
this._context = context;
|
||||||
|
this._adapter = context.adapter;
|
||||||
|
this._repositoryManager = context.repositoryManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
private getRepository<T>(name: string) {
|
||||||
|
return this._repositoryManager.getRepository<T>(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
private handleValidationFailure(
|
||||||
|
validationError: Error,
|
||||||
|
message?: string
|
||||||
|
): Result<never, IUseCaseError> {
|
||||||
|
return Result.fail<IUseCaseError>(
|
||||||
|
UseCaseError.create(
|
||||||
|
UseCaseError.INVALID_INPUT_DATA,
|
||||||
|
message ? message : validationError.message,
|
||||||
|
validationError
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
async execute(request: {
|
||||||
|
id: UniqueID;
|
||||||
|
data: IUpdateCustomerInvoice_DTO;
|
||||||
|
}): Promise<UpdateCustomerInvoiceResponseOrError> {
|
||||||
|
const { id, data: customerCustomerInvoiceDTO } = request;
|
||||||
|
|
||||||
|
// Validaciones
|
||||||
|
const customerCustomerInvoiceDTOOrError = ensureUpdateCustomerInvoice_DTOIsValid(customerCustomerInvoiceDTO);
|
||||||
|
if (customerCustomerInvoiceDTOOrError.isFailure) {
|
||||||
|
return this.handleValidationFailure(customerCustomerInvoiceDTOOrError.error);
|
||||||
|
}
|
||||||
|
|
||||||
|
const transaction = this._adapter.startTransaction();
|
||||||
|
|
||||||
|
const customerCustomerInvoiceRepoBuilder = this.getRepository<ICustomerInvoiceRepository>("CustomerInvoice");
|
||||||
|
|
||||||
|
let customerCustomerInvoice: CustomerInvoice | null = null;
|
||||||
|
|
||||||
|
try {
|
||||||
|
await transaction.complete(async (t) => {
|
||||||
|
customerCustomerInvoice = await customerCustomerInvoiceRepoBuilder({ transaction: t }).getById(id);
|
||||||
|
});
|
||||||
|
|
||||||
|
if (customerCustomerInvoice === null) {
|
||||||
|
return Result.fail<IUseCaseError>(
|
||||||
|
UseCaseError.create(UseCaseError.NOT_FOUND_ERROR, `CustomerInvoice not found`, {
|
||||||
|
id: request.id.toString(),
|
||||||
|
entity: "customerCustomerInvoice",
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Result.ok<CustomerInvoice>(customerCustomerInvoice);
|
||||||
|
} catch (error: unknown) {
|
||||||
|
const _error = error as Error;
|
||||||
|
if (customerCustomerInvoiceRepoBuilder().isRepositoryError(_error)) {
|
||||||
|
return this.handleRepositoryError(error as BaseError, customerCustomerInvoiceRepoBuilder());
|
||||||
|
} else {
|
||||||
|
return this.handleUnexceptedError(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Recipient validations
|
||||||
|
const recipientIdOrError = ensureParticipantIdIsValid(
|
||||||
|
customerCustomerInvoiceDTO?.recipient?.id,
|
||||||
|
);
|
||||||
|
if (recipientIdOrError.isFailure) {
|
||||||
|
return this.handleValidationFailure(
|
||||||
|
recipientIdOrError.error,
|
||||||
|
"Recipient ID not valid",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
const recipientId = recipientIdOrError.object;
|
||||||
|
|
||||||
|
const recipientBillingIdOrError = ensureParticipantAddressIdIsValid(
|
||||||
|
customerCustomerInvoiceDTO?.recipient?.billing_address_id,
|
||||||
|
);
|
||||||
|
if (recipientBillingIdOrError.isFailure) {
|
||||||
|
return this.handleValidationFailure(
|
||||||
|
recipientBillingIdOrError.error,
|
||||||
|
"Recipient billing address ID not valid",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
const recipientBillingId = recipientBillingIdOrError.object;
|
||||||
|
|
||||||
|
const recipientShippingIdOrError = ensureParticipantAddressIdIsValid(
|
||||||
|
customerCustomerInvoiceDTO?.recipient?.shipping_address_id,
|
||||||
|
);
|
||||||
|
if (recipientShippingIdOrError.isFailure) {
|
||||||
|
return this.handleValidationFailure(
|
||||||
|
recipientShippingIdOrError.error,
|
||||||
|
"Recipient shipping address ID not valid",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
const recipientShippingId = recipientShippingIdOrError.object;
|
||||||
|
|
||||||
|
const recipientContact = await this.findContact(
|
||||||
|
recipientId,
|
||||||
|
recipientBillingId,
|
||||||
|
recipientShippingId,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!recipientContact) {
|
||||||
|
return this.handleValidationFailure(
|
||||||
|
new Error(`Recipient with ID ${recipientId.toString()} does not exist`),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Crear customerCustomerInvoice
|
||||||
|
const customerCustomerInvoiceOrError = await this.tryUpdateCustomerInvoiceInstance(
|
||||||
|
customerCustomerInvoiceDTO,
|
||||||
|
customerCustomerInvoiceIdOrError.object,
|
||||||
|
//senderId,
|
||||||
|
//senderBillingId,
|
||||||
|
//senderShippingId,
|
||||||
|
recipientContact,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (customerCustomerInvoiceOrError.isFailure) {
|
||||||
|
const { error: domainError } = customerCustomerInvoiceOrError;
|
||||||
|
let errorCode = "";
|
||||||
|
let message = "";
|
||||||
|
|
||||||
|
switch (domainError.code) {
|
||||||
|
case CustomerInvoice.ERROR_CUSTOMER_WITHOUT_NAME:
|
||||||
|
errorCode = UseCaseError.INVALID_INPUT_DATA;
|
||||||
|
message =
|
||||||
|
"El cliente debe ser una compañía o tener nombre y apellidos.";
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
errorCode = UseCaseError.UNEXCEPTED_ERROR;
|
||||||
|
message = "";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Result.fail<IUseCaseError>(
|
||||||
|
UseCaseError.create(errorCode, message, domainError),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.saveCustomerInvoice(customerCustomerInvoiceOrError.object);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private async tryUpdateCustomerInvoiceInstance(customerCustomerInvoiceDTO, customerCustomerInvoiceId, recipient) {
|
||||||
|
// Create customerCustomerInvoice
|
||||||
|
let customerCustomerInvoice_status = CustomerInvoiceStatus.create(customerCustomerInvoiceDTO.status).object;
|
||||||
|
if (customerCustomerInvoice_status.isEmpty()) {
|
||||||
|
customerCustomerInvoice_status = CustomerInvoiceStatus.createDraft();
|
||||||
|
}
|
||||||
|
|
||||||
|
let customerCustomerInvoice_series = CustomerInvoiceSeries.create(customerCustomerInvoiceDTO.customerCustomerInvoice_series).object;
|
||||||
|
if (customerCustomerInvoice_series.isEmpty()) {
|
||||||
|
customerCustomerInvoice_series = CustomerInvoiceSeries.create(customerCustomerInvoiceDTO.customerCustomerInvoice_series).object;
|
||||||
|
}
|
||||||
|
|
||||||
|
let issue_date = CustomerInvoiceDate.create(customerCustomerInvoiceDTO.issue_date).object;
|
||||||
|
if (issue_date.isEmpty()) {
|
||||||
|
issue_date = CustomerInvoiceDate.createCurrentDate().object;
|
||||||
|
}
|
||||||
|
|
||||||
|
let operation_date = CustomerInvoiceDate.create(customerCustomerInvoiceDTO.operation_date).object;
|
||||||
|
if (operation_date.isEmpty()) {
|
||||||
|
operation_date = CustomerInvoiceDate.createCurrentDate().object;
|
||||||
|
}
|
||||||
|
|
||||||
|
let customerCustomerInvoiceCurrency = Currency.createFromCode(customerCustomerInvoiceDTO.currency).object;
|
||||||
|
|
||||||
|
if (customerCustomerInvoiceCurrency.isEmpty()) {
|
||||||
|
customerCustomerInvoiceCurrency = Currency.createDefaultCode().object;
|
||||||
|
}
|
||||||
|
|
||||||
|
let customerCustomerInvoiceLanguage = Language.createFromCode(customerCustomerInvoiceDTO.language_code).object;
|
||||||
|
|
||||||
|
if (customerCustomerInvoiceLanguage.isEmpty()) {
|
||||||
|
customerCustomerInvoiceLanguage = Language.createDefaultCode().object;
|
||||||
|
}
|
||||||
|
|
||||||
|
const items = new Collection<CustomerInvoiceItem>(
|
||||||
|
customerCustomerInvoiceDTO.items?.map(
|
||||||
|
(item) =>
|
||||||
|
CustomerInvoiceSimpleItem.create({
|
||||||
|
description: Description.create(item.description).object,
|
||||||
|
quantity: Quantity.create(item.quantity).object,
|
||||||
|
unitPrice: UnitPrice.create({
|
||||||
|
amount: item.unit_price.amount,
|
||||||
|
currencyCode: item.unit_price.currency,
|
||||||
|
precision: item.unit_price.precision,
|
||||||
|
}).object,
|
||||||
|
}).object
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!customerCustomerInvoice_status.isDraft()) {
|
||||||
|
throw Error("Error al crear una factura que no es borrador");
|
||||||
|
}
|
||||||
|
|
||||||
|
return DraftCustomerInvoice.create(
|
||||||
|
{
|
||||||
|
customerCustomerInvoiceSeries: customerCustomerInvoice_series,
|
||||||
|
issueDate: issue_date,
|
||||||
|
operationDate: operation_date,
|
||||||
|
customerCustomerInvoiceCurrency,
|
||||||
|
language: customerCustomerInvoiceLanguage,
|
||||||
|
customerCustomerInvoiceNumber: CustomerInvoiceNumber.create(undefined).object,
|
||||||
|
//notes: Note.create(customerCustomerInvoiceDTO.notes).object,
|
||||||
|
|
||||||
|
//senderId: UniqueID.create(null).object,
|
||||||
|
recipient,
|
||||||
|
|
||||||
|
items,
|
||||||
|
},
|
||||||
|
customerCustomerInvoiceId
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async findContact(
|
||||||
|
contactId: UniqueID,
|
||||||
|
billingAddressId: UniqueID,
|
||||||
|
shippingAddressId: UniqueID
|
||||||
|
) {
|
||||||
|
const contactRepoBuilder = this.getRepository<IContactRepository>("Contact");
|
||||||
|
|
||||||
|
const contact = await contactRepoBuilder().getById2(
|
||||||
|
contactId,
|
||||||
|
billingAddressId,
|
||||||
|
shippingAddressId
|
||||||
|
);
|
||||||
|
|
||||||
|
return contact;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async saveCustomerInvoice(customerCustomerInvoice: DraftCustomerInvoice) {
|
||||||
|
const transaction = this._adapter.startTransaction();
|
||||||
|
const customerCustomerInvoiceRepoBuilder = this.getRepository<ICustomerInvoiceRepository>("CustomerInvoice");
|
||||||
|
|
||||||
|
try {
|
||||||
|
await transaction.complete(async (t) => {
|
||||||
|
const customerCustomerInvoiceRepo = customerCustomerInvoiceRepoBuilder({ transaction: t });
|
||||||
|
await customerCustomerInvoiceRepo.save(customerCustomerInvoice);
|
||||||
|
});
|
||||||
|
|
||||||
|
return Result.ok<DraftCustomerInvoice>(customerCustomerInvoice);
|
||||||
|
} catch (error: unknown) {
|
||||||
|
const _error = error as Error;
|
||||||
|
if (customerCustomerInvoiceRepoBuilder().isRepositoryError(_error)) {
|
||||||
|
return this.handleRepositoryError(error as BaseError, customerCustomerInvoiceRepoBuilder());
|
||||||
|
} else {
|
||||||
|
return this.handleUnexceptedError(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private handleUnexceptedError(error): Result<never, IUseCaseError> {
|
||||||
|
return Result.fail<IUseCaseError>(
|
||||||
|
UseCaseError.create(UseCaseError.UNEXCEPTED_ERROR, error.message, error)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private handleRepositoryError(
|
||||||
|
error: BaseError,
|
||||||
|
repository: ICustomerInvoiceRepository
|
||||||
|
): Result<never, IUseCaseError> {
|
||||||
|
const { message, details } = repository.handleRepositoryError(error);
|
||||||
|
return Result.fail<IUseCaseError>(
|
||||||
|
UseCaseError.create(UseCaseError.REPOSITORY_ERROR, message, details)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
@ -1,13 +1,13 @@
|
|||||||
import { AggregateRoot, MoneyValue, UniqueID, UtcDate } from "@repo/rdx-ddd";
|
import { AggregateRoot, MoneyValue, UniqueID, UtcDate } from "@repo/rdx-ddd";
|
||||||
import { Collection, Result } from "@repo/rdx-utils";
|
import { Collection, Result } from "@repo/rdx-utils";
|
||||||
import { InvoiceCustomer, InvoiceItem, InvoiceItems } from "../entities";
|
import { CustomerInvoiceCustomer, CustomerInvoiceItem, CustomerInvoiceItems } from "../entities";
|
||||||
import { InvoiceNumber, InvoiceSerie, InvoiceStatus } from "../value-objects";
|
import { CustomerInvoiceNumber, CustomerInvoiceSerie, CustomerInvoiceStatus } from "../value-objects";
|
||||||
|
|
||||||
export interface IInvoiceProps {
|
export interface ICustomerInvoiceProps {
|
||||||
invoiceNumber: InvoiceNumber;
|
customerCustomerInvoiceNumber: CustomerInvoiceNumber;
|
||||||
invoiceSeries: InvoiceSerie;
|
customerCustomerInvoiceSeries: CustomerInvoiceSerie;
|
||||||
|
|
||||||
status: InvoiceStatus;
|
status: CustomerInvoiceStatus;
|
||||||
|
|
||||||
issueDate: UtcDate;
|
issueDate: UtcDate;
|
||||||
operationDate: UtcDate;
|
operationDate: UtcDate;
|
||||||
@ -15,7 +15,7 @@ export interface IInvoiceProps {
|
|||||||
//dueDate: UtcDate; // ? --> depende de la forma de pago
|
//dueDate: UtcDate; // ? --> depende de la forma de pago
|
||||||
|
|
||||||
//tax: Tax; // ? --> detalles?
|
//tax: Tax; // ? --> detalles?
|
||||||
invoiceCurrency: string;
|
customerCustomerInvoiceCurrency: string;
|
||||||
|
|
||||||
//language: Language;
|
//language: Language;
|
||||||
|
|
||||||
@ -27,29 +27,29 @@ export interface IInvoiceProps {
|
|||||||
//paymentInstructions: Note;
|
//paymentInstructions: Note;
|
||||||
//paymentTerms: string;
|
//paymentTerms: string;
|
||||||
|
|
||||||
customer?: InvoiceCustomer;
|
customer?: CustomerInvoiceCustomer;
|
||||||
items?: InvoiceItems;
|
items?: CustomerInvoiceItems;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IInvoice {
|
export interface ICustomerInvoice {
|
||||||
id: UniqueID;
|
id: UniqueID;
|
||||||
invoiceNumber: InvoiceNumber;
|
customerCustomerInvoiceNumber: CustomerInvoiceNumber;
|
||||||
invoiceSeries: InvoiceSerie;
|
customerCustomerInvoiceSeries: CustomerInvoiceSerie;
|
||||||
|
|
||||||
status: InvoiceStatus;
|
status: CustomerInvoiceStatus;
|
||||||
|
|
||||||
issueDate: UtcDate;
|
issueDate: UtcDate;
|
||||||
operationDate: UtcDate;
|
operationDate: UtcDate;
|
||||||
|
|
||||||
//senderId: UniqueID;
|
//senderId: UniqueID;
|
||||||
|
|
||||||
customer?: InvoiceCustomer;
|
customer?: CustomerInvoiceCustomer;
|
||||||
|
|
||||||
//dueDate
|
//dueDate
|
||||||
|
|
||||||
//tax: Tax;
|
//tax: Tax;
|
||||||
//language: Language;
|
//language: Language;
|
||||||
invoiceCurrency: string;
|
customerCustomerInvoiceCurrency: string;
|
||||||
|
|
||||||
//purchareOrderNumber: string;
|
//purchareOrderNumber: string;
|
||||||
//notes: Note;
|
//notes: Note;
|
||||||
@ -57,43 +57,43 @@ export interface IInvoice {
|
|||||||
//paymentInstructions: Note;
|
//paymentInstructions: Note;
|
||||||
//paymentTerms: string;
|
//paymentTerms: string;
|
||||||
|
|
||||||
items: InvoiceItems;
|
items: CustomerInvoiceItems;
|
||||||
|
|
||||||
calculateSubtotal: () => MoneyValue;
|
calculateSubtotal: () => MoneyValue;
|
||||||
calculateTaxTotal: () => MoneyValue;
|
calculateTaxTotal: () => MoneyValue;
|
||||||
calculateTotal: () => MoneyValue;
|
calculateTotal: () => MoneyValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class Invoice extends AggregateRoot<IInvoiceProps> implements IInvoice {
|
export class CustomerInvoice extends AggregateRoot<ICustomerInvoiceProps> implements ICustomerInvoice {
|
||||||
private _items!: Collection<InvoiceItem>;
|
private _items!: Collection<CustomerInvoiceItem>;
|
||||||
//protected _status: InvoiceStatus;
|
//protected _status: CustomerInvoiceStatus;
|
||||||
|
|
||||||
protected constructor(props: IInvoiceProps, id?: UniqueID) {
|
protected constructor(props: ICustomerInvoiceProps, id?: UniqueID) {
|
||||||
super(props, id);
|
super(props, id);
|
||||||
|
|
||||||
this._items = props.items || InvoiceItems.create();
|
this._items = props.items || CustomerInvoiceItems.create();
|
||||||
}
|
}
|
||||||
|
|
||||||
static create(props: IInvoiceProps, id?: UniqueID): Result<Invoice, Error> {
|
static create(props: ICustomerInvoiceProps, id?: UniqueID): Result<CustomerInvoice, Error> {
|
||||||
const invoice = new Invoice(props, id);
|
const customerCustomerInvoice = new CustomerInvoice(props, id);
|
||||||
|
|
||||||
// Reglas de negocio / validaciones
|
// Reglas de negocio / validaciones
|
||||||
// ...
|
// ...
|
||||||
// ...
|
// ...
|
||||||
|
|
||||||
// 🔹 Disparar evento de dominio "InvoiceAuthenticatedEvent"
|
// 🔹 Disparar evento de dominio "CustomerInvoiceAuthenticatedEvent"
|
||||||
//const { invoice } = props;
|
//const { customerCustomerInvoice } = props;
|
||||||
//user.addDomainEvent(new InvoiceAuthenticatedEvent(id, invoice.toString()));
|
//user.addDomainEvent(new CustomerInvoiceAuthenticatedEvent(id, customerCustomerInvoice.toString()));
|
||||||
|
|
||||||
return Result.ok(invoice);
|
return Result.ok(customerCustomerInvoice);
|
||||||
}
|
}
|
||||||
|
|
||||||
get invoiceNumber() {
|
get customerCustomerInvoiceNumber() {
|
||||||
return this.props.invoiceNumber;
|
return this.props.customerCustomerInvoiceNumber;
|
||||||
}
|
}
|
||||||
|
|
||||||
get invoiceSeries() {
|
get customerCustomerInvoiceSeries() {
|
||||||
return this.props.invoiceSeries;
|
return this.props.customerCustomerInvoiceSeries;
|
||||||
}
|
}
|
||||||
|
|
||||||
get issueDate() {
|
get issueDate() {
|
||||||
@ -104,7 +104,7 @@ export class Invoice extends AggregateRoot<IInvoiceProps> implements IInvoice {
|
|||||||
return this.props.senderId;
|
return this.props.senderId;
|
||||||
}*/
|
}*/
|
||||||
|
|
||||||
get customer(): InvoiceCustomer | undefined {
|
get customer(): CustomerInvoiceCustomer | undefined {
|
||||||
return this.props.customer;
|
return this.props.customer;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -152,8 +152,8 @@ export class Invoice extends AggregateRoot<IInvoiceProps> implements IInvoice {
|
|||||||
return this.props.shipTo;
|
return this.props.shipTo;
|
||||||
}*/
|
}*/
|
||||||
|
|
||||||
get invoiceCurrency() {
|
get customerCustomerInvoiceCurrency() {
|
||||||
return this.props.invoiceCurrency;
|
return this.props.customerCustomerInvoiceCurrency;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*get notes() {
|
/*get notes() {
|
||||||
@ -161,11 +161,11 @@ export class Invoice extends AggregateRoot<IInvoiceProps> implements IInvoice {
|
|||||||
}*/
|
}*/
|
||||||
|
|
||||||
// Method to get the complete list of line items
|
// Method to get the complete list of line items
|
||||||
/*get lineItems(): InvoiceLineItem[] {
|
/*get lineItems(): CustomerInvoiceLineItem[] {
|
||||||
return this._lineItems;
|
return this._lineItems;
|
||||||
}
|
}
|
||||||
|
|
||||||
addLineItem(lineItem: InvoiceLineItem, position?: number): void {
|
addLineItem(lineItem: CustomerInvoiceLineItem, position?: number): void {
|
||||||
if (position === undefined) {
|
if (position === undefined) {
|
||||||
this._lineItems.push(lineItem);
|
this._lineItems.push(lineItem);
|
||||||
} else {
|
} else {
|
||||||
@ -174,29 +174,29 @@ export class Invoice extends AggregateRoot<IInvoiceProps> implements IInvoice {
|
|||||||
}*/
|
}*/
|
||||||
|
|
||||||
calculateSubtotal(): MoneyValue {
|
calculateSubtotal(): MoneyValue {
|
||||||
const invoiceSubtotal = MoneyValue.create({
|
const customerCustomerInvoiceSubtotal = MoneyValue.create({
|
||||||
amount: 0,
|
amount: 0,
|
||||||
currency_code: this.props.invoiceCurrency,
|
currency_code: this.props.customerCustomerInvoiceCurrency,
|
||||||
scale: 2,
|
scale: 2,
|
||||||
}).data;
|
}).data;
|
||||||
|
|
||||||
return this._items.getAll().reduce((subtotal, item) => {
|
return this._items.getAll().reduce((subtotal, item) => {
|
||||||
return subtotal.add(item.calculateTotal());
|
return subtotal.add(item.calculateTotal());
|
||||||
}, invoiceSubtotal);
|
}, customerCustomerInvoiceSubtotal);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Method to calculate the total tax in the invoice
|
// Method to calculate the total tax in the customerCustomerInvoice
|
||||||
calculateTaxTotal(): MoneyValue {
|
calculateTaxTotal(): MoneyValue {
|
||||||
const taxTotal = MoneyValue.create({
|
const taxTotal = MoneyValue.create({
|
||||||
amount: 0,
|
amount: 0,
|
||||||
currency_code: this.props.invoiceCurrency,
|
currency_code: this.props.customerCustomerInvoiceCurrency,
|
||||||
scale: 2,
|
scale: 2,
|
||||||
}).data;
|
}).data;
|
||||||
|
|
||||||
return taxTotal;
|
return taxTotal;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Method to calculate the total invoice amount, including taxes
|
// Method to calculate the total customerCustomerInvoice amount, including taxes
|
||||||
calculateTotal(): MoneyValue {
|
calculateTotal(): MoneyValue {
|
||||||
return this.calculateSubtotal().add(this.calculateTaxTotal());
|
return this.calculateSubtotal().add(this.calculateTaxTotal());
|
||||||
}
|
}
|
||||||
@ -0,0 +1 @@
|
|||||||
|
export * from "./customerCustomerInvoice";
|
||||||
@ -0,0 +1,2 @@
|
|||||||
|
export * from "./customerCustomerInvoice-customer";
|
||||||
|
export * from "./customerCustomerInvoice-items";
|
||||||
@ -0,0 +1,2 @@
|
|||||||
|
export * from "./customerCustomerInvoice-address";
|
||||||
|
export * from "./customerCustomerInvoice-customer";
|
||||||
@ -1,43 +1,43 @@
|
|||||||
import { EmailAddress, Name, PostalAddress, ValueObject } from "@repo/rdx-ddd";
|
import { EmailAddress, Name, PostalAddress, ValueObject } from "@repo/rdx-ddd";
|
||||||
import { Result } from "@repo/rdx-utils";
|
import { Result } from "@repo/rdx-utils";
|
||||||
import { PhoneNumber } from "libphonenumber-js";
|
import { PhoneNumber } from "libphonenumber-js";
|
||||||
import { InvoiceAddressType } from "../../value-objects";
|
import { CustomerInvoiceAddressType } from "../../value-objects";
|
||||||
|
|
||||||
export interface IInvoiceAddressProps {
|
export interface ICustomerInvoiceAddressProps {
|
||||||
type: InvoiceAddressType;
|
type: CustomerInvoiceAddressType;
|
||||||
title: Name;
|
title: Name;
|
||||||
address: PostalAddress;
|
address: PostalAddress;
|
||||||
email: EmailAddress;
|
email: EmailAddress;
|
||||||
phone: PhoneNumber;
|
phone: PhoneNumber;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IInvoiceAddress {
|
export interface ICustomerInvoiceAddress {
|
||||||
type: InvoiceAddressType;
|
type: CustomerInvoiceAddressType;
|
||||||
title: Name;
|
title: Name;
|
||||||
address: PostalAddress;
|
address: PostalAddress;
|
||||||
email: EmailAddress;
|
email: EmailAddress;
|
||||||
phone: PhoneNumber;
|
phone: PhoneNumber;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class InvoiceAddress extends ValueObject<IInvoiceAddressProps> implements IInvoiceAddress {
|
export class CustomerInvoiceAddress extends ValueObject<ICustomerInvoiceAddressProps> implements ICustomerInvoiceAddress {
|
||||||
public static create(props: IInvoiceAddressProps) {
|
public static create(props: ICustomerInvoiceAddressProps) {
|
||||||
return Result.ok(new InvoiceAddress(props));
|
return Result.ok(new CustomerInvoiceAddress(props));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static createShippingAddress(props: IInvoiceAddressProps) {
|
public static createShippingAddress(props: ICustomerInvoiceAddressProps) {
|
||||||
return Result.ok(
|
return Result.ok(
|
||||||
new InvoiceAddress({
|
new CustomerInvoiceAddress({
|
||||||
...props,
|
...props,
|
||||||
type: InvoiceAddressType.create("shipping").data,
|
type: CustomerInvoiceAddressType.create("shipping").data,
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static createBillingAddress(props: IInvoiceAddressProps) {
|
public static createBillingAddress(props: ICustomerInvoiceAddressProps) {
|
||||||
return Result.ok(
|
return Result.ok(
|
||||||
new InvoiceAddress({
|
new CustomerInvoiceAddress({
|
||||||
...props,
|
...props,
|
||||||
type: InvoiceAddressType.create("billing").data,
|
type: CustomerInvoiceAddressType.create("billing").data,
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -58,11 +58,11 @@ export class InvoiceAddress extends ValueObject<IInvoiceAddressProps> implements
|
|||||||
return this.props.phone;
|
return this.props.phone;
|
||||||
}
|
}
|
||||||
|
|
||||||
get type(): InvoiceAddressType {
|
get type(): CustomerInvoiceAddressType {
|
||||||
return this.props.type;
|
return this.props.type;
|
||||||
}
|
}
|
||||||
|
|
||||||
getValue(): IInvoiceAddressProps {
|
getValue(): ICustomerInvoiceAddressProps {
|
||||||
return this.props;
|
return this.props;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1,38 +1,38 @@
|
|||||||
import { DomainEntity, Name, TINNumber, UniqueID } from "@repo/rdx-ddd";
|
import { DomainEntity, Name, TINNumber, UniqueID } from "@repo/rdx-ddd";
|
||||||
import { Result } from "@repo/rdx-utils";
|
import { Result } from "@repo/rdx-utils";
|
||||||
import { InvoiceAddress } from "./invoice-address";
|
import { CustomerInvoiceAddress } from "./customerCustomerInvoice-address";
|
||||||
|
|
||||||
export interface IInvoiceCustomerProps {
|
export interface ICustomerInvoiceCustomerProps {
|
||||||
tin: TINNumber;
|
tin: TINNumber;
|
||||||
companyName: Name;
|
companyName: Name;
|
||||||
firstName: Name;
|
firstName: Name;
|
||||||
lastName: Name;
|
lastName: Name;
|
||||||
|
|
||||||
billingAddress?: InvoiceAddress;
|
billingAddress?: CustomerInvoiceAddress;
|
||||||
shippingAddress?: InvoiceAddress;
|
shippingAddress?: CustomerInvoiceAddress;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IInvoiceCustomer {
|
export interface ICustomerInvoiceCustomer {
|
||||||
id: UniqueID;
|
id: UniqueID;
|
||||||
tin: TINNumber;
|
tin: TINNumber;
|
||||||
companyName: Name;
|
companyName: Name;
|
||||||
firstName: Name;
|
firstName: Name;
|
||||||
lastName: Name;
|
lastName: Name;
|
||||||
|
|
||||||
billingAddress?: InvoiceAddress;
|
billingAddress?: CustomerInvoiceAddress;
|
||||||
shippingAddress?: InvoiceAddress;
|
shippingAddress?: CustomerInvoiceAddress;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class InvoiceCustomer
|
export class CustomerInvoiceCustomer
|
||||||
extends DomainEntity<IInvoiceCustomerProps>
|
extends DomainEntity<ICustomerInvoiceCustomerProps>
|
||||||
implements IInvoiceCustomer
|
implements ICustomerInvoiceCustomer
|
||||||
{
|
{
|
||||||
public static create(
|
public static create(
|
||||||
props: IInvoiceCustomerProps,
|
props: ICustomerInvoiceCustomerProps,
|
||||||
id?: UniqueID
|
id?: UniqueID
|
||||||
): Result<InvoiceCustomer, Error> {
|
): Result<CustomerInvoiceCustomer, Error> {
|
||||||
const participant = new InvoiceCustomer(props, id);
|
const participant = new CustomerInvoiceCustomer(props, id);
|
||||||
return Result.ok<InvoiceCustomer>(participant);
|
return Result.ok<CustomerInvoiceCustomer>(participant);
|
||||||
}
|
}
|
||||||
|
|
||||||
get tin(): TINNumber {
|
get tin(): TINNumber {
|
||||||
@ -0,0 +1,2 @@
|
|||||||
|
export * from "./customerCustomerInvoice-item";
|
||||||
|
export * from "./customerCustomerInvoice-items";
|
||||||
@ -0,0 +1,83 @@
|
|||||||
|
import { MoneyValue, Percentage, Quantity } from "@/core/common/domain";
|
||||||
|
import { CustomerInvoiceItemDescription } from "../../value-objects";
|
||||||
|
import { CustomerInvoiceItem } from "./customerCustomerInvoice-item";
|
||||||
|
|
||||||
|
describe("CustomerInvoiceItem", () => {
|
||||||
|
it("debería calcular correctamente el subtotal (unitPrice * quantity)", () => {
|
||||||
|
const props = {
|
||||||
|
description: CustomerInvoiceItemDescription.create("Producto A"),
|
||||||
|
quantity: Quantity.create({ amount: 200, scale: 2 }),
|
||||||
|
unitPrice: MoneyValue.create(50),
|
||||||
|
discount: Percentage.create(0),
|
||||||
|
};
|
||||||
|
|
||||||
|
const result = CustomerInvoiceItem.create(props);
|
||||||
|
|
||||||
|
expect(result.isOk()).toBe(true);
|
||||||
|
const customerCustomerInvoiceItem = result.unwrap();
|
||||||
|
expect(customerCustomerInvoiceItem.subtotalPrice.value).toBe(100); // 50 * 2
|
||||||
|
});
|
||||||
|
|
||||||
|
it("debería calcular correctamente el total con descuento", () => {
|
||||||
|
const props = {
|
||||||
|
description: new CustomerInvoiceItemDescription("Producto B"),
|
||||||
|
quantity: new Quantity(3),
|
||||||
|
unitPrice: new MoneyValue(30),
|
||||||
|
discount: new Percentage(10), // 10%
|
||||||
|
};
|
||||||
|
|
||||||
|
const result = CustomerInvoiceItem.create(props);
|
||||||
|
|
||||||
|
expect(result.isOk()).toBe(true);
|
||||||
|
const customerCustomerInvoiceItem = result.unwrap();
|
||||||
|
expect(customerCustomerInvoiceItem.totalPrice.value).toBe(81); // (30 * 3) - 10% de (30 * 3)
|
||||||
|
});
|
||||||
|
|
||||||
|
it("debería devolver los valores correctos de las propiedades", () => {
|
||||||
|
const props = {
|
||||||
|
description: new CustomerInvoiceItemDescription("Producto C"),
|
||||||
|
quantity: new Quantity(1),
|
||||||
|
unitPrice: new MoneyValue(100),
|
||||||
|
discount: new Percentage(5),
|
||||||
|
};
|
||||||
|
|
||||||
|
const result = CustomerInvoiceItem.create(props);
|
||||||
|
|
||||||
|
expect(result.isOk()).toBe(true);
|
||||||
|
const customerCustomerInvoiceItem = result.unwrap();
|
||||||
|
expect(customerCustomerInvoiceItem.description.value).toBe("Producto C");
|
||||||
|
expect(customerCustomerInvoiceItem.quantity.value).toBe(1);
|
||||||
|
expect(customerCustomerInvoiceItem.unitPrice.value).toBe(100);
|
||||||
|
expect(customerCustomerInvoiceItem.discount.value).toBe(5);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("debería manejar correctamente un descuento del 0%", () => {
|
||||||
|
const props = {
|
||||||
|
description: new CustomerInvoiceItemDescription("Producto D"),
|
||||||
|
quantity: new Quantity(4),
|
||||||
|
unitPrice: new MoneyValue(25),
|
||||||
|
discount: new Percentage(0),
|
||||||
|
};
|
||||||
|
|
||||||
|
const result = CustomerInvoiceItem.create(props);
|
||||||
|
|
||||||
|
expect(result.isOk()).toBe(true);
|
||||||
|
const customerCustomerInvoiceItem = result.unwrap();
|
||||||
|
expect(customerCustomerInvoiceItem.totalPrice.value).toBe(100); // 25 * 4
|
||||||
|
});
|
||||||
|
|
||||||
|
it("debería manejar correctamente un descuento del 100%", () => {
|
||||||
|
const props = {
|
||||||
|
description: new CustomerInvoiceItemDescription("Producto E"),
|
||||||
|
quantity: new Quantity(2),
|
||||||
|
unitPrice: new MoneyValue(50),
|
||||||
|
discount: new Percentage(100),
|
||||||
|
};
|
||||||
|
|
||||||
|
const result = CustomerInvoiceItem.create(props);
|
||||||
|
|
||||||
|
expect(result.isOk()).toBe(true);
|
||||||
|
const customerCustomerInvoiceItem = result.unwrap();
|
||||||
|
expect(customerCustomerInvoiceItem.totalPrice.value).toBe(0); // (50 * 2) - 100% de (50 * 2)
|
||||||
|
});
|
||||||
|
});
|
||||||
@ -0,0 +1,101 @@
|
|||||||
|
import { DomainEntity, UniqueID } from "@repo/rdx-ddd";
|
||||||
|
import { Result } from "@repo/rdx-utils";
|
||||||
|
import {
|
||||||
|
CustomerInvoiceItemDescription,
|
||||||
|
CustomerInvoiceItemDiscount,
|
||||||
|
CustomerInvoiceItemQuantity,
|
||||||
|
CustomerInvoiceItemSubtotalPrice,
|
||||||
|
CustomerInvoiceItemTotalPrice,
|
||||||
|
CustomerInvoiceItemUnitPrice,
|
||||||
|
} from "../../value-objects";
|
||||||
|
|
||||||
|
export interface ICustomerInvoiceItemProps {
|
||||||
|
description: CustomerInvoiceItemDescription;
|
||||||
|
quantity: CustomerInvoiceItemQuantity; // Cantidad de unidades
|
||||||
|
unitPrice: CustomerInvoiceItemUnitPrice; // Precio unitario en la moneda de la factura
|
||||||
|
//subtotalPrice?: MoneyValue; // Precio unitario * Cantidad
|
||||||
|
discount: CustomerInvoiceItemDiscount; // % descuento
|
||||||
|
//totalPrice?: MoneyValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ICustomerInvoiceItem {
|
||||||
|
id: UniqueID;
|
||||||
|
description: CustomerInvoiceItemDescription;
|
||||||
|
quantity: CustomerInvoiceItemQuantity;
|
||||||
|
unitPrice: CustomerInvoiceItemUnitPrice;
|
||||||
|
subtotalPrice: CustomerInvoiceItemSubtotalPrice;
|
||||||
|
discount: CustomerInvoiceItemDiscount;
|
||||||
|
totalPrice: CustomerInvoiceItemTotalPrice;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class CustomerInvoiceItem extends DomainEntity<ICustomerInvoiceItemProps> implements ICustomerInvoiceItem {
|
||||||
|
private _subtotalPrice!: CustomerInvoiceItemSubtotalPrice;
|
||||||
|
private _totalPrice!: CustomerInvoiceItemTotalPrice;
|
||||||
|
|
||||||
|
public static create(props: ICustomerInvoiceItemProps, id?: UniqueID): Result<CustomerInvoiceItem, Error> {
|
||||||
|
const item = new CustomerInvoiceItem(props, id);
|
||||||
|
|
||||||
|
// Reglas de negocio / validaciones
|
||||||
|
// ...
|
||||||
|
// ...
|
||||||
|
|
||||||
|
// 🔹 Disparar evento de dominio "CustomerInvoiceItemCreatedEvent"
|
||||||
|
//const { customerCustomerInvoice } = props;
|
||||||
|
//user.addDomainEvent(new CustomerInvoiceAuthenticatedEvent(id, customerCustomerInvoice.toString()));
|
||||||
|
|
||||||
|
return Result.ok(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
get description(): CustomerInvoiceItemDescription {
|
||||||
|
return this.props.description;
|
||||||
|
}
|
||||||
|
|
||||||
|
get quantity(): CustomerInvoiceItemQuantity {
|
||||||
|
return this.props.quantity;
|
||||||
|
}
|
||||||
|
|
||||||
|
get unitPrice(): CustomerInvoiceItemUnitPrice {
|
||||||
|
return this.props.unitPrice;
|
||||||
|
}
|
||||||
|
|
||||||
|
get subtotalPrice(): CustomerInvoiceItemSubtotalPrice {
|
||||||
|
if (!this._subtotalPrice) {
|
||||||
|
this._subtotalPrice = this.calculateSubtotal();
|
||||||
|
}
|
||||||
|
return this._subtotalPrice;
|
||||||
|
}
|
||||||
|
|
||||||
|
get discount(): CustomerInvoiceItemDiscount {
|
||||||
|
return this.props.discount;
|
||||||
|
}
|
||||||
|
|
||||||
|
get totalPrice(): CustomerInvoiceItemTotalPrice {
|
||||||
|
if (!this._totalPrice) {
|
||||||
|
this._totalPrice = this.calculateTotal();
|
||||||
|
}
|
||||||
|
return this._totalPrice;
|
||||||
|
}
|
||||||
|
|
||||||
|
getValue() {
|
||||||
|
return this.props;
|
||||||
|
}
|
||||||
|
|
||||||
|
toPrimitive() {
|
||||||
|
return {
|
||||||
|
description: this.description.toPrimitive(),
|
||||||
|
quantity: this.quantity.toPrimitive(),
|
||||||
|
unit_price: this.unitPrice.toPrimitive(),
|
||||||
|
subtotal_price: this.subtotalPrice.toPrimitive(),
|
||||||
|
discount: this.discount.toPrimitive(),
|
||||||
|
total_price: this.totalPrice.toPrimitive(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
calculateSubtotal(): CustomerInvoiceItemSubtotalPrice {
|
||||||
|
return this.unitPrice.multiply(this.quantity.toNumber()); // Precio unitario * Cantidad
|
||||||
|
}
|
||||||
|
|
||||||
|
calculateTotal(): CustomerInvoiceItemTotalPrice {
|
||||||
|
return this.subtotalPrice.subtract(this.subtotalPrice.percentage(this.discount.toNumber()));
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,8 @@
|
|||||||
|
import { Collection } from "@repo/rdx-utils";
|
||||||
|
import { CustomerInvoiceItem } from "./customerCustomerInvoice-item";
|
||||||
|
|
||||||
|
export class CustomerInvoiceItems extends Collection<CustomerInvoiceItem> {
|
||||||
|
public static create(items?: CustomerInvoiceItem[]): CustomerInvoiceItems {
|
||||||
|
return new CustomerInvoiceItems(items);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,13 @@
|
|||||||
|
import { Criteria } from "@repo/rdx-criteria/server";
|
||||||
|
import { UniqueID } from "@repo/rdx-ddd";
|
||||||
|
import { Collection, Result } from "@repo/rdx-utils";
|
||||||
|
import { CustomerInvoice } from "../aggregates";
|
||||||
|
|
||||||
|
export interface ICustomerInvoiceRepository {
|
||||||
|
findAll(criteria: Criteria, transaction?: any): Promise<Result<Collection<CustomerInvoice>, Error>>;
|
||||||
|
getById(id: UniqueID, transaction?: any): Promise<Result<CustomerInvoice, Error>>;
|
||||||
|
deleteById(id: UniqueID, transaction?: any): Promise<Result<boolean, Error>>;
|
||||||
|
|
||||||
|
create(customerCustomerInvoice: CustomerInvoice, transaction?: any): Promise<void>;
|
||||||
|
update(customerCustomerInvoice: CustomerInvoice, transaction?: any): Promise<void>;
|
||||||
|
}
|
||||||
@ -0,0 +1 @@
|
|||||||
|
export * from "./customerCustomerInvoice-repository.interface";
|
||||||
@ -0,0 +1,23 @@
|
|||||||
|
import { Criteria } from "@repo/rdx-criteria/server";
|
||||||
|
import { UniqueID } from "@repo/rdx-ddd";
|
||||||
|
import { Collection, Result } from "@repo/rdx-utils";
|
||||||
|
import { ICustomerInvoiceProps, CustomerInvoice } from "../aggregates";
|
||||||
|
|
||||||
|
export interface ICustomerInvoiceService {
|
||||||
|
findCustomerInvoices(criteria: Criteria, transaction?: any): Promise<Result<Collection<CustomerInvoice>, Error>>;
|
||||||
|
findCustomerInvoiceById(customerCustomerInvoiceId: UniqueID, transaction?: any): Promise<Result<CustomerInvoice>>;
|
||||||
|
|
||||||
|
updateCustomerInvoiceById(
|
||||||
|
customerCustomerInvoiceId: UniqueID,
|
||||||
|
data: Partial<ICustomerInvoiceProps>,
|
||||||
|
transaction?: any
|
||||||
|
): Promise<Result<CustomerInvoice, Error>>;
|
||||||
|
|
||||||
|
createCustomerInvoice(
|
||||||
|
customerCustomerInvoiceId: UniqueID,
|
||||||
|
data: ICustomerInvoiceProps,
|
||||||
|
transaction?: any
|
||||||
|
): Promise<Result<CustomerInvoice, Error>>;
|
||||||
|
|
||||||
|
deleteCustomerInvoiceById(customerCustomerInvoiceId: UniqueID, transaction?: any): Promise<Result<boolean, Error>>;
|
||||||
|
}
|
||||||
@ -0,0 +1,86 @@
|
|||||||
|
import { Criteria } from "@repo/rdx-criteria/server";
|
||||||
|
import { UniqueID } from "@repo/rdx-ddd";
|
||||||
|
import { Collection, Result } from "@repo/rdx-utils";
|
||||||
|
import { Transaction } from "sequelize";
|
||||||
|
import { ICustomerInvoiceProps, CustomerInvoice } from "../aggregates";
|
||||||
|
import { ICustomerInvoiceRepository } from "../repositories";
|
||||||
|
import { ICustomerInvoiceService } from "./customerCustomerInvoice-service.interface";
|
||||||
|
|
||||||
|
export class CustomerInvoiceService implements ICustomerInvoiceService {
|
||||||
|
constructor(private readonly repo: ICustomerInvoiceRepository) {}
|
||||||
|
|
||||||
|
async findCustomerInvoices(
|
||||||
|
criteria: Criteria,
|
||||||
|
transaction?: Transaction
|
||||||
|
): Promise<Result<Collection<CustomerInvoice>, Error>> {
|
||||||
|
const customerCustomerInvoicesOrError = await this.repo.findAll(criteria, transaction);
|
||||||
|
if (customerCustomerInvoicesOrError.isFailure) {
|
||||||
|
return Result.fail(customerCustomerInvoicesOrError.error);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Solo devolver usuarios activos
|
||||||
|
//const allCustomerInvoices = customerCustomerInvoicesOrError.data.filter((customerCustomerInvoice) => customerCustomerInvoice.isActive);
|
||||||
|
//return Result.ok(new Collection(allCustomerInvoices));
|
||||||
|
|
||||||
|
return customerCustomerInvoicesOrError;
|
||||||
|
}
|
||||||
|
|
||||||
|
async findCustomerInvoiceById(customerCustomerInvoiceId: UniqueID, transaction?: Transaction): Promise<Result<CustomerInvoice>> {
|
||||||
|
return await this.repo.getById(customerCustomerInvoiceId, transaction);
|
||||||
|
}
|
||||||
|
|
||||||
|
async updateCustomerInvoiceById(
|
||||||
|
customerCustomerInvoiceId: UniqueID,
|
||||||
|
data: Partial<ICustomerInvoiceProps>,
|
||||||
|
transaction?: Transaction
|
||||||
|
): Promise<Result<CustomerInvoice, Error>> {
|
||||||
|
// Verificar si la factura existe
|
||||||
|
const customerCustomerInvoiceOrError = await this.repo.getById(customerCustomerInvoiceId, transaction);
|
||||||
|
if (customerCustomerInvoiceOrError.isFailure) {
|
||||||
|
return Result.fail(new Error("CustomerInvoice not found"));
|
||||||
|
}
|
||||||
|
|
||||||
|
return Result.fail(new Error("No implementado"));
|
||||||
|
|
||||||
|
/*const updatedCustomerInvoiceOrError = CustomerInvoice.update(customerCustomerInvoiceOrError.data, data);
|
||||||
|
if (updatedCustomerInvoiceOrError.isFailure) {
|
||||||
|
return Result.fail(
|
||||||
|
new Error(`Error updating customerCustomerInvoice: ${updatedCustomerInvoiceOrError.error.message}`)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const updateCustomerInvoice = updatedCustomerInvoiceOrError.data;
|
||||||
|
|
||||||
|
await this.repo.update(updateCustomerInvoice, transaction);
|
||||||
|
return Result.ok(updateCustomerInvoice);*/
|
||||||
|
}
|
||||||
|
|
||||||
|
async createCustomerInvoice(
|
||||||
|
customerCustomerInvoiceId: UniqueID,
|
||||||
|
data: ICustomerInvoiceProps,
|
||||||
|
transaction?: Transaction
|
||||||
|
): Promise<Result<CustomerInvoice, Error>> {
|
||||||
|
// Verificar si la factura existe
|
||||||
|
const customerCustomerInvoiceOrError = await this.repo.getById(customerCustomerInvoiceId, transaction);
|
||||||
|
if (customerCustomerInvoiceOrError.isSuccess) {
|
||||||
|
return Result.fail(new Error("CustomerInvoice exists"));
|
||||||
|
}
|
||||||
|
|
||||||
|
const newCustomerInvoiceOrError = CustomerInvoice.create(data, customerCustomerInvoiceId);
|
||||||
|
if (newCustomerInvoiceOrError.isFailure) {
|
||||||
|
return Result.fail(new Error(`Error creating customerCustomerInvoice: ${newCustomerInvoiceOrError.error.message}`));
|
||||||
|
}
|
||||||
|
|
||||||
|
const newCustomerInvoice = newCustomerInvoiceOrError.data;
|
||||||
|
|
||||||
|
await this.repo.create(newCustomerInvoice, transaction);
|
||||||
|
return Result.ok(newCustomerInvoice);
|
||||||
|
}
|
||||||
|
|
||||||
|
async deleteCustomerInvoiceById(
|
||||||
|
customerCustomerInvoiceId: UniqueID,
|
||||||
|
transaction?: Transaction
|
||||||
|
): Promise<Result<boolean, Error>> {
|
||||||
|
return this.repo.deleteById(customerCustomerInvoiceId, transaction);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,2 @@
|
|||||||
|
export * from "./customerCustomerInvoice-service.interface";
|
||||||
|
export * from "./customerCustomerInvoice.service";
|
||||||
@ -1,7 +1,7 @@
|
|||||||
import { ValueObject } from "@repo/rdx-ddd";
|
import { ValueObject } from "@repo/rdx-ddd";
|
||||||
import { Result } from "@repo/rdx-utils";
|
import { Result } from "@repo/rdx-utils";
|
||||||
|
|
||||||
interface IInvoiceAddressTypeProps {
|
interface ICustomerInvoiceAddressTypeProps {
|
||||||
value: string;
|
value: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -10,10 +10,10 @@ export enum INVOICE_ADDRESS_TYPE {
|
|||||||
BILLING = "billing",
|
BILLING = "billing",
|
||||||
}
|
}
|
||||||
|
|
||||||
export class InvoiceAddressType extends ValueObject<IInvoiceAddressTypeProps> {
|
export class CustomerInvoiceAddressType extends ValueObject<ICustomerInvoiceAddressTypeProps> {
|
||||||
private static readonly ALLOWED_TYPES = ["shipping", "billing"];
|
private static readonly ALLOWED_TYPES = ["shipping", "billing"];
|
||||||
|
|
||||||
static create(value: string): Result<InvoiceAddressType, Error> {
|
static create(value: string): Result<CustomerInvoiceAddressType, Error> {
|
||||||
if (!this.ALLOWED_TYPES.includes(value)) {
|
if (!this.ALLOWED_TYPES.includes(value)) {
|
||||||
return Result.fail(
|
return Result.fail(
|
||||||
new Error(
|
new Error(
|
||||||
@ -21,7 +21,7 @@ export class InvoiceAddressType extends ValueObject<IInvoiceAddressTypeProps> {
|
|||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return Result.ok(new InvoiceAddressType({ value }));
|
return Result.ok(new CustomerInvoiceAddressType({ value }));
|
||||||
}
|
}
|
||||||
|
|
||||||
getValue(): string {
|
getValue(): string {
|
||||||
@ -0,0 +1,50 @@
|
|||||||
|
import { ValueObject } from "@repo/rdx-ddd";
|
||||||
|
import { Maybe, Result } from "@repo/rdx-utils";
|
||||||
|
import { z } from "zod";
|
||||||
|
|
||||||
|
interface ICustomerInvoiceItemDescriptionProps {
|
||||||
|
value: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class CustomerInvoiceItemDescription extends ValueObject<ICustomerInvoiceItemDescriptionProps> {
|
||||||
|
private static readonly MAX_LENGTH = 255;
|
||||||
|
|
||||||
|
protected static validate(value: string) {
|
||||||
|
const schema = z
|
||||||
|
.string()
|
||||||
|
.trim()
|
||||||
|
.max(CustomerInvoiceItemDescription.MAX_LENGTH, {
|
||||||
|
message: `Description must be at most ${CustomerInvoiceItemDescription.MAX_LENGTH} characters long`,
|
||||||
|
});
|
||||||
|
return schema.safeParse(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
static create(value: string) {
|
||||||
|
const valueIsValid = CustomerInvoiceItemDescription.validate(value);
|
||||||
|
|
||||||
|
if (!valueIsValid.success) {
|
||||||
|
return Result.fail(new Error(valueIsValid.error.errors[0].message));
|
||||||
|
}
|
||||||
|
return Result.ok(new CustomerInvoiceItemDescription({ value }));
|
||||||
|
}
|
||||||
|
|
||||||
|
static createNullable(value?: string): Result<Maybe<CustomerInvoiceItemDescription>, Error> {
|
||||||
|
if (!value || value.trim() === "") {
|
||||||
|
return Result.ok(Maybe.none<CustomerInvoiceItemDescription>());
|
||||||
|
}
|
||||||
|
|
||||||
|
return CustomerInvoiceItemDescription.create(value).map((value) => Maybe.some(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
getValue(): string {
|
||||||
|
return this.props.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
toString(): string {
|
||||||
|
return this.getValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
toPrimitive() {
|
||||||
|
return this.getValue();
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,3 @@
|
|||||||
|
import { Percentage } from "@repo/rdx-ddd";
|
||||||
|
|
||||||
|
export class CustomerInvoiceItemDiscount extends Percentage {}
|
||||||
@ -0,0 +1,3 @@
|
|||||||
|
import { Quantity } from "@repo/rdx-ddd";
|
||||||
|
|
||||||
|
export class CustomerInvoiceItemQuantity extends Quantity {}
|
||||||
@ -1,6 +1,6 @@
|
|||||||
import { IMoneyValueProps, MoneyValue } from "@repo/rdx-ddd";
|
import { IMoneyValueProps, MoneyValue } from "@repo/rdx-ddd";
|
||||||
|
|
||||||
export class InvoiceItemSubtotalPrice extends MoneyValue {
|
export class CustomerInvoiceItemSubtotalPrice extends MoneyValue {
|
||||||
public static DEFAULT_SCALE = 4;
|
public static DEFAULT_SCALE = 4;
|
||||||
|
|
||||||
static create({ amount, currency_code, scale }: IMoneyValueProps) {
|
static create({ amount, currency_code, scale }: IMoneyValueProps) {
|
||||||
@ -1,6 +1,6 @@
|
|||||||
import { IMoneyValueProps, MoneyValue } from "@repo/rdx-ddd";
|
import { IMoneyValueProps, MoneyValue } from "@repo/rdx-ddd";
|
||||||
|
|
||||||
export class InvoiceItemTotalPrice extends MoneyValue {
|
export class CustomerInvoiceItemTotalPrice extends MoneyValue {
|
||||||
public static DEFAULT_SCALE = 4;
|
public static DEFAULT_SCALE = 4;
|
||||||
|
|
||||||
static create({ amount, currency_code, scale }: IMoneyValueProps) {
|
static create({ amount, currency_code, scale }: IMoneyValueProps) {
|
||||||
@ -1,6 +1,6 @@
|
|||||||
import { IMoneyValueProps, MoneyValue } from "@repo/rdx-ddd";
|
import { IMoneyValueProps, MoneyValue } from "@repo/rdx-ddd";
|
||||||
|
|
||||||
export class InvoiceItemUnitPrice extends MoneyValue {
|
export class CustomerInvoiceItemUnitPrice extends MoneyValue {
|
||||||
public static DEFAULT_SCALE = 4;
|
public static DEFAULT_SCALE = 4;
|
||||||
|
|
||||||
static create({ amount, currency_code, scale }: IMoneyValueProps) {
|
static create({ amount, currency_code, scale }: IMoneyValueProps) {
|
||||||
@ -2,30 +2,30 @@ import { ValueObject } from "@repo/rdx-ddd";
|
|||||||
import { Result } from "@repo/rdx-utils";
|
import { Result } from "@repo/rdx-utils";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
|
||||||
interface IInvoiceNumberProps {
|
interface ICustomerInvoiceNumberProps {
|
||||||
value: string;
|
value: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class InvoiceNumber extends ValueObject<IInvoiceNumberProps> {
|
export class CustomerInvoiceNumber extends ValueObject<ICustomerInvoiceNumberProps> {
|
||||||
private static readonly MAX_LENGTH = 255;
|
private static readonly MAX_LENGTH = 255;
|
||||||
|
|
||||||
protected static validate(value: string) {
|
protected static validate(value: string) {
|
||||||
const schema = z
|
const schema = z
|
||||||
.string()
|
.string()
|
||||||
.trim()
|
.trim()
|
||||||
.max(InvoiceNumber.MAX_LENGTH, {
|
.max(CustomerInvoiceNumber.MAX_LENGTH, {
|
||||||
message: `Name must be at most ${InvoiceNumber.MAX_LENGTH} characters long`,
|
message: `Name must be at most ${CustomerInvoiceNumber.MAX_LENGTH} characters long`,
|
||||||
});
|
});
|
||||||
return schema.safeParse(value);
|
return schema.safeParse(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
static create(value: string) {
|
static create(value: string) {
|
||||||
const valueIsValid = InvoiceNumber.validate(value);
|
const valueIsValid = CustomerInvoiceNumber.validate(value);
|
||||||
|
|
||||||
if (!valueIsValid.success) {
|
if (!valueIsValid.success) {
|
||||||
return Result.fail(new Error(valueIsValid.error.errors[0].message));
|
return Result.fail(new Error(valueIsValid.error.errors[0].message));
|
||||||
}
|
}
|
||||||
return Result.ok(new InvoiceNumber({ value }));
|
return Result.ok(new CustomerInvoiceNumber({ value }));
|
||||||
}
|
}
|
||||||
|
|
||||||
getValue(): string {
|
getValue(): string {
|
||||||
@ -2,38 +2,38 @@ import { ValueObject } from "@repo/rdx-ddd";
|
|||||||
import { Maybe, Result } from "@repo/rdx-utils";
|
import { Maybe, Result } from "@repo/rdx-utils";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
|
||||||
interface IInvoiceSerieProps {
|
interface ICustomerInvoiceSerieProps {
|
||||||
value: string;
|
value: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class InvoiceSerie extends ValueObject<IInvoiceSerieProps> {
|
export class CustomerInvoiceSerie extends ValueObject<ICustomerInvoiceSerieProps> {
|
||||||
private static readonly MAX_LENGTH = 255;
|
private static readonly MAX_LENGTH = 255;
|
||||||
|
|
||||||
protected static validate(value: string) {
|
protected static validate(value: string) {
|
||||||
const schema = z
|
const schema = z
|
||||||
.string()
|
.string()
|
||||||
.trim()
|
.trim()
|
||||||
.max(InvoiceSerie.MAX_LENGTH, {
|
.max(CustomerInvoiceSerie.MAX_LENGTH, {
|
||||||
message: `Name must be at most ${InvoiceSerie.MAX_LENGTH} characters long`,
|
message: `Name must be at most ${CustomerInvoiceSerie.MAX_LENGTH} characters long`,
|
||||||
});
|
});
|
||||||
return schema.safeParse(value);
|
return schema.safeParse(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
static create(value: string) {
|
static create(value: string) {
|
||||||
const valueIsValid = InvoiceSerie.validate(value);
|
const valueIsValid = CustomerInvoiceSerie.validate(value);
|
||||||
|
|
||||||
if (!valueIsValid.success) {
|
if (!valueIsValid.success) {
|
||||||
return Result.fail(new Error(valueIsValid.error.errors[0].message));
|
return Result.fail(new Error(valueIsValid.error.errors[0].message));
|
||||||
}
|
}
|
||||||
return Result.ok(new InvoiceSerie({ value }));
|
return Result.ok(new CustomerInvoiceSerie({ value }));
|
||||||
}
|
}
|
||||||
|
|
||||||
static createNullable(value?: string): Result<Maybe<InvoiceSerie>, Error> {
|
static createNullable(value?: string): Result<Maybe<CustomerInvoiceSerie>, Error> {
|
||||||
if (!value || value.trim() === "") {
|
if (!value || value.trim() === "") {
|
||||||
return Result.ok(Maybe.none<InvoiceSerie>());
|
return Result.ok(Maybe.none<CustomerInvoiceSerie>());
|
||||||
}
|
}
|
||||||
|
|
||||||
return InvoiceSerie.create(value).map((value) => Maybe.some(value));
|
return CustomerInvoiceSerie.create(value).map((value) => Maybe.some(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
getValue(): string {
|
getValue(): string {
|
||||||
@ -1,7 +1,7 @@
|
|||||||
import { ValueObject } from "@repo/rdx-ddd";
|
import { ValueObject } from "@repo/rdx-ddd";
|
||||||
import { Result } from "@repo/rdx-utils";
|
import { Result } from "@repo/rdx-utils";
|
||||||
|
|
||||||
interface IInvoiceStatusProps {
|
interface ICustomerInvoiceStatusProps {
|
||||||
value: string;
|
value: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -11,7 +11,7 @@ export enum INVOICE_STATUS {
|
|||||||
SENT = "sent",
|
SENT = "sent",
|
||||||
REJECTED = "rejected",
|
REJECTED = "rejected",
|
||||||
}
|
}
|
||||||
export class InvoiceStatus extends ValueObject<IInvoiceStatusProps> {
|
export class CustomerInvoiceStatus extends ValueObject<ICustomerInvoiceStatusProps> {
|
||||||
private static readonly ALLOWED_STATUSES = ["draft", "emitted", "sent", "rejected"];
|
private static readonly ALLOWED_STATUSES = ["draft", "emitted", "sent", "rejected"];
|
||||||
|
|
||||||
private static readonly TRANSITIONS: Record<string, string[]> = {
|
private static readonly TRANSITIONS: Record<string, string[]> = {
|
||||||
@ -21,36 +21,36 @@ export class InvoiceStatus extends ValueObject<IInvoiceStatusProps> {
|
|||||||
rejected: [],
|
rejected: [],
|
||||||
};
|
};
|
||||||
|
|
||||||
static create(value: string): Result<InvoiceStatus, Error> {
|
static create(value: string): Result<CustomerInvoiceStatus, Error> {
|
||||||
if (!InvoiceStatus.ALLOWED_STATUSES.includes(value)) {
|
if (!CustomerInvoiceStatus.ALLOWED_STATUSES.includes(value)) {
|
||||||
return Result.fail(new Error(`Estado de la factura no válido: ${value}`));
|
return Result.fail(new Error(`Estado de la factura no válido: ${value}`));
|
||||||
}
|
}
|
||||||
|
|
||||||
return Result.ok(
|
return Result.ok(
|
||||||
value === "rejected"
|
value === "rejected"
|
||||||
? InvoiceStatus.createRejected()
|
? CustomerInvoiceStatus.createRejected()
|
||||||
: value === "sent"
|
: value === "sent"
|
||||||
? InvoiceStatus.createSent()
|
? CustomerInvoiceStatus.createSent()
|
||||||
: value === "emitted"
|
: value === "emitted"
|
||||||
? InvoiceStatus.createSent()
|
? CustomerInvoiceStatus.createSent()
|
||||||
: InvoiceStatus.createDraft()
|
: CustomerInvoiceStatus.createDraft()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static createDraft(): InvoiceStatus {
|
public static createDraft(): CustomerInvoiceStatus {
|
||||||
return new InvoiceStatus({ value: INVOICE_STATUS.DRAFT });
|
return new CustomerInvoiceStatus({ value: INVOICE_STATUS.DRAFT });
|
||||||
}
|
}
|
||||||
|
|
||||||
public static createEmitted(): InvoiceStatus {
|
public static createEmitted(): CustomerInvoiceStatus {
|
||||||
return new InvoiceStatus({ value: INVOICE_STATUS.EMITTED });
|
return new CustomerInvoiceStatus({ value: INVOICE_STATUS.EMITTED });
|
||||||
}
|
}
|
||||||
|
|
||||||
public static createSent(): InvoiceStatus {
|
public static createSent(): CustomerInvoiceStatus {
|
||||||
return new InvoiceStatus({ value: INVOICE_STATUS.SENT });
|
return new CustomerInvoiceStatus({ value: INVOICE_STATUS.SENT });
|
||||||
}
|
}
|
||||||
|
|
||||||
public static createRejected(): InvoiceStatus {
|
public static createRejected(): CustomerInvoiceStatus {
|
||||||
return new InvoiceStatus({ value: INVOICE_STATUS.REJECTED });
|
return new CustomerInvoiceStatus({ value: INVOICE_STATUS.REJECTED });
|
||||||
}
|
}
|
||||||
|
|
||||||
getValue(): string {
|
getValue(): string {
|
||||||
@ -62,16 +62,16 @@ export class InvoiceStatus extends ValueObject<IInvoiceStatusProps> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
canTransitionTo(nextStatus: string): boolean {
|
canTransitionTo(nextStatus: string): boolean {
|
||||||
return InvoiceStatus.TRANSITIONS[this.props.value].includes(nextStatus);
|
return CustomerInvoiceStatus.TRANSITIONS[this.props.value].includes(nextStatus);
|
||||||
}
|
}
|
||||||
|
|
||||||
transitionTo(nextStatus: string): Result<InvoiceStatus, Error> {
|
transitionTo(nextStatus: string): Result<CustomerInvoiceStatus, Error> {
|
||||||
if (!this.canTransitionTo(nextStatus)) {
|
if (!this.canTransitionTo(nextStatus)) {
|
||||||
return Result.fail(
|
return Result.fail(
|
||||||
new Error(`Transición no permitida de ${this.props.value} a ${nextStatus}`)
|
new Error(`Transición no permitida de ${this.props.value} a ${nextStatus}`)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return InvoiceStatus.create(nextStatus);
|
return CustomerInvoiceStatus.create(nextStatus);
|
||||||
}
|
}
|
||||||
|
|
||||||
toString(): string {
|
toString(): string {
|
||||||
@ -0,0 +1,10 @@
|
|||||||
|
export * from "./customerCustomerInvoice-address-type";
|
||||||
|
export * from "./customerCustomerInvoice-item-description";
|
||||||
|
export * from "./customerCustomerInvoice-item-discount";
|
||||||
|
export * from "./customerCustomerInvoice-item-quantity";
|
||||||
|
export * from "./customerCustomerInvoice-item-subtotal-price";
|
||||||
|
export * from "./customerCustomerInvoice-item-total-price";
|
||||||
|
export * from "./customerCustomerInvoice-item-unit-price";
|
||||||
|
export * from "./customerCustomerInvoice-number";
|
||||||
|
export * from "./customerCustomerInvoice-serie";
|
||||||
|
export * from "./customerCustomerInvoice-status";
|
||||||
26
modules/customer-invoices/src/api/index.ts
Normal file
26
modules/customer-invoices/src/api/index.ts
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
import { IModuleServer, ModuleParams } from "@erp/core/api";
|
||||||
|
import { customerCustomerInvoicesRouter, models } from "./infrastructure";
|
||||||
|
|
||||||
|
export const customerCustomerInvoicesAPIModule: IModuleServer = {
|
||||||
|
name: "customerCustomerInvoices",
|
||||||
|
version: "1.0.0",
|
||||||
|
dependencies: [],
|
||||||
|
|
||||||
|
init(params: ModuleParams) {
|
||||||
|
// const contacts = getService<ContactsService>("contacts");
|
||||||
|
const { logger } = params;
|
||||||
|
customerCustomerInvoicesRouter(params);
|
||||||
|
logger.info("🚀 CustomerInvoices module initialized", { label: "customerCustomerInvoices" });
|
||||||
|
},
|
||||||
|
registerDependencies(params) {
|
||||||
|
const { database, logger } = params;
|
||||||
|
logger.info("🚀 CustomerInvoices module dependencies registered", { label: "customerCustomerInvoices" });
|
||||||
|
return {
|
||||||
|
models,
|
||||||
|
services: {
|
||||||
|
getCustomerInvoice: () => {},
|
||||||
|
/*...*/
|
||||||
|
},
|
||||||
|
};
|
||||||
|
},
|
||||||
|
};
|
||||||
@ -1,9 +1,9 @@
|
|||||||
import { ModuleParams } from "@erp/core/api";
|
import { ModuleParams } from "@erp/core/api";
|
||||||
import { Application, NextFunction, Request, Response, Router } from "express";
|
import { Application, NextFunction, Request, Response, Router } from "express";
|
||||||
import { Sequelize } from "sequelize";
|
import { Sequelize } from "sequelize";
|
||||||
import { buildListInvoicesController } from "../../presentation";
|
import { buildListCustomerInvoicesController } from "../../presentation";
|
||||||
|
|
||||||
export const invoicesRouter = (params: ModuleParams) => {
|
export const customerCustomerInvoicesRouter = (params: ModuleParams) => {
|
||||||
const { app, database, baseRoutePath } = params as {
|
const { app, database, baseRoutePath } = params as {
|
||||||
app: Application;
|
app: Application;
|
||||||
database: Sequelize;
|
database: Sequelize;
|
||||||
@ -17,48 +17,48 @@ export const invoicesRouter = (params: ModuleParams) => {
|
|||||||
//checkTabContext,
|
//checkTabContext,
|
||||||
//checkUser,
|
//checkUser,
|
||||||
(req: Request, res: Response, next: NextFunction) => {
|
(req: Request, res: Response, next: NextFunction) => {
|
||||||
buildListInvoicesController(database).execute(req, res, next);
|
buildListCustomerInvoicesController(database).execute(req, res, next);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
app.use(`${baseRoutePath}/invoices`, routes);
|
app.use(`${baseRoutePath}/customerCustomerInvoices`, routes);
|
||||||
|
|
||||||
/*routes.get(
|
/*routes.get(
|
||||||
"/:invoiceId",
|
"/:customerCustomerInvoiceId",
|
||||||
//checkTabContext,
|
//checkTabContext,
|
||||||
//checkUser,
|
//checkUser,
|
||||||
(req: Request, res: Response, next: NextFunction) => {
|
(req: Request, res: Response, next: NextFunction) => {
|
||||||
buildGetInvoiceController(database).execute(req, res, next);
|
buildGetCustomerInvoiceController(database).execute(req, res, next);
|
||||||
}
|
}
|
||||||
);*/
|
);*/
|
||||||
|
|
||||||
/*routes.post(
|
/*routes.post(
|
||||||
"/",
|
"/",
|
||||||
validateAndParseBody(ICreateInvoiceRequestSchema, { sanitize: false }),
|
validateAndParseBody(ICreateCustomerInvoiceRequestSchema, { sanitize: false }),
|
||||||
//checkTabContext,
|
//checkTabContext,
|
||||||
//checkUser,
|
//checkUser,
|
||||||
(req: Request, res: Response, next: NextFunction) => {
|
(req: Request, res: Response, next: NextFunction) => {
|
||||||
buildCreateInvoiceController(database).execute(req, res, next);
|
buildCreateCustomerInvoiceController(database).execute(req, res, next);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
routes.put(
|
routes.put(
|
||||||
"/:invoiceId",
|
"/:customerCustomerInvoiceId",
|
||||||
validateAndParseBody(IUpdateInvoiceRequestSchema),
|
validateAndParseBody(IUpdateCustomerInvoiceRequestSchema),
|
||||||
checkTabContext,
|
checkTabContext,
|
||||||
//checkUser,
|
//checkUser,
|
||||||
(req: Request, res: Response, next: NextFunction) => {
|
(req: Request, res: Response, next: NextFunction) => {
|
||||||
buildUpdateInvoiceController().execute(req, res, next);
|
buildUpdateCustomerInvoiceController().execute(req, res, next);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
routes.delete(
|
routes.delete(
|
||||||
"/:invoiceId",
|
"/:customerCustomerInvoiceId",
|
||||||
validateAndParseBody(IDeleteInvoiceRequestSchema),
|
validateAndParseBody(IDeleteCustomerInvoiceRequestSchema),
|
||||||
checkTabContext,
|
checkTabContext,
|
||||||
//checkUser,
|
//checkUser,
|
||||||
(req: Request, res: Response, next: NextFunction) => {
|
(req: Request, res: Response, next: NextFunction) => {
|
||||||
buildDeleteInvoiceController().execute(req, res, next);
|
buildDeleteCustomerInvoiceController().execute(req, res, next);
|
||||||
}
|
}
|
||||||
);*/
|
);*/
|
||||||
};
|
};
|
||||||
@ -0,0 +1 @@
|
|||||||
|
export * from "./customerInvoices.routes";
|
||||||
@ -3,27 +3,27 @@ import { UniqueID } from "@repo/rdx-ddd";
|
|||||||
import { Result } from "@repo/rdx-utils";
|
import { Result } from "@repo/rdx-utils";
|
||||||
import { InferCreationAttributes } from "sequelize";
|
import { InferCreationAttributes } from "sequelize";
|
||||||
import {
|
import {
|
||||||
Invoice,
|
CustomerInvoice,
|
||||||
InvoiceItem,
|
CustomerInvoiceItem,
|
||||||
InvoiceItemDescription,
|
CustomerInvoiceItemDescription,
|
||||||
InvoiceItemDiscount,
|
CustomerInvoiceItemDiscount,
|
||||||
InvoiceItemQuantity,
|
CustomerInvoiceItemQuantity,
|
||||||
InvoiceItemUnitPrice,
|
CustomerInvoiceItemUnitPrice,
|
||||||
} from "../../domain";
|
} from "../../domain";
|
||||||
import { InvoiceItemCreationAttributes, InvoiceItemModel, InvoiceModel } from "../sequelize";
|
import { CustomerInvoiceItemCreationAttributes, CustomerInvoiceItemModel, CustomerInvoiceModel } from "../sequelize";
|
||||||
|
|
||||||
export interface IInvoiceItemMapper
|
export interface ICustomerInvoiceItemMapper
|
||||||
extends ISequelizeMapper<InvoiceItemModel, InvoiceItemCreationAttributes, InvoiceItem> {}
|
extends ISequelizeMapper<CustomerInvoiceItemModel, CustomerInvoiceItemCreationAttributes, CustomerInvoiceItem> {}
|
||||||
|
|
||||||
export class InvoiceItemMapper
|
export class CustomerInvoiceItemMapper
|
||||||
extends SequelizeMapper<InvoiceItemModel, InvoiceItemCreationAttributes, InvoiceItem>
|
extends SequelizeMapper<CustomerInvoiceItemModel, CustomerInvoiceItemCreationAttributes, CustomerInvoiceItem>
|
||||||
implements IInvoiceItemMapper
|
implements ICustomerInvoiceItemMapper
|
||||||
{
|
{
|
||||||
public mapToDomain(
|
public mapToDomain(
|
||||||
source: InvoiceItemModel,
|
source: CustomerInvoiceItemModel,
|
||||||
params?: MapperParamsType
|
params?: MapperParamsType
|
||||||
): Result<InvoiceItem, Error> {
|
): Result<CustomerInvoiceItem, Error> {
|
||||||
const { sourceParent } = params as { sourceParent: InvoiceModel };
|
const { sourceParent } = params as { sourceParent: CustomerInvoiceModel };
|
||||||
|
|
||||||
// Validación y creación de ID único
|
// Validación y creación de ID único
|
||||||
const idOrError = UniqueID.create(source.item_id);
|
const idOrError = UniqueID.create(source.item_id);
|
||||||
@ -32,13 +32,13 @@ export class InvoiceItemMapper
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Validación y creación de descripción
|
// Validación y creación de descripción
|
||||||
const descriptionOrError = InvoiceItemDescription.create(source.description || "");
|
const descriptionOrError = CustomerInvoiceItemDescription.create(source.description || "");
|
||||||
if (descriptionOrError.isFailure) {
|
if (descriptionOrError.isFailure) {
|
||||||
return Result.fail(descriptionOrError.error);
|
return Result.fail(descriptionOrError.error);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validación y creación de cantidad
|
// Validación y creación de cantidad
|
||||||
const quantityOrError = InvoiceItemQuantity.create({
|
const quantityOrError = CustomerInvoiceItemQuantity.create({
|
||||||
amount: source.quantity_amount,
|
amount: source.quantity_amount,
|
||||||
scale: source.quantity_scale,
|
scale: source.quantity_scale,
|
||||||
});
|
});
|
||||||
@ -47,17 +47,17 @@ export class InvoiceItemMapper
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Validación y creación de precio unitario
|
// Validación y creación de precio unitario
|
||||||
const unitPriceOrError = InvoiceItemUnitPrice.create({
|
const unitPriceOrError = CustomerInvoiceItemUnitPrice.create({
|
||||||
amount: source.unit_price_amount,
|
amount: source.unit_price_amount,
|
||||||
scale: source.unit_price_scale,
|
scale: source.unit_price_scale,
|
||||||
currency_code: sourceParent.invoice_currency,
|
currency_code: sourceParent.customerCustomerInvoice_currency,
|
||||||
});
|
});
|
||||||
if (unitPriceOrError.isFailure) {
|
if (unitPriceOrError.isFailure) {
|
||||||
return Result.fail(unitPriceOrError.error);
|
return Result.fail(unitPriceOrError.error);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validación y creación de descuento
|
// Validación y creación de descuento
|
||||||
const discountOrError = InvoiceItemDiscount.create({
|
const discountOrError = CustomerInvoiceItemDiscount.create({
|
||||||
amount: source.discount_amount || 0,
|
amount: source.discount_amount || 0,
|
||||||
scale: source.discount_scale || 0,
|
scale: source.discount_scale || 0,
|
||||||
});
|
});
|
||||||
@ -79,7 +79,7 @@ export class InvoiceItemMapper
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Creación del objeto de dominio
|
// Creación del objeto de dominio
|
||||||
return InvoiceItem.create(
|
return CustomerInvoiceItem.create(
|
||||||
{
|
{
|
||||||
description: descriptionOrError.data,
|
description: descriptionOrError.data,
|
||||||
quantity: quantityOrError.data,
|
quantity: quantityOrError.data,
|
||||||
@ -91,17 +91,17 @@ export class InvoiceItemMapper
|
|||||||
}
|
}
|
||||||
|
|
||||||
public mapToPersistence(
|
public mapToPersistence(
|
||||||
source: InvoiceItem,
|
source: CustomerInvoiceItem,
|
||||||
params?: MapperParamsType
|
params?: MapperParamsType
|
||||||
): InferCreationAttributes<InvoiceItemModel, {}> {
|
): InferCreationAttributes<CustomerInvoiceItemModel, {}> {
|
||||||
const { index, sourceParent } = params as {
|
const { index, sourceParent } = params as {
|
||||||
index: number;
|
index: number;
|
||||||
sourceParent: Invoice;
|
sourceParent: CustomerInvoice;
|
||||||
};
|
};
|
||||||
|
|
||||||
const lineData = {
|
const lineData = {
|
||||||
parent_id: undefined,
|
parent_id: undefined,
|
||||||
invoice_id: sourceParent.id.toPrimitive(),
|
customerCustomerInvoice_id: sourceParent.id.toPrimitive(),
|
||||||
item_type: "simple",
|
item_type: "simple",
|
||||||
position: index,
|
position: index,
|
||||||
|
|
||||||
@ -0,0 +1,97 @@
|
|||||||
|
import { ISequelizeMapper, MapperParamsType, SequelizeMapper } from "@erp/core/api";
|
||||||
|
import { UniqueID, UtcDate } from "@repo/rdx-ddd";
|
||||||
|
import { Result } from "@repo/rdx-utils";
|
||||||
|
import { CustomerInvoice, CustomerInvoiceNumber, CustomerInvoiceSerie, CustomerInvoiceStatus } from "../../domain";
|
||||||
|
import { CustomerInvoiceCreationAttributes, CustomerInvoiceModel } from "../sequelize";
|
||||||
|
import { CustomerInvoiceItemMapper } from "./customerCustomerInvoice-item.mapper";
|
||||||
|
|
||||||
|
export interface ICustomerInvoiceMapper
|
||||||
|
extends ISequelizeMapper<CustomerInvoiceModel, CustomerInvoiceCreationAttributes, CustomerInvoice> {}
|
||||||
|
|
||||||
|
export class CustomerInvoiceMapper
|
||||||
|
extends SequelizeMapper<CustomerInvoiceModel, CustomerInvoiceCreationAttributes, CustomerInvoice>
|
||||||
|
implements ICustomerInvoiceMapper
|
||||||
|
{
|
||||||
|
private customerCustomerInvoiceItemMapper: CustomerInvoiceItemMapper;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
this.customerCustomerInvoiceItemMapper = new CustomerInvoiceItemMapper(); // Instanciar el mapper de items
|
||||||
|
}
|
||||||
|
|
||||||
|
public mapToDomain(source: CustomerInvoiceModel, params?: MapperParamsType): Result<CustomerInvoice, Error> {
|
||||||
|
const idOrError = UniqueID.create(source.id);
|
||||||
|
const statusOrError = CustomerInvoiceStatus.create(source.customerCustomerInvoice_status);
|
||||||
|
const customerCustomerInvoiceSeriesOrError = CustomerInvoiceSerie.create(source.customerCustomerInvoice_series);
|
||||||
|
const customerCustomerInvoiceNumberOrError = CustomerInvoiceNumber.create(source.customerCustomerInvoice_number);
|
||||||
|
const issueDateOrError = UtcDate.create(source.issue_date);
|
||||||
|
const operationDateOrError = UtcDate.create(source.operation_date);
|
||||||
|
|
||||||
|
const result = Result.combine([
|
||||||
|
idOrError,
|
||||||
|
statusOrError,
|
||||||
|
customerCustomerInvoiceSeriesOrError,
|
||||||
|
customerCustomerInvoiceNumberOrError,
|
||||||
|
issueDateOrError,
|
||||||
|
operationDateOrError,
|
||||||
|
]);
|
||||||
|
|
||||||
|
if (result.isFailure) {
|
||||||
|
return Result.fail(result.error);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mapear los items de la factura
|
||||||
|
const itemsOrErrors = this.customerCustomerInvoiceItemMapper.mapArrayToDomain(source.items, {
|
||||||
|
sourceParent: source,
|
||||||
|
...params,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (itemsOrErrors.isFailure) {
|
||||||
|
return Result.fail(itemsOrErrors.error);
|
||||||
|
}
|
||||||
|
|
||||||
|
const customerCustomerInvoiceCurrency = source.customerCustomerInvoice_currency || "EUR";
|
||||||
|
|
||||||
|
return CustomerInvoice.create(
|
||||||
|
{
|
||||||
|
status: statusOrError.data,
|
||||||
|
customerCustomerInvoiceSeries: customerCustomerInvoiceSeriesOrError.data,
|
||||||
|
customerCustomerInvoiceNumber: customerCustomerInvoiceNumberOrError.data,
|
||||||
|
issueDate: issueDateOrError.data,
|
||||||
|
operationDate: operationDateOrError.data,
|
||||||
|
customerCustomerInvoiceCurrency,
|
||||||
|
items: itemsOrErrors.data,
|
||||||
|
},
|
||||||
|
idOrError.data
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public mapToPersistence(source: CustomerInvoice, params?: MapperParamsType): CustomerInvoiceCreationAttributes {
|
||||||
|
const subtotal = source.calculateSubtotal();
|
||||||
|
const total = source.calculateTotal();
|
||||||
|
|
||||||
|
const items = this.customerCustomerInvoiceItemMapper.mapCollectionToPersistence(source.items, params);
|
||||||
|
|
||||||
|
return {
|
||||||
|
id: source.id.toString(),
|
||||||
|
customerCustomerInvoice_status: source.status.toPrimitive(),
|
||||||
|
customerCustomerInvoice_series: source.customerCustomerInvoiceSeries.toPrimitive(),
|
||||||
|
customerCustomerInvoice_number: source.customerCustomerInvoiceNumber.toPrimitive(),
|
||||||
|
issue_date: source.issueDate.toPrimitive(),
|
||||||
|
operation_date: source.operationDate.toPrimitive(),
|
||||||
|
customerCustomerInvoice_language: "es",
|
||||||
|
customerCustomerInvoice_currency: source.customerCustomerInvoiceCurrency || "EUR",
|
||||||
|
|
||||||
|
subtotal_amount: subtotal.amount,
|
||||||
|
subtotal_scale: subtotal.scale,
|
||||||
|
|
||||||
|
total_amount: total.amount,
|
||||||
|
total_scale: total.scale,
|
||||||
|
|
||||||
|
items,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const customerCustomerInvoiceMapper: CustomerInvoiceMapper = new CustomerInvoiceMapper();
|
||||||
|
export { customerCustomerInvoiceMapper };
|
||||||
@ -1,50 +1,50 @@
|
|||||||
import { ISequelizeMapper, SequelizeMapper } from "@/contexts/common/infrastructure";
|
import { ISequelizeMapper, SequelizeMapper } from "@/contexts/common/infrastructure";
|
||||||
import { Name, TINNumber, UniqueID } from "@shared/contexts";
|
import { Name, TINNumber, UniqueID } from "@shared/contexts";
|
||||||
import {
|
import {
|
||||||
IInvoiceCustomerProps,
|
ICustomerInvoiceCustomerProps,
|
||||||
Invoice,
|
CustomerInvoice,
|
||||||
InvoiceCustomer,
|
CustomerInvoiceCustomer,
|
||||||
InvoiceParticipantBillingAddress,
|
CustomerInvoiceParticipantBillingAddress,
|
||||||
InvoiceParticipantShippingAddress,
|
CustomerInvoiceParticipantShippingAddress,
|
||||||
} from "../../domain";
|
} from "../../domain";
|
||||||
import { IInvoicingContext } from "../InvoicingContext";
|
import { IInvoicingContext } from "../InvoicingContext";
|
||||||
import { InvoiceParticipant_Model, TCreationInvoiceParticipant_Model } from "../sequelize";
|
import { CustomerInvoiceParticipant_Model, TCreationCustomerInvoiceParticipant_Model } from "../sequelize";
|
||||||
import {
|
import {
|
||||||
IInvoiceParticipantAddressMapper,
|
ICustomerInvoiceParticipantAddressMapper,
|
||||||
createInvoiceParticipantAddressMapper,
|
createCustomerInvoiceParticipantAddressMapper,
|
||||||
} from "./invoiceParticipantAddress.mapper";
|
} from "./customerCustomerInvoiceParticipantAddress.mapper";
|
||||||
|
|
||||||
export interface IInvoiceParticipantMapper
|
export interface ICustomerInvoiceParticipantMapper
|
||||||
extends ISequelizeMapper<
|
extends ISequelizeMapper<
|
||||||
InvoiceParticipant_Model,
|
CustomerInvoiceParticipant_Model,
|
||||||
TCreationInvoiceParticipant_Model,
|
TCreationCustomerInvoiceParticipant_Model,
|
||||||
InvoiceCustomer
|
CustomerInvoiceCustomer
|
||||||
> {}
|
> {}
|
||||||
|
|
||||||
export const createInvoiceParticipantMapper = (
|
export const createCustomerInvoiceParticipantMapper = (
|
||||||
context: IInvoicingContext
|
context: IInvoicingContext
|
||||||
): IInvoiceParticipantMapper =>
|
): ICustomerInvoiceParticipantMapper =>
|
||||||
new InvoiceParticipantMapper({
|
new CustomerInvoiceParticipantMapper({
|
||||||
context,
|
context,
|
||||||
addressMapper: createInvoiceParticipantAddressMapper(context),
|
addressMapper: createCustomerInvoiceParticipantAddressMapper(context),
|
||||||
});
|
});
|
||||||
|
|
||||||
class InvoiceParticipantMapper
|
class CustomerInvoiceParticipantMapper
|
||||||
extends SequelizeMapper<
|
extends SequelizeMapper<
|
||||||
InvoiceParticipant_Model,
|
CustomerInvoiceParticipant_Model,
|
||||||
TCreationInvoiceParticipant_Model,
|
TCreationCustomerInvoiceParticipant_Model,
|
||||||
InvoiceCustomer
|
CustomerInvoiceCustomer
|
||||||
>
|
>
|
||||||
implements IInvoiceParticipantMapper
|
implements ICustomerInvoiceParticipantMapper
|
||||||
{
|
{
|
||||||
public constructor(props: {
|
public constructor(props: {
|
||||||
addressMapper: IInvoiceParticipantAddressMapper;
|
addressMapper: ICustomerInvoiceParticipantAddressMapper;
|
||||||
context: IInvoicingContext;
|
context: IInvoicingContext;
|
||||||
}) {
|
}) {
|
||||||
super(props);
|
super(props);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected toDomainMappingImpl(source: InvoiceParticipant_Model, params: any) {
|
protected toDomainMappingImpl(source: CustomerInvoiceParticipant_Model, params: any) {
|
||||||
/*if (!source.billingAddress) {
|
/*if (!source.billingAddress) {
|
||||||
this.handleRequiredFieldError(
|
this.handleRequiredFieldError(
|
||||||
"billingAddress",
|
"billingAddress",
|
||||||
@ -60,20 +60,20 @@ class InvoiceParticipantMapper
|
|||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
const billingAddress = source.billingAddress
|
const billingAddress = source.billingAddress
|
||||||
? ((this.props.addressMapper as IInvoiceParticipantAddressMapper).mapToDomain(
|
? ((this.props.addressMapper as ICustomerInvoiceParticipantAddressMapper).mapToDomain(
|
||||||
source.billingAddress,
|
source.billingAddress,
|
||||||
params
|
params
|
||||||
) as InvoiceParticipantBillingAddress)
|
) as CustomerInvoiceParticipantBillingAddress)
|
||||||
: undefined;
|
: undefined;
|
||||||
|
|
||||||
const shippingAddress = source.shippingAddress
|
const shippingAddress = source.shippingAddress
|
||||||
? ((this.props.addressMapper as IInvoiceParticipantAddressMapper).mapToDomain(
|
? ((this.props.addressMapper as ICustomerInvoiceParticipantAddressMapper).mapToDomain(
|
||||||
source.shippingAddress,
|
source.shippingAddress,
|
||||||
params
|
params
|
||||||
) as InvoiceParticipantShippingAddress)
|
) as CustomerInvoiceParticipantShippingAddress)
|
||||||
: undefined;
|
: undefined;
|
||||||
|
|
||||||
const props: IInvoiceCustomerProps = {
|
const props: ICustomerInvoiceCustomerProps = {
|
||||||
tin: this.mapsValue(source, "tin", TINNumber.create),
|
tin: this.mapsValue(source, "tin", TINNumber.create),
|
||||||
firstName: this.mapsValue(source, "first_name", Name.create),
|
firstName: this.mapsValue(source, "first_name", Name.create),
|
||||||
lastName: this.mapsValue(source, "last_name", Name.create),
|
lastName: this.mapsValue(source, "last_name", Name.create),
|
||||||
@ -83,7 +83,7 @@ class InvoiceParticipantMapper
|
|||||||
};
|
};
|
||||||
|
|
||||||
const id = this.mapsValue(source, "participant_id", UniqueID.create);
|
const id = this.mapsValue(source, "participant_id", UniqueID.create);
|
||||||
const participantOrError = InvoiceCustomer.create(props, id);
|
const participantOrError = CustomerInvoiceCustomer.create(props, id);
|
||||||
|
|
||||||
if (participantOrError.isFailure) {
|
if (participantOrError.isFailure) {
|
||||||
throw participantOrError.error;
|
throw participantOrError.error;
|
||||||
@ -93,13 +93,13 @@ class InvoiceParticipantMapper
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected toPersistenceMappingImpl(
|
protected toPersistenceMappingImpl(
|
||||||
source: InvoiceCustomer,
|
source: CustomerInvoiceCustomer,
|
||||||
params: { sourceParent: Invoice }
|
params: { sourceParent: CustomerInvoice }
|
||||||
): TCreationInvoiceParticipant_Model {
|
): TCreationCustomerInvoiceParticipant_Model {
|
||||||
const { sourceParent } = params;
|
const { sourceParent } = params;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
invoice_id: sourceParent.id.toPrimitive(),
|
customerCustomerInvoice_id: sourceParent.id.toPrimitive(),
|
||||||
|
|
||||||
participant_id: source.id.toPrimitive(),
|
participant_id: source.id.toPrimitive(),
|
||||||
tin: source.tin.toPrimitive(),
|
tin: source.tin.toPrimitive(),
|
||||||
@ -108,11 +108,11 @@ class InvoiceParticipantMapper
|
|||||||
company_name: source.companyName.toPrimitive(),
|
company_name: source.companyName.toPrimitive(),
|
||||||
|
|
||||||
billingAddress: (
|
billingAddress: (
|
||||||
this.props.addressMapper as IInvoiceParticipantAddressMapper
|
this.props.addressMapper as ICustomerInvoiceParticipantAddressMapper
|
||||||
).mapToPersistence(source.billingAddress!, { sourceParent: source }),
|
).mapToPersistence(source.billingAddress!, { sourceParent: source }),
|
||||||
|
|
||||||
shippingAddress: (
|
shippingAddress: (
|
||||||
this.props.addressMapper as IInvoiceParticipantAddressMapper
|
this.props.addressMapper as ICustomerInvoiceParticipantAddressMapper
|
||||||
).mapToPersistence(source.shippingAddress!, { sourceParent: source }),
|
).mapToPersistence(source.shippingAddress!, { sourceParent: source }),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -11,39 +11,39 @@ import {
|
|||||||
UniqueID,
|
UniqueID,
|
||||||
} from "@shared/contexts";
|
} from "@shared/contexts";
|
||||||
import {
|
import {
|
||||||
IInvoiceParticipantAddressProps,
|
ICustomerInvoiceParticipantAddressProps,
|
||||||
InvoiceCustomer,
|
CustomerInvoiceCustomer,
|
||||||
InvoiceParticipantAddress,
|
CustomerInvoiceParticipantAddress,
|
||||||
} from "../../domain";
|
} from "../../domain";
|
||||||
import { IInvoicingContext } from "../InvoicingContext";
|
import { IInvoicingContext } from "../InvoicingContext";
|
||||||
import {
|
import {
|
||||||
InvoiceParticipantAddress_Model,
|
CustomerInvoiceParticipantAddress_Model,
|
||||||
TCreationInvoiceParticipantAddress_Model,
|
TCreationCustomerInvoiceParticipantAddress_Model,
|
||||||
} from "../sequelize";
|
} from "../sequelize";
|
||||||
|
|
||||||
export interface IInvoiceParticipantAddressMapper
|
export interface ICustomerInvoiceParticipantAddressMapper
|
||||||
extends ISequelizeMapper<
|
extends ISequelizeMapper<
|
||||||
InvoiceParticipantAddress_Model,
|
CustomerInvoiceParticipantAddress_Model,
|
||||||
TCreationInvoiceParticipantAddress_Model,
|
TCreationCustomerInvoiceParticipantAddress_Model,
|
||||||
InvoiceParticipantAddress
|
CustomerInvoiceParticipantAddress
|
||||||
> {}
|
> {}
|
||||||
|
|
||||||
export const createInvoiceParticipantAddressMapper = (
|
export const createCustomerInvoiceParticipantAddressMapper = (
|
||||||
context: IInvoicingContext
|
context: IInvoicingContext
|
||||||
): IInvoiceParticipantAddressMapper => new InvoiceParticipantAddressMapper({ context });
|
): ICustomerInvoiceParticipantAddressMapper => new CustomerInvoiceParticipantAddressMapper({ context });
|
||||||
|
|
||||||
class InvoiceParticipantAddressMapper
|
class CustomerInvoiceParticipantAddressMapper
|
||||||
extends SequelizeMapper<
|
extends SequelizeMapper<
|
||||||
InvoiceParticipantAddress_Model,
|
CustomerInvoiceParticipantAddress_Model,
|
||||||
TCreationInvoiceParticipantAddress_Model,
|
TCreationCustomerInvoiceParticipantAddress_Model,
|
||||||
InvoiceParticipantAddress
|
CustomerInvoiceParticipantAddress
|
||||||
>
|
>
|
||||||
implements IInvoiceParticipantAddressMapper
|
implements ICustomerInvoiceParticipantAddressMapper
|
||||||
{
|
{
|
||||||
protected toDomainMappingImpl(source: InvoiceParticipantAddress_Model, params: any) {
|
protected toDomainMappingImpl(source: CustomerInvoiceParticipantAddress_Model, params: any) {
|
||||||
const id = this.mapsValue(source, "address_id", UniqueID.create);
|
const id = this.mapsValue(source, "address_id", UniqueID.create);
|
||||||
|
|
||||||
const props: IInvoiceParticipantAddressProps = {
|
const props: ICustomerInvoiceParticipantAddressProps = {
|
||||||
type: source.type,
|
type: source.type,
|
||||||
street: this.mapsValue(source, "street", Street.create),
|
street: this.mapsValue(source, "street", Street.create),
|
||||||
city: this.mapsValue(source, "city", City.create),
|
city: this.mapsValue(source, "city", City.create),
|
||||||
@ -55,7 +55,7 @@ class InvoiceParticipantAddressMapper
|
|||||||
notes: this.mapsValue(source, "notes", Note.create),
|
notes: this.mapsValue(source, "notes", Note.create),
|
||||||
};
|
};
|
||||||
|
|
||||||
const addressOrError = InvoiceParticipantAddress.create(props, id);
|
const addressOrError = CustomerInvoiceParticipantAddress.create(props, id);
|
||||||
|
|
||||||
if (addressOrError.isFailure) {
|
if (addressOrError.isFailure) {
|
||||||
throw addressOrError.error;
|
throw addressOrError.error;
|
||||||
@ -65,8 +65,8 @@ class InvoiceParticipantAddressMapper
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected toPersistenceMappingImpl(
|
protected toPersistenceMappingImpl(
|
||||||
source: InvoiceParticipantAddress,
|
source: CustomerInvoiceParticipantAddress,
|
||||||
params: { sourceParent: InvoiceCustomer }
|
params: { sourceParent: CustomerInvoiceCustomer }
|
||||||
) {
|
) {
|
||||||
const { sourceParent } = params;
|
const { sourceParent } = params;
|
||||||
|
|
||||||
@ -0,0 +1 @@
|
|||||||
|
export * from "./customerCustomerInvoice.mapper";
|
||||||
@ -7,19 +7,19 @@ import {
|
|||||||
NonAttribute,
|
NonAttribute,
|
||||||
Sequelize,
|
Sequelize,
|
||||||
} from "sequelize";
|
} from "sequelize";
|
||||||
import { InvoiceModel } from "./invoice.model";
|
import { CustomerInvoiceModel } from "./customerCustomerInvoice.model";
|
||||||
|
|
||||||
export type InvoiceItemCreationAttributes = InferCreationAttributes<
|
export type CustomerInvoiceItemCreationAttributes = InferCreationAttributes<
|
||||||
InvoiceItemModel,
|
CustomerInvoiceItemModel,
|
||||||
{ omit: "invoice" }
|
{ omit: "customerCustomerInvoice" }
|
||||||
>;
|
>;
|
||||||
|
|
||||||
export class InvoiceItemModel extends Model<
|
export class CustomerInvoiceItemModel extends Model<
|
||||||
InferAttributes<InvoiceItemModel>,
|
InferAttributes<CustomerInvoiceItemModel>,
|
||||||
InferCreationAttributes<InvoiceItemModel, { omit: "invoice" }>
|
InferCreationAttributes<CustomerInvoiceItemModel, { omit: "customerCustomerInvoice" }>
|
||||||
> {
|
> {
|
||||||
declare item_id: string;
|
declare item_id: string;
|
||||||
declare invoice_id: string;
|
declare customerCustomerInvoice_id: string;
|
||||||
|
|
||||||
declare parent_id: CreationOptional<string>;
|
declare parent_id: CreationOptional<string>;
|
||||||
declare position: number;
|
declare position: number;
|
||||||
@ -42,27 +42,27 @@ export class InvoiceItemModel extends Model<
|
|||||||
declare total_amount: CreationOptional<number>;
|
declare total_amount: CreationOptional<number>;
|
||||||
declare total_scale: CreationOptional<number>;
|
declare total_scale: CreationOptional<number>;
|
||||||
|
|
||||||
declare invoice: NonAttribute<InvoiceModel>;
|
declare customerCustomerInvoice: NonAttribute<CustomerInvoiceModel>;
|
||||||
|
|
||||||
static associate(database: Sequelize) {
|
static associate(database: Sequelize) {
|
||||||
/*const { Invoice_Model, InvoiceItem_Model } = connection.models;
|
/*const { CustomerInvoice_Model, CustomerInvoiceItem_Model } = connection.models;
|
||||||
|
|
||||||
InvoiceItem_Model.belongsTo(Invoice_Model, {
|
CustomerInvoiceItem_Model.belongsTo(CustomerInvoice_Model, {
|
||||||
as: "invoice",
|
as: "customerCustomerInvoice",
|
||||||
foreignKey: "invoice_id",
|
foreignKey: "customerCustomerInvoice_id",
|
||||||
onDelete: "CASCADE",
|
onDelete: "CASCADE",
|
||||||
});*/
|
});*/
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default (database: Sequelize) => {
|
export default (database: Sequelize) => {
|
||||||
InvoiceItemModel.init(
|
CustomerInvoiceItemModel.init(
|
||||||
{
|
{
|
||||||
item_id: {
|
item_id: {
|
||||||
type: new DataTypes.UUID(),
|
type: new DataTypes.UUID(),
|
||||||
primaryKey: true,
|
primaryKey: true,
|
||||||
},
|
},
|
||||||
invoice_id: {
|
customerCustomerInvoice_id: {
|
||||||
type: new DataTypes.UUID(),
|
type: new DataTypes.UUID(),
|
||||||
primaryKey: true,
|
primaryKey: true,
|
||||||
},
|
},
|
||||||
@ -159,7 +159,7 @@ export default (database: Sequelize) => {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
sequelize: database,
|
sequelize: database,
|
||||||
tableName: "invoice_items",
|
tableName: "customerCustomerInvoice_items",
|
||||||
|
|
||||||
defaultScope: {},
|
defaultScope: {},
|
||||||
|
|
||||||
@ -167,5 +167,5 @@ export default (database: Sequelize) => {
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
return InvoiceItemModel;
|
return CustomerInvoiceItemModel;
|
||||||
};
|
};
|
||||||
@ -7,25 +7,25 @@ import {
|
|||||||
NonAttribute,
|
NonAttribute,
|
||||||
Sequelize,
|
Sequelize,
|
||||||
} from "sequelize";
|
} from "sequelize";
|
||||||
import { InvoiceItemCreationAttributes, InvoiceItemModel } from "./invoice-item.model";
|
import { CustomerInvoiceItemCreationAttributes, CustomerInvoiceItemModel } from "./customerCustomerInvoice-item.model";
|
||||||
|
|
||||||
export type InvoiceCreationAttributes = InferCreationAttributes<InvoiceModel, { omit: "items" }> & {
|
export type CustomerInvoiceCreationAttributes = InferCreationAttributes<CustomerInvoiceModel, { omit: "items" }> & {
|
||||||
items?: InvoiceItemCreationAttributes[];
|
items?: CustomerInvoiceItemCreationAttributes[];
|
||||||
};
|
};
|
||||||
|
|
||||||
export class InvoiceModel extends Model<
|
export class CustomerInvoiceModel extends Model<
|
||||||
InferAttributes<InvoiceModel>,
|
InferAttributes<CustomerInvoiceModel>,
|
||||||
InferCreationAttributes<InvoiceModel, { omit: "items" }>
|
InferCreationAttributes<CustomerInvoiceModel, { omit: "items" }>
|
||||||
> {
|
> {
|
||||||
declare id: string;
|
declare id: string;
|
||||||
|
|
||||||
declare invoice_status: string;
|
declare customerCustomerInvoice_status: string;
|
||||||
declare invoice_series: CreationOptional<string>;
|
declare customerCustomerInvoice_series: CreationOptional<string>;
|
||||||
declare invoice_number: CreationOptional<string>;
|
declare customerCustomerInvoice_number: CreationOptional<string>;
|
||||||
declare issue_date: CreationOptional<string>;
|
declare issue_date: CreationOptional<string>;
|
||||||
declare operation_date: CreationOptional<string>;
|
declare operation_date: CreationOptional<string>;
|
||||||
declare invoice_language: string;
|
declare customerCustomerInvoice_language: string;
|
||||||
declare invoice_currency: string;
|
declare customerCustomerInvoice_currency: string;
|
||||||
|
|
||||||
// Subtotal
|
// Subtotal
|
||||||
declare subtotal_amount: CreationOptional<number>;
|
declare subtotal_amount: CreationOptional<number>;
|
||||||
@ -36,40 +36,40 @@ export class InvoiceModel extends Model<
|
|||||||
declare total_scale: CreationOptional<number>;
|
declare total_scale: CreationOptional<number>;
|
||||||
|
|
||||||
// Relaciones
|
// Relaciones
|
||||||
declare items: NonAttribute<InvoiceItemModel[]>;
|
declare items: NonAttribute<CustomerInvoiceItemModel[]>;
|
||||||
//declare customer: NonAttribute<InvoiceParticipant_Model[]>;
|
//declare customer: NonAttribute<CustomerInvoiceParticipant_Model[]>;
|
||||||
|
|
||||||
static associate(database: Sequelize) {
|
static associate(database: Sequelize) {
|
||||||
const { InvoiceModel, InvoiceItemModel } = database.models;
|
const { CustomerInvoiceModel, CustomerInvoiceItemModel } = database.models;
|
||||||
|
|
||||||
InvoiceModel.hasMany(InvoiceItemModel, {
|
CustomerInvoiceModel.hasMany(CustomerInvoiceItemModel, {
|
||||||
as: "items",
|
as: "items",
|
||||||
foreignKey: "invoice_id",
|
foreignKey: "customerCustomerInvoice_id",
|
||||||
onDelete: "CASCADE",
|
onDelete: "CASCADE",
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default (database: Sequelize) => {
|
export default (database: Sequelize) => {
|
||||||
InvoiceModel.init(
|
CustomerInvoiceModel.init(
|
||||||
{
|
{
|
||||||
id: {
|
id: {
|
||||||
type: new DataTypes.UUID(),
|
type: new DataTypes.UUID(),
|
||||||
primaryKey: true,
|
primaryKey: true,
|
||||||
},
|
},
|
||||||
|
|
||||||
invoice_status: {
|
customerCustomerInvoice_status: {
|
||||||
type: new DataTypes.STRING(),
|
type: new DataTypes.STRING(),
|
||||||
allowNull: false,
|
allowNull: false,
|
||||||
},
|
},
|
||||||
|
|
||||||
invoice_series: {
|
customerCustomerInvoice_series: {
|
||||||
type: new DataTypes.STRING(),
|
type: new DataTypes.STRING(),
|
||||||
allowNull: true,
|
allowNull: true,
|
||||||
defaultValue: null,
|
defaultValue: null,
|
||||||
},
|
},
|
||||||
|
|
||||||
invoice_number: {
|
customerCustomerInvoice_number: {
|
||||||
type: new DataTypes.STRING(),
|
type: new DataTypes.STRING(),
|
||||||
allowNull: true,
|
allowNull: true,
|
||||||
defaultValue: null,
|
defaultValue: null,
|
||||||
@ -87,12 +87,12 @@ export default (database: Sequelize) => {
|
|||||||
defaultValue: null,
|
defaultValue: null,
|
||||||
},
|
},
|
||||||
|
|
||||||
invoice_language: {
|
customerCustomerInvoice_language: {
|
||||||
type: new DataTypes.STRING(),
|
type: new DataTypes.STRING(),
|
||||||
allowNull: false,
|
allowNull: false,
|
||||||
},
|
},
|
||||||
|
|
||||||
invoice_currency: {
|
customerCustomerInvoice_currency: {
|
||||||
type: new DataTypes.STRING(3), // ISO 4217
|
type: new DataTypes.STRING(3), // ISO 4217
|
||||||
allowNull: false,
|
allowNull: false,
|
||||||
},
|
},
|
||||||
@ -121,7 +121,7 @@ export default (database: Sequelize) => {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
sequelize: database,
|
sequelize: database,
|
||||||
tableName: "invoices",
|
tableName: "customerCustomerInvoices",
|
||||||
|
|
||||||
paranoid: true, // softs deletes
|
paranoid: true, // softs deletes
|
||||||
timestamps: true,
|
timestamps: true,
|
||||||
@ -130,7 +130,7 @@ export default (database: Sequelize) => {
|
|||||||
updatedAt: "updated_at",
|
updatedAt: "updated_at",
|
||||||
deletedAt: "deleted_at",
|
deletedAt: "deleted_at",
|
||||||
|
|
||||||
indexes: [{ unique: true, fields: ["invoice_number"] }],
|
indexes: [{ unique: true, fields: ["customerCustomerInvoice_number"] }],
|
||||||
|
|
||||||
whereMergeStrategy: "and", // <- cómo tratar el merge de un scope
|
whereMergeStrategy: "and", // <- cómo tratar el merge de un scope
|
||||||
|
|
||||||
@ -140,5 +140,5 @@ export default (database: Sequelize) => {
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
return InvoiceModel;
|
return CustomerInvoiceModel;
|
||||||
};
|
};
|
||||||
@ -0,0 +1,107 @@
|
|||||||
|
import { SequelizeRepository } from "@erp/core/api";
|
||||||
|
import { Criteria } from "@repo/rdx-criteria/server";
|
||||||
|
import { UniqueID } from "@repo/rdx-ddd";
|
||||||
|
import { Collection, Result } from "@repo/rdx-utils";
|
||||||
|
import { Sequelize, Transaction } from "sequelize";
|
||||||
|
import { ICustomerInvoiceRepository, CustomerInvoice } from "../../domain";
|
||||||
|
import { ICustomerInvoiceMapper } from "../mappers/customerCustomerInvoice.mapper";
|
||||||
|
import { CustomerInvoiceItemModel } from "./customerCustomerInvoice-item.model";
|
||||||
|
import { CustomerInvoiceModel } from "./customerCustomerInvoice.model";
|
||||||
|
|
||||||
|
export class CustomerInvoiceRepository extends SequelizeRepository<CustomerInvoice> implements ICustomerInvoiceRepository {
|
||||||
|
private readonly _mapper!: ICustomerInvoiceMapper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 🔹 Función personalizada para mapear errores de unicidad en autenticación
|
||||||
|
*/
|
||||||
|
private _customErrorMapper(error: Error): string | null {
|
||||||
|
if (error.name === "SequelizeUniqueConstraintError") {
|
||||||
|
return "CustomerInvoice with this email already exists";
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(database: Sequelize, mapper: ICustomerInvoiceMapper) {
|
||||||
|
super(database);
|
||||||
|
this._mapper = mapper;
|
||||||
|
}
|
||||||
|
|
||||||
|
async customerCustomerInvoiceExists(id: UniqueID, transaction?: Transaction): Promise<Result<boolean, Error>> {
|
||||||
|
try {
|
||||||
|
const _customerCustomerInvoice = await this._getById(CustomerInvoiceModel, id, {}, transaction);
|
||||||
|
|
||||||
|
return Result.ok(Boolean(id.equals(_customerCustomerInvoice.id)));
|
||||||
|
} catch (error: any) {
|
||||||
|
return this._handleDatabaseError(error, this._customErrorMapper);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async findAll(
|
||||||
|
criteria: Criteria,
|
||||||
|
transaction?: Transaction
|
||||||
|
): Promise<Result<Collection<CustomerInvoice>, Error>> {
|
||||||
|
try {
|
||||||
|
const rawCustomerInvoices = await CustomerInvoiceModel.findAll({
|
||||||
|
include: [
|
||||||
|
{
|
||||||
|
model: CustomerInvoiceItemModel,
|
||||||
|
as: "items",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
transaction,
|
||||||
|
...this.convertCriteria(criteria),
|
||||||
|
});
|
||||||
|
|
||||||
|
console.error("aqui");
|
||||||
|
|
||||||
|
return this._mapper.mapArrayToDomain(rawCustomerInvoices);
|
||||||
|
} catch (error: unknown) {
|
||||||
|
console.error("Error in findAll", error);
|
||||||
|
return this._handleDatabaseError(error, this._customErrorMapper);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async getById(id: UniqueID, transaction?: Transaction): Promise<Result<CustomerInvoice, Error>> {
|
||||||
|
try {
|
||||||
|
const rawCustomerInvoice: any = await this._getById(
|
||||||
|
CustomerInvoiceModel,
|
||||||
|
id,
|
||||||
|
{
|
||||||
|
include: [
|
||||||
|
{
|
||||||
|
model: CustomerInvoiceItemModel,
|
||||||
|
as: "items",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
transaction
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!rawCustomerInvoice === true) {
|
||||||
|
return Result.fail(new Error(`CustomerInvoice with id ${id.toString()} not exists`));
|
||||||
|
}
|
||||||
|
} catch (error: any) {
|
||||||
|
return this._handleDatabaseError(error, this._customErrorMapper);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async deleteById(id: UniqueID, transaction?: Transaction): Promise<Result<boolean, Error>> {
|
||||||
|
try {
|
||||||
|
this._deleteById(CustomerInvoiceModel, id, false, transaction);
|
||||||
|
return Result.ok<boolean>(true);
|
||||||
|
} catch (error: any) {
|
||||||
|
return this._handleDatabaseError(error, this._customErrorMapper);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async create(customerCustomerInvoice: CustomerInvoice, transaction?: Transaction): Promise<void> {
|
||||||
|
const customerCustomerInvoiceData = this._mapper.mapToPersistence(customerCustomerInvoice);
|
||||||
|
await this._save(CustomerInvoiceModel, customerCustomerInvoice.id, customerCustomerInvoiceData, {}, transaction);
|
||||||
|
}
|
||||||
|
|
||||||
|
async update(customerCustomerInvoice: CustomerInvoice, transaction?: Transaction): Promise<void> {
|
||||||
|
const customerCustomerInvoiceData = this._mapper.mapToPersistence(customerCustomerInvoice);
|
||||||
|
await this._save(CustomerInvoiceModel, customerCustomerInvoice.id, customerCustomerInvoiceData, {}, transaction);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,106 @@
|
|||||||
|
import {
|
||||||
|
CreationOptional,
|
||||||
|
DataTypes,
|
||||||
|
InferAttributes,
|
||||||
|
InferCreationAttributes,
|
||||||
|
Model,
|
||||||
|
NonAttribute,
|
||||||
|
Sequelize,
|
||||||
|
} from "sequelize";
|
||||||
|
import { CustomerInvoiceModel } from "./customerCustomerInvoice.model";
|
||||||
|
import {
|
||||||
|
CustomerInvoiceParticipantAddress_Model,
|
||||||
|
TCreationCustomerInvoiceParticipantAddress_Model,
|
||||||
|
} from "./customerCustomerInvoiceParticipantAddress.mo.del.ts.bak";
|
||||||
|
|
||||||
|
export type TCreationCustomerInvoiceParticipant_Model = InferCreationAttributes<
|
||||||
|
CustomerInvoiceParticipant_Model,
|
||||||
|
{ omit: "shippingAddress" | "billingAddress" | "customerCustomerInvoice" }
|
||||||
|
> & {
|
||||||
|
billingAddress: TCreationCustomerInvoiceParticipantAddress_Model;
|
||||||
|
shippingAddress: TCreationCustomerInvoiceParticipantAddress_Model;
|
||||||
|
};
|
||||||
|
|
||||||
|
export class CustomerInvoiceParticipant_Model extends Model<
|
||||||
|
InferAttributes<
|
||||||
|
CustomerInvoiceParticipant_Model,
|
||||||
|
{ omit: "shippingAddress" | "billingAddress" | "customerCustomerInvoice" }
|
||||||
|
>,
|
||||||
|
InferCreationAttributes<
|
||||||
|
CustomerInvoiceParticipant_Model,
|
||||||
|
{ omit: "shippingAddress" | "billingAddress" | "customerCustomerInvoice" }
|
||||||
|
>
|
||||||
|
> {
|
||||||
|
static associate(connection: Sequelize) {
|
||||||
|
const { CustomerInvoice_Model, CustomerInvoiceParticipantAddress_Model, CustomerInvoiceParticipant_Model } =
|
||||||
|
connection.models;
|
||||||
|
|
||||||
|
CustomerInvoiceParticipant_Model.belongsTo(CustomerInvoice_Model, {
|
||||||
|
as: "customerCustomerInvoice",
|
||||||
|
foreignKey: "customerCustomerInvoice_id",
|
||||||
|
onDelete: "CASCADE",
|
||||||
|
});
|
||||||
|
|
||||||
|
CustomerInvoiceParticipant_Model.hasOne(CustomerInvoiceParticipantAddress_Model, {
|
||||||
|
as: "shippingAddress",
|
||||||
|
foreignKey: "participant_id",
|
||||||
|
onDelete: "CASCADE",
|
||||||
|
});
|
||||||
|
|
||||||
|
CustomerInvoiceParticipant_Model.hasOne(CustomerInvoiceParticipantAddress_Model, {
|
||||||
|
as: "billingAddress",
|
||||||
|
foreignKey: "participant_id",
|
||||||
|
onDelete: "CASCADE",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
declare participant_id: string;
|
||||||
|
declare customerCustomerInvoice_id: string;
|
||||||
|
declare tin: CreationOptional<string>;
|
||||||
|
declare company_name: CreationOptional<string>;
|
||||||
|
declare first_name: CreationOptional<string>;
|
||||||
|
declare last_name: CreationOptional<string>;
|
||||||
|
|
||||||
|
declare shippingAddress?: NonAttribute<CustomerInvoiceParticipantAddress_Model>;
|
||||||
|
declare billingAddress?: NonAttribute<CustomerInvoiceParticipantAddress_Model>;
|
||||||
|
|
||||||
|
declare customerCustomerInvoice?: NonAttribute<CustomerInvoiceModel>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default (sequelize: Sequelize) => {
|
||||||
|
CustomerInvoiceParticipant_Model.init(
|
||||||
|
{
|
||||||
|
participant_id: {
|
||||||
|
type: new DataTypes.UUID(),
|
||||||
|
primaryKey: true,
|
||||||
|
},
|
||||||
|
customerCustomerInvoice_id: {
|
||||||
|
type: new DataTypes.UUID(),
|
||||||
|
primaryKey: true,
|
||||||
|
},
|
||||||
|
tin: {
|
||||||
|
type: new DataTypes.STRING(),
|
||||||
|
allowNull: true,
|
||||||
|
},
|
||||||
|
company_name: {
|
||||||
|
type: new DataTypes.STRING(),
|
||||||
|
allowNull: true,
|
||||||
|
},
|
||||||
|
first_name: {
|
||||||
|
type: new DataTypes.STRING(),
|
||||||
|
allowNull: true,
|
||||||
|
},
|
||||||
|
last_name: {
|
||||||
|
type: new DataTypes.STRING(),
|
||||||
|
allowNull: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
sequelize,
|
||||||
|
tableName: "customerCustomerInvoice_participants",
|
||||||
|
timestamps: false,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
return CustomerInvoiceParticipant_Model;
|
||||||
|
};
|
||||||
@ -7,20 +7,20 @@ import {
|
|||||||
NonAttribute,
|
NonAttribute,
|
||||||
Sequelize,
|
Sequelize,
|
||||||
} from "sequelize";
|
} from "sequelize";
|
||||||
import { InvoiceParticipant_Model } from "./invoiceParticipant.mo.del.ts.bak";
|
import { CustomerInvoiceParticipant_Model } from "./customerCustomerInvoiceParticipant.mo.del.ts.bak";
|
||||||
|
|
||||||
export type TCreationInvoiceParticipantAddress_Model = InferCreationAttributes<
|
export type TCreationCustomerInvoiceParticipantAddress_Model = InferCreationAttributes<
|
||||||
InvoiceParticipantAddress_Model,
|
CustomerInvoiceParticipantAddress_Model,
|
||||||
{ omit: "participant" }
|
{ omit: "participant" }
|
||||||
>;
|
>;
|
||||||
|
|
||||||
export class InvoiceParticipantAddress_Model extends Model<
|
export class CustomerInvoiceParticipantAddress_Model extends Model<
|
||||||
InferAttributes<InvoiceParticipantAddress_Model, { omit: "participant" }>,
|
InferAttributes<CustomerInvoiceParticipantAddress_Model, { omit: "participant" }>,
|
||||||
InferCreationAttributes<InvoiceParticipantAddress_Model, { omit: "participant" }>
|
InferCreationAttributes<CustomerInvoiceParticipantAddress_Model, { omit: "participant" }>
|
||||||
> {
|
> {
|
||||||
static associate(connection: Sequelize) {
|
static associate(connection: Sequelize) {
|
||||||
const { InvoiceParticipantAddress_Model, InvoiceParticipant_Model } = connection.models;
|
const { CustomerInvoiceParticipantAddress_Model, CustomerInvoiceParticipant_Model } = connection.models;
|
||||||
InvoiceParticipantAddress_Model.belongsTo(InvoiceParticipant_Model, {
|
CustomerInvoiceParticipantAddress_Model.belongsTo(CustomerInvoiceParticipant_Model, {
|
||||||
as: "participant",
|
as: "participant",
|
||||||
foreignKey: "participant_id",
|
foreignKey: "participant_id",
|
||||||
});
|
});
|
||||||
@ -37,11 +37,11 @@ export class InvoiceParticipantAddress_Model extends Model<
|
|||||||
declare phone: CreationOptional<string>;
|
declare phone: CreationOptional<string>;
|
||||||
declare email: CreationOptional<string>;
|
declare email: CreationOptional<string>;
|
||||||
|
|
||||||
declare participant?: NonAttribute<InvoiceParticipant_Model>;
|
declare participant?: NonAttribute<CustomerInvoiceParticipant_Model>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default (sequelize: Sequelize) => {
|
export default (sequelize: Sequelize) => {
|
||||||
InvoiceParticipantAddress_Model.init(
|
CustomerInvoiceParticipantAddress_Model.init(
|
||||||
{
|
{
|
||||||
address_id: {
|
address_id: {
|
||||||
type: new DataTypes.UUID(),
|
type: new DataTypes.UUID(),
|
||||||
@ -86,9 +86,9 @@ export default (sequelize: Sequelize) => {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
sequelize,
|
sequelize,
|
||||||
tableName: "invoice_participant_addresses",
|
tableName: "customerCustomerInvoice_participant_addresses",
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
return InvoiceParticipantAddress_Model;
|
return CustomerInvoiceParticipantAddress_Model;
|
||||||
};
|
};
|
||||||
@ -0,0 +1,9 @@
|
|||||||
|
import customerCustomerInvoiceItemModelInit from "./customerCustomerInvoice-item.model";
|
||||||
|
import customerCustomerInvoiceModelInit from "./customerCustomerInvoice.model";
|
||||||
|
|
||||||
|
export * from "./customerCustomerInvoice-item.model"; // exporta las clases, tipos
|
||||||
|
export * from "./customerCustomerInvoice.model";
|
||||||
|
export * from "./customerCustomerInvoice.repository";
|
||||||
|
|
||||||
|
// Array de inicializadores para que registerModels() lo use
|
||||||
|
export const models = [customerCustomerInvoiceItemModelInit, customerCustomerInvoiceModelInit];
|
||||||
@ -0,0 +1,12 @@
|
|||||||
|
import { DeleteCustomerInvoiceUseCase } from "@/contexts/customerCustomerInvoices/application";
|
||||||
|
import { ExpressController } from "@/core/common/presentation";
|
||||||
|
|
||||||
|
export class DeleteCustomerInvoiceController extends ExpressController {
|
||||||
|
public constructor(private readonly deleteCustomerInvoice: DeleteCustomerInvoiceUseCase) {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
async executeImpl(): Promise<any> {
|
||||||
|
return this.noContent();
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,14 @@
|
|||||||
|
import { DeleteCustomerInvoiceUseCase } from "@/contexts/customerCustomerInvoices/application";
|
||||||
|
import { CustomerInvoiceService } from "@/contexts/customerCustomerInvoices/domain";
|
||||||
|
import { customerCustomerInvoiceRepository } from "@/contexts/customerCustomerInvoices/intrastructure";
|
||||||
|
import { SequelizeTransactionManager } from "@/core/common/infrastructure";
|
||||||
|
import { DeleteCustomerInvoiceController } from "./delete-customer-invoice.controller";
|
||||||
|
|
||||||
|
export const buildDeleteCustomerInvoiceController = () => {
|
||||||
|
const transactionManager = new SequelizeTransactionManager();
|
||||||
|
const customerCustomerInvoiceService = new CustomerInvoiceService(customerCustomerInvoiceRepository);
|
||||||
|
|
||||||
|
const useCase = new DeleteCustomerInvoiceUseCase(customerCustomerInvoiceService, transactionManager);
|
||||||
|
|
||||||
|
return new DeleteCustomerInvoiceController(useCase);
|
||||||
|
};
|
||||||
@ -0,0 +1,44 @@
|
|||||||
|
import { ExpressController } from "@erp/core/api";
|
||||||
|
import { UniqueID } from "@repo/rdx-ddd";
|
||||||
|
import { GetCustomerInvoiceUseCase } from "../../application";
|
||||||
|
import { IGetCustomerInvoicePresenter } from "./presenter";
|
||||||
|
|
||||||
|
export class GetCustomerInvoiceController extends ExpressController {
|
||||||
|
public constructor(
|
||||||
|
private readonly getCustomerInvoice: GetCustomerInvoiceUseCase,
|
||||||
|
private readonly presenter: IGetCustomerInvoicePresenter
|
||||||
|
) {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected async executeImpl() {
|
||||||
|
const { customerCustomerInvoiceId } = this.req.params;
|
||||||
|
|
||||||
|
// Validar ID
|
||||||
|
const customerCustomerInvoiceIdOrError = UniqueID.create(customerCustomerInvoiceId);
|
||||||
|
if (customerCustomerInvoiceIdOrError.isFailure) return this.invalidInputError("CustomerInvoice ID not valid");
|
||||||
|
|
||||||
|
const customerCustomerInvoiceOrError = await this.getCustomerInvoice.execute(customerCustomerInvoiceIdOrError.data);
|
||||||
|
|
||||||
|
if (customerCustomerInvoiceOrError.isFailure) {
|
||||||
|
return this.handleError(customerCustomerInvoiceOrError.error);
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.ok(this.presenter.toDTO(customerCustomerInvoiceOrError.data));
|
||||||
|
}
|
||||||
|
|
||||||
|
private handleError(error: Error) {
|
||||||
|
const message = error.message;
|
||||||
|
|
||||||
|
if (
|
||||||
|
message.includes("Database connection lost") ||
|
||||||
|
message.includes("Database request timed out")
|
||||||
|
) {
|
||||||
|
return this.unavailableError(
|
||||||
|
"Database service is currently unavailable. Please try again later."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.conflictError(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,24 @@
|
|||||||
|
import { SequelizeTransactionManager } from "@erp/core/api";
|
||||||
|
import { Sequelize } from "sequelize";
|
||||||
|
import { CustomerInvoiceService } from "../../domain";
|
||||||
|
import { CustomerInvoiceRepository, customerCustomerInvoiceMapper } from "../../infrastructure";
|
||||||
|
|
||||||
|
import { GetCustomerInvoiceUseCase } from "../../application";
|
||||||
|
import { GetCustomerInvoiceController } from "./get-customer-invoice.controller";
|
||||||
|
import { getCustomerInvoicePresenter } from "./presenter";
|
||||||
|
|
||||||
|
export const buildGetCustomerInvoiceController = (database: Sequelize) => {
|
||||||
|
const transactionManager = new SequelizeTransactionManager(database);
|
||||||
|
const customerCustomerInvoiceRepository = new CustomerInvoiceRepository(
|
||||||
|
database,
|
||||||
|
customerCustomerInvoiceMapper
|
||||||
|
);
|
||||||
|
const customerCustomerInvoiceService = new CustomerInvoiceService(
|
||||||
|
customerCustomerInvoiceRepository
|
||||||
|
);
|
||||||
|
|
||||||
|
const useCase = new GetCustomerInvoiceUseCase(customerCustomerInvoiceService, transactionManager);
|
||||||
|
const presenter = getCustomerInvoicePresenter;
|
||||||
|
|
||||||
|
return new GetCustomerInvoiceController(useCase, presenter);
|
||||||
|
};
|
||||||
@ -1,10 +1,10 @@
|
|||||||
import { InvoiceItem } from "#/server/domain";
|
import { CustomerInvoiceItem } from "#/server/domain";
|
||||||
import { IInvoicingContext } from "#/server/intrastructure";
|
import { IInvoicingContext } from "#/server/intrastructure";
|
||||||
import { Collection } from "@rdx/core";
|
import { Collection } from "@rdx/core";
|
||||||
|
|
||||||
export const invoiceItemPresenter = (items: Collection<InvoiceItem>, context: IInvoicingContext) =>
|
export const customerCustomerInvoiceItemPresenter = (items: Collection<CustomerInvoiceItem>, context: IInvoicingContext) =>
|
||||||
items.totalCount > 0
|
items.totalCount > 0
|
||||||
? items.items.map((item: InvoiceItem) => ({
|
? items.items.map((item: CustomerInvoiceItem) => ({
|
||||||
description: item.description.toString(),
|
description: item.description.toString(),
|
||||||
quantity: item.quantity.toString(),
|
quantity: item.quantity.toString(),
|
||||||
unit_measure: "",
|
unit_measure: "",
|
||||||
@ -0,0 +1,26 @@
|
|||||||
|
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,11 +1,11 @@
|
|||||||
import { InvoiceParticipantAddress } from "@/contexts/invoicing/domain";
|
import { CustomerInvoiceParticipantAddress } from "@/contexts/invoicing/domain";
|
||||||
import { IInvoicingContext } from "@/contexts/invoicing/intrastructure/InvoicingContext";
|
import { IInvoicingContext } from "@/contexts/invoicing/intrastructure/InvoicingContext";
|
||||||
import { ICreateInvoice_AddressParticipant_Response_DTO } from "@shared/contexts";
|
import { ICreateCustomerInvoice_AddressParticipant_Response_DTO } from "@shared/contexts";
|
||||||
|
|
||||||
export const InvoiceParticipantAddressPresenter = async (
|
export const CustomerInvoiceParticipantAddressPresenter = async (
|
||||||
address: InvoiceParticipantAddress,
|
address: CustomerInvoiceParticipantAddress,
|
||||||
context: IInvoicingContext,
|
context: IInvoicingContext,
|
||||||
): Promise<ICreateInvoice_AddressParticipant_Response_DTO> => {
|
): Promise<ICreateCustomerInvoice_AddressParticipant_Response_DTO> => {
|
||||||
return {
|
return {
|
||||||
id: address.id.toString(),
|
id: address.id.toString(),
|
||||||
street: address.street.toString(),
|
street: address.street.toString(),
|
||||||
@ -0,0 +1,59 @@
|
|||||||
|
import { IGetCustomerInvoiceResponseDTO } from "../../../../../common/dto";
|
||||||
|
import { CustomerInvoice, CustomerInvoiceItem } from "../../../../domain";
|
||||||
|
|
||||||
|
export interface IGetCustomerInvoicePresenter {
|
||||||
|
toDTO: (customerCustomerInvoice: CustomerInvoice) => IGetCustomerInvoiceResponseDTO;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const getCustomerInvoicePresenter: IGetCustomerInvoicePresenter = {
|
||||||
|
toDTO: (customerCustomerInvoice: CustomerInvoice): IGetCustomerInvoiceResponseDTO => ({
|
||||||
|
id: customerCustomerInvoice.id.toPrimitive(),
|
||||||
|
|
||||||
|
customerCustomerInvoice_status: customerCustomerInvoice.status.toString(),
|
||||||
|
customerCustomerInvoice_number: customerCustomerInvoice.customerCustomerInvoiceNumber.toString(),
|
||||||
|
customerCustomerInvoice_series: customerCustomerInvoice.customerCustomerInvoiceSeries.toString(),
|
||||||
|
issue_date: customerCustomerInvoice.issueDate.toDateString(),
|
||||||
|
operation_date: customerCustomerInvoice.operationDate.toDateString(),
|
||||||
|
language_code: "ES",
|
||||||
|
currency: customerCustomerInvoice.customerCustomerInvoiceCurrency.toString(),
|
||||||
|
subtotal: customerCustomerInvoice.calculateSubtotal().toPrimitive(),
|
||||||
|
total: customerCustomerInvoice.calculateTotal().toPrimitive(),
|
||||||
|
|
||||||
|
items:
|
||||||
|
customerCustomerInvoice.items.size() > 0
|
||||||
|
? customerCustomerInvoice.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(customerCustomerInvoice.senderId, context),
|
||||||
|
|
||||||
|
/*recipient: await CustomerInvoiceParticipantPresenter(customerCustomerInvoice.recipient, context),
|
||||||
|
items: customerCustomerInvoiceItemPresenter(customerCustomerInvoice.items, context),
|
||||||
|
|
||||||
|
payment_term: {
|
||||||
|
payment_type: "",
|
||||||
|
due_date: "",
|
||||||
|
},
|
||||||
|
|
||||||
|
due_amount: {
|
||||||
|
currency: customerCustomerInvoice.currency.toString(),
|
||||||
|
precision: 2,
|
||||||
|
amount: 0,
|
||||||
|
},
|
||||||
|
|
||||||
|
custom_fields: [],
|
||||||
|
|
||||||
|
metadata: {
|
||||||
|
create_time: "",
|
||||||
|
last_updated_time: "",
|
||||||
|
delete_time: "",
|
||||||
|
},*/
|
||||||
|
}),
|
||||||
|
};
|
||||||
@ -0,0 +1 @@
|
|||||||
|
export * from "./get-customer-invoice.presenter";
|
||||||
5
modules/customer-invoices/src/api/presentation/index.ts
Normal file
5
modules/customer-invoices/src/api/presentation/index.ts
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
//export * from "./create-customer-invoice";
|
||||||
|
//export * from "./delete-customer-invoice";
|
||||||
|
export * from "./get-customer-invoice";
|
||||||
|
export * from "./list-customer-invoices";
|
||||||
|
///export * from "./update-customer-invoice";
|
||||||
@ -0,0 +1,26 @@
|
|||||||
|
import { SequelizeTransactionManager } from "@erp/core/api";
|
||||||
|
import { Sequelize } from "sequelize";
|
||||||
|
import { ListCustomerInvoicesUseCase } from "../../application";
|
||||||
|
import { CustomerInvoiceService } from "../../domain";
|
||||||
|
import { CustomerInvoiceRepository, customerCustomerInvoiceMapper } from "../../infrastructure";
|
||||||
|
import { ListCustomerInvoicesController } from "./list-customer-invoices.controller";
|
||||||
|
import { listCustomerInvoicesPresenter } from "./presenter";
|
||||||
|
|
||||||
|
export const buildListCustomerInvoicesController = (database: Sequelize) => {
|
||||||
|
const transactionManager = new SequelizeTransactionManager(database);
|
||||||
|
const customerCustomerInvoiceRepository = new CustomerInvoiceRepository(
|
||||||
|
database,
|
||||||
|
customerCustomerInvoiceMapper
|
||||||
|
);
|
||||||
|
const customerCustomerInvoiceService = new CustomerInvoiceService(
|
||||||
|
customerCustomerInvoiceRepository
|
||||||
|
);
|
||||||
|
|
||||||
|
const useCase = new ListCustomerInvoicesUseCase(
|
||||||
|
customerCustomerInvoiceService,
|
||||||
|
transactionManager
|
||||||
|
);
|
||||||
|
const presenter = listCustomerInvoicesPresenter;
|
||||||
|
|
||||||
|
return new ListCustomerInvoicesController(useCase, presenter);
|
||||||
|
};
|
||||||
@ -0,0 +1,38 @@
|
|||||||
|
import { ExpressController } from "@erp/core/api";
|
||||||
|
import { ListCustomerInvoicesUseCase } from "../../application";
|
||||||
|
import { IListCustomerInvoicesPresenter } from "./presenter";
|
||||||
|
|
||||||
|
export class ListCustomerInvoicesController extends ExpressController {
|
||||||
|
public constructor(
|
||||||
|
private readonly listCustomerInvoices: ListCustomerInvoicesUseCase,
|
||||||
|
private readonly presenter: IListCustomerInvoicesPresenter
|
||||||
|
) {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected async executeImpl() {
|
||||||
|
const criteria = this.criteria;
|
||||||
|
const customerCustomerInvoicesOrError = await this.listCustomerInvoices.execute(criteria);
|
||||||
|
|
||||||
|
if (customerCustomerInvoicesOrError.isFailure) {
|
||||||
|
return this.handleError(customerCustomerInvoicesOrError.error);
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.ok(this.presenter.toDTO(customerCustomerInvoicesOrError.data, criteria));
|
||||||
|
}
|
||||||
|
|
||||||
|
private handleError(error: Error) {
|
||||||
|
const message = error.message;
|
||||||
|
|
||||||
|
if (
|
||||||
|
message.includes("Database connection lost") ||
|
||||||
|
message.includes("Database request timed out")
|
||||||
|
) {
|
||||||
|
return this.unavailableError(
|
||||||
|
"Database service is currently unavailable. Please try again later."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.conflictError(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,22 @@
|
|||||||
|
import { ICustomerInvoiceParticipant } from "@/contexts/invoicing/domain";
|
||||||
|
import { IListCustomerInvoice_Participant_Response_DTO } from "@shared/contexts";
|
||||||
|
import { CustomerInvoiceParticipantAddressPresenter } from "./CustomerInvoiceParticipantAddress.presenter";
|
||||||
|
|
||||||
|
export const CustomerInvoiceParticipantPresenter = (
|
||||||
|
participant: ICustomerInvoiceParticipant,
|
||||||
|
): IListCustomerInvoice_Participant_Response_DTO => {
|
||||||
|
return {
|
||||||
|
participant_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: CustomerInvoiceParticipantAddressPresenter(
|
||||||
|
participant?.billingAddress!,
|
||||||
|
),
|
||||||
|
shipping_address: CustomerInvoiceParticipantAddressPresenter(
|
||||||
|
participant?.shippingAddress!,
|
||||||
|
),
|
||||||
|
};
|
||||||
|
};
|
||||||
@ -1,6 +1,6 @@
|
|||||||
export const InvoiceParticipantAddressPresenter = (
|
export const CustomerInvoiceParticipantAddressPresenter = (
|
||||||
address: InvoiceParticipantAddress
|
address: CustomerInvoiceParticipantAddress
|
||||||
): IListInvoice_AddressParticipant_Response_DTO => {
|
): IListCustomerInvoice_AddressParticipant_Response_DTO => {
|
||||||
return {
|
return {
|
||||||
address_id: address?.id.toString(),
|
address_id: address?.id.toString(),
|
||||||
street: address?.street.toString(),
|
street: address?.street.toString(),
|
||||||
@ -0,0 +1 @@
|
|||||||
|
export * from "./list-customer-invoices.presenter";
|
||||||
@ -0,0 +1,54 @@
|
|||||||
|
import { IListResponseDTO } from "@erp/core/api";
|
||||||
|
import { Criteria } from "@repo/rdx-criteria/server";
|
||||||
|
import { Collection } from "@repo/rdx-utils";
|
||||||
|
import { IListCustomerInvoicesResponseDTO } from "../../../../common/dto";
|
||||||
|
import { CustomerInvoice } from "../../../domain";
|
||||||
|
|
||||||
|
export interface IListCustomerInvoicesPresenter {
|
||||||
|
toDTO: (
|
||||||
|
customerCustomerInvoices: Collection<CustomerInvoice>,
|
||||||
|
criteria: Criteria
|
||||||
|
) => IListResponseDTO<IListCustomerInvoicesResponseDTO>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const listCustomerInvoicesPresenter: IListCustomerInvoicesPresenter = {
|
||||||
|
toDTO: (
|
||||||
|
customerCustomerInvoices: Collection<CustomerInvoice>,
|
||||||
|
criteria: Criteria
|
||||||
|
): IListResponseDTO<IListCustomerInvoicesResponseDTO> => {
|
||||||
|
const items = customerInvoices.map((customerCustomerInvoice) => {
|
||||||
|
return {
|
||||||
|
id: customerCustomerInvoice.id.toPrimitive(),
|
||||||
|
|
||||||
|
customerCustomerInvoice_status: customerCustomerInvoice.status.toString(),
|
||||||
|
customerCustomerInvoice_number:
|
||||||
|
customerCustomerInvoice.customerCustomerInvoiceNumber.toString(),
|
||||||
|
customerCustomerInvoice_series:
|
||||||
|
customerCustomerInvoice.customerCustomerInvoiceSeries.toString(),
|
||||||
|
issue_date: customerCustomerInvoice.issueDate.toISOString(),
|
||||||
|
operation_date: customerCustomerInvoice.operationDate.toISOString(),
|
||||||
|
language_code: "ES",
|
||||||
|
|
||||||
|
currency: customerCustomerInvoice.customerCustomerInvoiceCurrency.toString(),
|
||||||
|
subtotal: customerCustomerInvoice.calculateSubtotal().toPrimitive(),
|
||||||
|
total: customerCustomerInvoice.calculateTotal().toPrimitive(),
|
||||||
|
|
||||||
|
//recipient: CustomerInvoiceParticipantPresenter(customerCustomerInvoice.recipient),
|
||||||
|
|
||||||
|
metadata: {
|
||||||
|
entity: "customerCustomerInvoice",
|
||||||
|
},
|
||||||
|
} as IListCustomerInvoicesResponseDTO;
|
||||||
|
});
|
||||||
|
|
||||||
|
const totalItems = customerInvoices.total();
|
||||||
|
|
||||||
|
return {
|
||||||
|
page: criteria.pageNumber,
|
||||||
|
per_page: criteria.pageSize,
|
||||||
|
total_pages: Math.ceil(totalItems / criteria.pageSize),
|
||||||
|
total_items: totalItems,
|
||||||
|
items: items,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
};
|
||||||
@ -1,37 +1,37 @@
|
|||||||
import { IInvoicingContext } from "#/server/intrastructure";
|
import { IInvoicingContext } from "#/server/intrastructure";
|
||||||
import { InvoiceRepository } from "#/server/intrastructure/Invoice.repository";
|
import { CustomerInvoiceRepository } from "#/server/intrastructure/CustomerInvoice.repository";
|
||||||
|
|
||||||
export const updateInvoiceController = (context: IInvoicingContext) => {
|
export const updateCustomerInvoiceController = (context: IInvoicingContext) => {
|
||||||
const adapter = context.adapter;
|
const adapter = context.adapter;
|
||||||
const repoManager = context.repositoryManager;
|
const repoManager = context.repositoryManager;
|
||||||
|
|
||||||
repoManager.registerRepository("Invoice", (params = { transaction: null }) => {
|
repoManager.registerRepository("CustomerInvoice", (params = { transaction: null }) => {
|
||||||
const { transaction } = params;
|
const { transaction } = params;
|
||||||
|
|
||||||
return new InvoiceRepository({
|
return new CustomerInvoiceRepository({
|
||||||
transaction,
|
transaction,
|
||||||
adapter,
|
adapter,
|
||||||
mapper: createInvoiceMapper(context),
|
mapper: createCustomerInvoiceMapper(context),
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
repoManager.registerRepository("Participant", (params = { transaction: null }) => {
|
repoManager.registerRepository("Participant", (params = { transaction: null }) => {
|
||||||
const { transaction } = params;
|
const { transaction } = params;
|
||||||
|
|
||||||
return new InvoiceParticipantRepository({
|
return new CustomerInvoiceParticipantRepository({
|
||||||
transaction,
|
transaction,
|
||||||
adapter,
|
adapter,
|
||||||
mapper: createInvoiceParticipantMapper(context),
|
mapper: createCustomerInvoiceParticipantMapper(context),
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
repoManager.registerRepository("ParticipantAddress", (params = { transaction: null }) => {
|
repoManager.registerRepository("ParticipantAddress", (params = { transaction: null }) => {
|
||||||
const { transaction } = params;
|
const { transaction } = params;
|
||||||
|
|
||||||
return new InvoiceParticipantAddressRepository({
|
return new CustomerInvoiceParticipantAddressRepository({
|
||||||
transaction,
|
transaction,
|
||||||
adapter,
|
adapter,
|
||||||
mapper: createInvoiceParticipantAddressMapper(context),
|
mapper: createCustomerInvoiceParticipantAddressMapper(context),
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -45,12 +45,12 @@ export const updateInvoiceController = (context: IInvoicingContext) => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
const updateInvoiceUseCase = new UpdateInvoiceUseCase(context);
|
const updateCustomerInvoiceUseCase = new UpdateCustomerInvoiceUseCase(context);
|
||||||
|
|
||||||
return new UpdateInvoiceController(
|
return new UpdateCustomerInvoiceController(
|
||||||
{
|
{
|
||||||
useCase: updateInvoiceUseCase,
|
useCase: updateCustomerInvoiceUseCase,
|
||||||
presenter: updateInvoicePresenter,
|
presenter: updateCustomerInvoicePresenter,
|
||||||
},
|
},
|
||||||
context
|
context
|
||||||
);
|
);
|
||||||
@ -1,13 +1,13 @@
|
|||||||
import { InvoiceItem } from "@/contexts/invoicing/domain/InvoiceItems";
|
import { CustomerInvoiceItem } from "@/contexts/invoicing/domain/CustomerInvoiceItems";
|
||||||
import { IInvoicingContext } from "@/contexts/invoicing/intrastructure/InvoicingContext";
|
import { IInvoicingContext } from "@/contexts/invoicing/intrastructure/InvoicingContext";
|
||||||
import { ICollection, IMoney_Response_DTO } from "@shared/contexts";
|
import { ICollection, IMoney_Response_DTO } from "@shared/contexts";
|
||||||
|
|
||||||
export const invoiceItemPresenter = (
|
export const customerCustomerInvoiceItemPresenter = (
|
||||||
items: ICollection<InvoiceItem>,
|
items: ICollection<CustomerInvoiceItem>,
|
||||||
context: IInvoicingContext
|
context: IInvoicingContext
|
||||||
) =>
|
) =>
|
||||||
items.totalCount > 0
|
items.totalCount > 0
|
||||||
? items.items.map((item: InvoiceItem) => ({
|
? items.items.map((item: CustomerInvoiceItem) => ({
|
||||||
description: item.description.toString(),
|
description: item.description.toString(),
|
||||||
quantity: item.quantity.toString(),
|
quantity: item.quantity.toString(),
|
||||||
unit_measure: "",
|
unit_measure: "",
|
||||||
@ -0,0 +1,26 @@
|
|||||||
|
import { ICustomerInvoiceParticipant } from "@/contexts/invoicing/domain";
|
||||||
|
import { IInvoicingContext } from "@/contexts/invoicing/intrastructure/InvoicingContext";
|
||||||
|
import { IUpdateCustomerInvoice_Participant_Response_DTO } from "@shared/contexts";
|
||||||
|
import { CustomerInvoiceParticipantAddressPresenter } from "./CustomerInvoiceParticipantAddress.presenter";
|
||||||
|
|
||||||
|
export const CustomerInvoiceParticipantPresenter = (
|
||||||
|
participant: ICustomerInvoiceParticipant,
|
||||||
|
context: IInvoicingContext,
|
||||||
|
): IUpdateCustomerInvoice_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: CustomerInvoiceParticipantAddressPresenter(
|
||||||
|
participant.billingAddress!,
|
||||||
|
context,
|
||||||
|
),
|
||||||
|
shipping_address: CustomerInvoiceParticipantAddressPresenter(
|
||||||
|
participant.shippingAddress!,
|
||||||
|
context,
|
||||||
|
),
|
||||||
|
};
|
||||||
|
};
|
||||||
@ -1,11 +1,11 @@
|
|||||||
import { InvoiceParticipantAddress } from "@/contexts/invoicing/domain";
|
import { CustomerInvoiceParticipantAddress } from "@/contexts/invoicing/domain";
|
||||||
import { IInvoicingContext } from "@/contexts/invoicing/intrastructure/InvoicingContext";
|
import { IInvoicingContext } from "@/contexts/invoicing/intrastructure/InvoicingContext";
|
||||||
import { IUpdateInvoice_AddressParticipant_Response_DTO } from "@shared/contexts";
|
import { IUpdateCustomerInvoice_AddressParticipant_Response_DTO } from "@shared/contexts";
|
||||||
|
|
||||||
export const InvoiceParticipantAddressPresenter = (
|
export const CustomerInvoiceParticipantAddressPresenter = (
|
||||||
address: InvoiceParticipantAddress,
|
address: CustomerInvoiceParticipantAddress,
|
||||||
context: IInvoicingContext,
|
context: IInvoicingContext,
|
||||||
): IUpdateInvoice_AddressParticipant_Response_DTO => {
|
): IUpdateCustomerInvoice_AddressParticipant_Response_DTO => {
|
||||||
return {
|
return {
|
||||||
id: address.id.toString(),
|
id: address.id.toString(),
|
||||||
street: address.street.toString(),
|
street: address.street.toString(),
|
||||||
@ -0,0 +1,33 @@
|
|||||||
|
import { CustomerInvoice } from "@/contexts/invoicing/domain";
|
||||||
|
import { IInvoicingContext } from "@/contexts/invoicing/intrastructure/InvoicingContext";
|
||||||
|
import { IUpdateCustomerInvoice_Response_DTO } from "@shared/contexts";
|
||||||
|
import { customerCustomerInvoiceItemPresenter } from "./CustomerInvoiceItem.presenter";
|
||||||
|
import { CustomerInvoiceParticipantPresenter } from "./CustomerInvoiceParticipant.presenter";
|
||||||
|
|
||||||
|
export interface IUpdateCustomerInvoicePresenter {
|
||||||
|
map: (customerCustomerInvoice: CustomerInvoice, context: IInvoicingContext) => IUpdateCustomerInvoice_Response_DTO;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const updateCustomerInvoicePresenter: IUpdateCustomerInvoicePresenter = {
|
||||||
|
map: (customerCustomerInvoice: CustomerInvoice, context: IInvoicingContext): IUpdateCustomerInvoice_Response_DTO => {
|
||||||
|
return {
|
||||||
|
id: customerCustomerInvoice.id.toString(),
|
||||||
|
|
||||||
|
customerCustomerInvoice_status: customerCustomerInvoice.status.toString(),
|
||||||
|
customerCustomerInvoice_number: customerCustomerInvoice.customerCustomerInvoiceNumber.toString(),
|
||||||
|
customerCustomerInvoice_series: customerCustomerInvoice.customerCustomerInvoiceSeries.toString(),
|
||||||
|
issue_date: customerCustomerInvoice.issueDate.toISO8601(),
|
||||||
|
operation_date: customerCustomerInvoice.operationDate.toISO8601(),
|
||||||
|
language_code: customerCustomerInvoice.language.toString(),
|
||||||
|
currency: customerCustomerInvoice.currency.toString(),
|
||||||
|
subtotal: customerCustomerInvoice.calculateSubtotal().toPrimitive(),
|
||||||
|
total: customerCustomerInvoice.calculateTotal().toPrimitive(),
|
||||||
|
|
||||||
|
//sender: {}, //await CustomerInvoiceParticipantPresenter(customerCustomerInvoice.senderId, context),
|
||||||
|
|
||||||
|
recipient: CustomerInvoiceParticipantPresenter(customerCustomerInvoice.recipient, context),
|
||||||
|
|
||||||
|
items: customerCustomerInvoiceItemPresenter(customerCustomerInvoice.items, context),
|
||||||
|
};
|
||||||
|
},
|
||||||
|
};
|
||||||
@ -0,0 +1 @@
|
|||||||
|
export * from "./UpdateCustomerInvoice.presenter";
|
||||||
@ -1,16 +1,16 @@
|
|||||||
import { IInvoicingContext } from "#/server/intrastructure";
|
import { IInvoicingContext } from "#/server/intrastructure";
|
||||||
import { ExpressController } from "@rdx/core";
|
import { ExpressController } from "@rdx/core";
|
||||||
import { IUpdateInvoicePresenter } from "./presenter";
|
import { IUpdateCustomerInvoicePresenter } from "./presenter";
|
||||||
|
|
||||||
export class UpdateInvoiceController extends ExpressController {
|
export class UpdateCustomerInvoiceController extends ExpressController {
|
||||||
private useCase: UpdateInvoiceUseCase2;
|
private useCase: UpdateCustomerInvoiceUseCase2;
|
||||||
private presenter: IUpdateInvoicePresenter;
|
private presenter: IUpdateCustomerInvoicePresenter;
|
||||||
private context: IInvoicingContext;
|
private context: IInvoicingContext;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
props: {
|
props: {
|
||||||
useCase: UpdateInvoiceUseCase;
|
useCase: UpdateCustomerInvoiceUseCase;
|
||||||
presenter: IUpdateInvoicePresenter;
|
presenter: IUpdateCustomerInvoicePresenter;
|
||||||
},
|
},
|
||||||
context: IInvoicingContext
|
context: IInvoicingContext
|
||||||
) {
|
) {
|
||||||
@ -23,16 +23,16 @@ export class UpdateInvoiceController extends ExpressController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async executeImpl(): Promise<any> {
|
async executeImpl(): Promise<any> {
|
||||||
const { invoiceId } = this.req.params;
|
const { customerCustomerInvoiceId } = this.req.params;
|
||||||
const request: IUpdateInvoice_DTO = this.req.body;
|
const request: IUpdateCustomerInvoice_DTO = this.req.body;
|
||||||
|
|
||||||
if (RuleValidator.validate(RuleValidator.RULE_NOT_NULL_OR_UNDEFINED, invoiceId).isFailure) {
|
if (RuleValidator.validate(RuleValidator.RULE_NOT_NULL_OR_UNDEFINED, customerCustomerInvoiceId).isFailure) {
|
||||||
return this.invalidInputError("Invoice Id param is required!");
|
return this.invalidInputError("CustomerInvoice Id param is required!");
|
||||||
}
|
}
|
||||||
|
|
||||||
const idOrError = UniqueID.create(invoiceId);
|
const idOrError = UniqueID.create(customerCustomerInvoiceId);
|
||||||
if (idOrError.isFailure) {
|
if (idOrError.isFailure) {
|
||||||
return this.invalidInputError("Invalid invoice Id param!");
|
return this.invalidInputError("Invalid customerCustomerInvoice Id param!");
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@ -46,7 +46,7 @@ export class UpdateInvoiceController extends ExpressController {
|
|||||||
|
|
||||||
switch (error.code) {
|
switch (error.code) {
|
||||||
case UseCaseError.NOT_FOUND_ERROR:
|
case UseCaseError.NOT_FOUND_ERROR:
|
||||||
return this.notFoundError("Invoice not found", error);
|
return this.notFoundError("CustomerInvoice not found", error);
|
||||||
|
|
||||||
case UseCaseError.INVALID_INPUT_DATA:
|
case UseCaseError.INVALID_INPUT_DATA:
|
||||||
return this.invalidInputError(error.message);
|
return this.invalidInputError(error.message);
|
||||||
@ -62,9 +62,9 @@ export class UpdateInvoiceController extends ExpressController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const invoice = <Invoice>result.object;
|
const customerCustomerInvoice = <CustomerInvoice>result.object;
|
||||||
|
|
||||||
return this.ok<IUpdateInvoice_Response_DTO>(this.presenter.map(invoice, this.context));
|
return this.ok<IUpdateCustomerInvoice_Response_DTO>(this.presenter.map(customerCustomerInvoice, this.context));
|
||||||
} catch (e: unknown) {
|
} catch (e: unknown) {
|
||||||
return this.fail(e as IServerError);
|
return this.fail(e as IServerError);
|
||||||
}
|
}
|
||||||
@ -1,17 +1,17 @@
|
|||||||
export type IListInvoicesRequestDTO = {}
|
export type IListCustomerInvoicesRequestDTO = {}
|
||||||
|
|
||||||
export interface ICreateInvoiceRequestDTO {
|
export interface ICreateCustomerInvoiceRequestDTO {
|
||||||
id: string;
|
id: string;
|
||||||
|
|
||||||
invoice_number: string;
|
customerCustomerInvoice_number: string;
|
||||||
invoice_series: string;
|
customerCustomerInvoice_series: string;
|
||||||
issue_date: string;
|
issue_date: string;
|
||||||
operation_date: string;
|
operation_date: string;
|
||||||
language_code: string;
|
language_code: string;
|
||||||
currency: string;
|
currency: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IUpdateInvoiceRequestDTO {
|
export interface IUpdateCustomerInvoiceRequestDTO {
|
||||||
is_freelancer: boolean;
|
is_freelancer: boolean;
|
||||||
name: string;
|
name: string;
|
||||||
trade_name: string;
|
trade_name: string;
|
||||||
@ -1,11 +1,11 @@
|
|||||||
import { IMetadataDTO, IMoneyDTO, IQuantityDTO } from "@erp/core";
|
import { IMetadataDTO, IMoneyDTO, IQuantityDTO } from "@erp/core";
|
||||||
|
|
||||||
export interface IListInvoicesResponseDTO {
|
export interface IListCustomerInvoicesResponseDTO {
|
||||||
id: string;
|
id: string;
|
||||||
|
|
||||||
invoice_status: string;
|
customerCustomerInvoice_status: string;
|
||||||
invoice_number: string;
|
customerCustomerInvoice_number: string;
|
||||||
invoice_series: string;
|
customerCustomerInvoice_series: string;
|
||||||
issue_date: string;
|
issue_date: string;
|
||||||
operation_date: string;
|
operation_date: string;
|
||||||
language_code: string;
|
language_code: string;
|
||||||
@ -17,12 +17,12 @@ export interface IListInvoicesResponseDTO {
|
|||||||
metadata?: IMetadataDTO;
|
metadata?: IMetadataDTO;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IGetInvoiceResponseDTO {
|
export interface IGetCustomerInvoiceResponseDTO {
|
||||||
id: string;
|
id: string;
|
||||||
|
|
||||||
invoice_status: string;
|
customerCustomerInvoice_status: string;
|
||||||
invoice_number: string;
|
customerCustomerInvoice_number: string;
|
||||||
invoice_series: string;
|
customerCustomerInvoice_series: string;
|
||||||
issue_date: string;
|
issue_date: string;
|
||||||
operation_date: string;
|
operation_date: string;
|
||||||
language_code: string;
|
language_code: string;
|
||||||
@ -46,12 +46,12 @@ export interface IGetInvoiceResponseDTO {
|
|||||||
metadata?: IMetadataDTO;
|
metadata?: IMetadataDTO;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ICreateInvoiceResponseDTO {
|
export interface ICreateCustomerInvoiceResponseDTO {
|
||||||
id: string;
|
id: string;
|
||||||
|
|
||||||
invoice_status: string;
|
customerCustomerInvoice_status: string;
|
||||||
invoice_number: string;
|
customerCustomerInvoice_number: string;
|
||||||
invoice_series: string;
|
customerCustomerInvoice_series: string;
|
||||||
issue_date: string;
|
issue_date: string;
|
||||||
operation_date: string;
|
operation_date: string;
|
||||||
language_code: string;
|
language_code: string;
|
||||||
@ -64,12 +64,12 @@ export interface ICreateInvoiceResponseDTO {
|
|||||||
// Inferir el tipo en TypeScript desde el esquema Zod
|
// Inferir el tipo en TypeScript desde el esquema Zod
|
||||||
//export type IUpdateAcccountResponseDTO = z.infer<typeof IUpdateAcccountResponseDTOSchema>;
|
//export type IUpdateAcccountResponseDTO = z.infer<typeof IUpdateAcccountResponseDTOSchema>;
|
||||||
|
|
||||||
export interface IUpdateInvoiceResponseDTO {
|
export interface IUpdateCustomerInvoiceResponseDTO {
|
||||||
id: string;
|
id: string;
|
||||||
|
|
||||||
invoice_status: string;
|
customerCustomerInvoice_status: string;
|
||||||
invoice_number: string;
|
customerCustomerInvoice_number: string;
|
||||||
invoice_series: string;
|
customerCustomerInvoice_series: string;
|
||||||
issue_date: string;
|
issue_date: string;
|
||||||
operation_date: string;
|
operation_date: string;
|
||||||
language_code: string;
|
language_code: string;
|
||||||
@ -1,9 +1,9 @@
|
|||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
|
||||||
export const ICreateInvoiceRequestSchema = z.object({
|
export const ICreateCustomerInvoiceRequestSchema = z.object({
|
||||||
id: z.string().uuid(),
|
id: z.string().uuid(),
|
||||||
invoice_number: z.string().min(1),
|
customerCustomerInvoice_number: z.string().min(1),
|
||||||
invoice_series: z.string().min(1),
|
customerCustomerInvoice_series: z.string().min(1),
|
||||||
issue_date: z.string().refine((date) => {
|
issue_date: z.string().refine((date) => {
|
||||||
const dateStr = z.string().regex(/^\d{4}-\d{2}-\d{2}$/, "Invalid YYYY-MM-DD format");
|
const dateStr = z.string().regex(/^\d{4}-\d{2}-\d{2}$/, "Invalid YYYY-MM-DD format");
|
||||||
return dateStr.safeParse(date).success;
|
return dateStr.safeParse(date).success;
|
||||||
@ -38,6 +38,6 @@ export const ICreateInvoiceRequestSchema = z.object({
|
|||||||
.optional(),
|
.optional(),
|
||||||
});
|
});
|
||||||
|
|
||||||
export const IUpdateInvoiceRequestSchema = z.object({});
|
export const IUpdateCustomerInvoiceRequestSchema = z.object({});
|
||||||
|
|
||||||
export const IDeleteInvoiceRequestSchema = z.object({});
|
export const IDeleteCustomerInvoiceRequestSchema = z.object({});
|
||||||
3
modules/customer-invoices/src/common/dto/index.ts
Normal file
3
modules/customer-invoices/src/common/dto/index.ts
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
export * from "./customer-invoices.request.dto";
|
||||||
|
export * from "./customer-invoices.response.dto";
|
||||||
|
export * from "./customer-invoices.schemas";
|
||||||
26
modules/customer-invoices/src/common/locales/en.json
Normal file
26
modules/customer-invoices/src/common/locales/en.json
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
{
|
||||||
|
"customerInvoices": {
|
||||||
|
"title": "Customer invoices",
|
||||||
|
"description": "Manage your customer invoices",
|
||||||
|
"list": {
|
||||||
|
"title": "Customer invoice list",
|
||||||
|
"description": "List all customer invoices"
|
||||||
|
},
|
||||||
|
"create": {
|
||||||
|
"title": "Create customer invoice",
|
||||||
|
"description": "Create a new customer invoice"
|
||||||
|
},
|
||||||
|
"edit": {
|
||||||
|
"title": "Edit customer invoice",
|
||||||
|
"description": "Edit the selected customer invoice"
|
||||||
|
},
|
||||||
|
"delete": {
|
||||||
|
"title": "Delete customer invoice",
|
||||||
|
"description": "Delete the selected customer invoice"
|
||||||
|
},
|
||||||
|
"view": {
|
||||||
|
"title": "View customer invoice",
|
||||||
|
"description": "View the details of the selected customer invoice"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"invoices": {
|
"customerInvoices": {
|
||||||
"title": "Facturas",
|
"title": "Facturas",
|
||||||
"description": "Gestiona tus facturas",
|
"description": "Gestiona tus facturas",
|
||||||
"list": {
|
"list": {
|
||||||
@ -9,7 +9,7 @@ ModuleRegistry.registerModules([AllCommunityModule]);
|
|||||||
|
|
||||||
// Core CSS
|
// Core CSS
|
||||||
import { AgGridReact } from "ag-grid-react";
|
import { AgGridReact } from "ag-grid-react";
|
||||||
import { useInvoices } from "../hooks/use-invoices";
|
import { useCustomerInvoices } from "../hooks";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fetch example Json data
|
* Fetch example Json data
|
||||||
@ -47,10 +47,10 @@ interface IRow {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Create new GridExample component
|
// Create new GridExample component
|
||||||
export const InvoicesGrid = () => {
|
export const CustomerInvoicesGrid = () => {
|
||||||
const { useList } = useInvoices();
|
//const { useList } = useCustomerInvoices();
|
||||||
|
|
||||||
const { data, isLoading, isPending, isError, error } = useList({});
|
const { data, isLoading, isPending, isError, error } = useCustomerInvoices({});
|
||||||
|
|
||||||
// Column Definitions: Defines & controls grid columns.
|
// Column Definitions: Defines & controls grid columns.
|
||||||
const [colDefs] = useState<ColDef[]>([
|
const [colDefs] = useState<ColDef[]>([
|
||||||
@ -0,0 +1,6 @@
|
|||||||
|
import { PropsWithChildren } from "react";
|
||||||
|
import { CustomerInvoicesProvider } from "../context";
|
||||||
|
|
||||||
|
export const CustomerInvoicesLayout = ({ children }: PropsWithChildren) => {
|
||||||
|
return <CustomerInvoicesProvider>{children}</CustomerInvoicesProvider>;
|
||||||
|
};
|
||||||
2
modules/customer-invoices/src/web/components/index.tsx
Normal file
2
modules/customer-invoices/src/web/components/index.tsx
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
export * from "./customer-invoices-grid";
|
||||||
|
export * from "./customer-invoices-layout";
|
||||||
@ -0,0 +1,56 @@
|
|||||||
|
import { CustomerInvoiceService } from "@erp/customerCustomerInvoices/api/domain/services/customer-invoice.service";
|
||||||
|
import { PropsWithChildren, createContext } from "react";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ────────────────────────────────────────────────────────────────────────────────
|
||||||
|
* 💡 Posibles usos del InvoicingContext
|
||||||
|
* ────────────────────────────────────────────────────────────────────────────────
|
||||||
|
* Este contexto se diseña para encapsular estado y lógica compartida dentro del
|
||||||
|
* bounded context de facturación (facturas), proporcionando acceso global a datos
|
||||||
|
* o funciones relevantes para múltiples vistas (listado, detalle, edición, etc).
|
||||||
|
*
|
||||||
|
* ✅ Usos recomendados:
|
||||||
|
*
|
||||||
|
* 1. 🔎 Gestión de filtros globales:
|
||||||
|
* - Permite que los filtros aplicados en el listado de facturas se conserven
|
||||||
|
* cuando el usuario navega a otras vistas (detalle, edición) y luego regresa.
|
||||||
|
* - Mejora la experiencia de usuario evitando la necesidad de reestablecer filtros.
|
||||||
|
*
|
||||||
|
* 2. 🛡️ Gestión de permisos o configuración de acciones disponibles:
|
||||||
|
* - Permite definir qué acciones están habilitadas para el usuario actual
|
||||||
|
* (crear, editar, eliminar).
|
||||||
|
* - Útil para mostrar u ocultar botones de acción en diferentes pantallas.
|
||||||
|
*
|
||||||
|
* 3. 🧭 Control del layout:
|
||||||
|
* - Si el layout tiene elementos dinámicos (tabs, breadcrumb, loading global),
|
||||||
|
* este contexto puede coordinar su estado desde componentes hijos.
|
||||||
|
* - Ejemplo: seleccionar una pestaña activa que aplica en todas las subrutas.
|
||||||
|
*
|
||||||
|
* 4. 📦 Cacheo liviano de datos compartidos:
|
||||||
|
* - Puede almacenar la última factura abierta, borradores de edición,
|
||||||
|
* o referencias temporales para operaciones CRUD sin tener que usar la URL.
|
||||||
|
*
|
||||||
|
* 5. 🚀 Coordinación de side-effects:
|
||||||
|
* - Permite exponer funciones comunes como `refetch`, `resetFilters`,
|
||||||
|
* o `notifyInvoiceChanged`, usadas desde cualquier subcomponente del dominio.
|
||||||
|
*
|
||||||
|
* ⚠️ Alternativas:
|
||||||
|
* - Si el estado compartido es muy mutable, grande o requiere persistencia,
|
||||||
|
* podría ser preferible usar Zustand o Redux Toolkit.
|
||||||
|
* - No usar contextos para valores que cambian frecuentemente en tiempo real,
|
||||||
|
* ya que pueden causar renders innecesarios.
|
||||||
|
*
|
||||||
|
* ────────────────────────────────────────────────────────────────────────────────
|
||||||
|
*/
|
||||||
|
|
||||||
|
export type CustomerInvoicesContextType = {};
|
||||||
|
|
||||||
|
export type CustomerInvoicesContextParamsType = {
|
||||||
|
service: CustomerInvoiceService;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const CustomerInvoicesContext = createContext<CustomerInvoicesContextType>({});
|
||||||
|
|
||||||
|
export const CustomerInvoicesProvider = ({ children }: PropsWithChildren) => {
|
||||||
|
return <CustomerInvoicesContext.Provider value={{}}>{children}</CustomerInvoicesContext.Provider>;
|
||||||
|
};
|
||||||
1
modules/customer-invoices/src/web/context/index.ts
Normal file
1
modules/customer-invoices/src/web/context/index.ts
Normal file
@ -0,0 +1 @@
|
|||||||
|
export * from "./customer-invoices-context";
|
||||||
@ -0,0 +1,58 @@
|
|||||||
|
import { ModuleClientParams } from "@erp/core/client";
|
||||||
|
import { lazy } from "react";
|
||||||
|
import { Outlet, RouteObject } from "react-router-dom";
|
||||||
|
|
||||||
|
// Lazy load components
|
||||||
|
const CustomerInvoicesLayout = lazy(() =>
|
||||||
|
import("./components").then((m) => ({ default: m.CustomerInvoicesLayout }))
|
||||||
|
);
|
||||||
|
const CustomerInvoicesList = lazy(() => import("./pages").then((m) => ({ default: m.CustomerInvoicesList })));
|
||||||
|
|
||||||
|
//const LogoutPage = lazy(() => import("./app").then((m) => ({ default: m.LogoutPage })));
|
||||||
|
|
||||||
|
/*const DealerLayout = lazy(() => import("./app").then((m) => ({ default: m.DealerLayout })));
|
||||||
|
const DealersList = lazy(() => import("./app").then((m) => ({ default: m.DealersList })));
|
||||||
|
|
||||||
|
const LoginPageWithLanguageSelector = lazy(() =>
|
||||||
|
import("./app").then((m) => ({ default: m.LoginPageWithLanguageSelector }))
|
||||||
|
);
|
||||||
|
|
||||||
|
const CustomerInvoiceCreate = lazy(() => import("./app").then((m) => ({ default: m.CustomerInvoiceCreate })));
|
||||||
|
const CustomerInvoiceEdit = lazy(() => import("./app").then((m) => ({ default: m.CustomerInvoiceEdit })));
|
||||||
|
const SettingsEditor = lazy(() => import("./app").then((m) => ({ default: m.SettingsEditor })));
|
||||||
|
const SettingsLayout = lazy(() => import("./app").then((m) => ({ default: m.SettingsLayout })));
|
||||||
|
const CatalogLayout = lazy(() => import("./app").then((m) => ({ default: m.CatalogLayout })));
|
||||||
|
const CatalogList = lazy(() => import("./app").then((m) => ({ default: m.CatalogList })));
|
||||||
|
const DashboardPage = lazy(() => import("./app").then((m) => ({ default: m.DashboardPage })));
|
||||||
|
const CustomerInvoicesLayout = lazy(() => import("./app").then((m) => ({ default: m.CustomerInvoicesLayout })));
|
||||||
|
const CustomerInvoicesList = lazy(() => import("./app").then((m) => ({ default: m.CustomerInvoicesList })));*/
|
||||||
|
|
||||||
|
export const CustomerInvoiceRoutes = (params: ModuleClientParams): RouteObject[] => {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
path: "*",
|
||||||
|
element: (
|
||||||
|
<CustomerInvoicesLayout>
|
||||||
|
<Outlet context={params} />
|
||||||
|
</CustomerInvoicesLayout>
|
||||||
|
),
|
||||||
|
children: [
|
||||||
|
{ path: "", element: <CustomerInvoicesList /> }, // index
|
||||||
|
{ path: "list", element: <CustomerInvoicesList /> },
|
||||||
|
{ path: "*", element: <CustomerInvoicesList /> },
|
||||||
|
|
||||||
|
//
|
||||||
|
/*{ path: "create", element: <CustomerInvoicesList /> },
|
||||||
|
{ path: ":id", element: <CustomerInvoicesList /> },
|
||||||
|
{ path: ":id/edit", element: <CustomerInvoicesList /> },
|
||||||
|
{ path: ":id/delete", element: <CustomerInvoicesList /> },
|
||||||
|
{ path: ":id/view", element: <CustomerInvoicesList /> },
|
||||||
|
{ path: ":id/print", element: <CustomerInvoicesList /> },
|
||||||
|
{ path: ":id/email", element: <CustomerInvoicesList /> },
|
||||||
|
{ path: ":id/download", element: <CustomerInvoicesList /> },
|
||||||
|
{ path: ":id/duplicate", element: <CustomerInvoicesList /> },
|
||||||
|
{ path: ":id/preview", element: <CustomerInvoicesList /> },*/
|
||||||
|
],
|
||||||
|
},
|
||||||
|
];
|
||||||
|
};
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user