Facturas de cliente
This commit is contained in:
parent
6c472c21aa
commit
b87082754b
@ -27,7 +27,7 @@
|
|||||||
"@types/glob": "^8.1.0",
|
"@types/glob": "^8.1.0",
|
||||||
"@types/jest": "^29.5.14",
|
"@types/jest": "^29.5.14",
|
||||||
"@types/jsonwebtoken": "^9.0.8",
|
"@types/jsonwebtoken": "^9.0.8",
|
||||||
"@types/luxon": "^3.4.2",
|
"@types/luxon": "^3.6.2",
|
||||||
"@types/node": "^22.15.12",
|
"@types/node": "^22.15.12",
|
||||||
"@types/passport": "^1.0.16",
|
"@types/passport": "^1.0.16",
|
||||||
"@types/passport-jwt": "^4.0.1",
|
"@types/passport-jwt": "^4.0.1",
|
||||||
@ -54,7 +54,7 @@
|
|||||||
"helmet": "^8.0.0",
|
"helmet": "^8.0.0",
|
||||||
"http": "0.0.1-security",
|
"http": "0.0.1-security",
|
||||||
"jsonwebtoken": "^9.0.2",
|
"jsonwebtoken": "^9.0.2",
|
||||||
"luxon": "^3.5.0",
|
"luxon": "^3.6.1",
|
||||||
"module-alias": "^2.2.3",
|
"module-alias": "^2.2.3",
|
||||||
"mysql2": "^3.12.0",
|
"mysql2": "^3.12.0",
|
||||||
"passport": "^0.7.0",
|
"passport": "^0.7.0",
|
||||||
@ -75,14 +75,9 @@
|
|||||||
"node": ">=22"
|
"node": ">=22"
|
||||||
},
|
},
|
||||||
"tsup": {
|
"tsup": {
|
||||||
"entry": [
|
"entry": ["src/index.ts"],
|
||||||
"src/index.ts"
|
|
||||||
],
|
|
||||||
"outDir": "dist",
|
"outDir": "dist",
|
||||||
"format": [
|
"format": ["esm", "cjs"],
|
||||||
"esm",
|
|
||||||
"cjs"
|
|
||||||
],
|
|
||||||
"target": "es2020",
|
"target": "es2020",
|
||||||
"sourcemap": true,
|
"sourcemap": true,
|
||||||
"clean": true,
|
"clean": true,
|
||||||
|
|||||||
@ -105,7 +105,8 @@ const server = http
|
|||||||
|
|
||||||
// Manejo de promesas no capturadas
|
// Manejo de promesas no capturadas
|
||||||
process.on("unhandledRejection", (reason: any, promise: Promise<any>) => {
|
process.on("unhandledRejection", (reason: any, promise: Promise<any>) => {
|
||||||
logger.error(`❌ Unhandled rejection at:", ${promise}, "reason:", ${reason}`);
|
const error = `❌ Unhandled rejection at:", ${promise}, "reason:", ${reason}`;
|
||||||
|
logger.error(error);
|
||||||
// Dependiendo de la aplicación, podrías desear una salida total o un cierre controlado
|
// Dependiendo de la aplicación, podrías desear una salida total o un cierre controlado
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
});
|
});
|
||||||
|
|||||||
6
modules/core/src/api/errors/duplicate-entity-error.ts
Normal file
6
modules/core/src/api/errors/duplicate-entity-error.ts
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
export class DuplicateEntityError extends Error {
|
||||||
|
constructor(entity: string, id: string) {
|
||||||
|
super(`Entity '${entity}' with ID '${id}' already exists.`);
|
||||||
|
this.name = "DuplicateEntityError";
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -9,6 +9,7 @@ import {
|
|||||||
import { ApiError } from "./api-error";
|
import { ApiError } from "./api-error";
|
||||||
import { ConflictApiError } from "./conflict-api-error";
|
import { ConflictApiError } from "./conflict-api-error";
|
||||||
import { DomainValidationError } from "./domain-validation-error";
|
import { DomainValidationError } from "./domain-validation-error";
|
||||||
|
import { DuplicateEntityError } from "./duplicate-entity-error";
|
||||||
import { ForbiddenApiError } from "./forbidden-api-error";
|
import { ForbiddenApiError } from "./forbidden-api-error";
|
||||||
import { InternalApiError } from "./internal-api-error";
|
import { InternalApiError } from "./internal-api-error";
|
||||||
import { NotFoundApiError } from "./not-found-api-error";
|
import { NotFoundApiError } from "./not-found-api-error";
|
||||||
@ -74,6 +75,10 @@ export const errorMapper = {
|
|||||||
return new ValidationApiError(error.detail, [{ path: error.field, message: error.detail }]);
|
return new ValidationApiError(error.detail, [{ path: error.field, message: error.detail }]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (error instanceof DuplicateEntityError) {
|
||||||
|
return new ConflictApiError(error.message);
|
||||||
|
}
|
||||||
|
|
||||||
// 3. 🔍 Errores individuales de validación
|
// 3. 🔍 Errores individuales de validación
|
||||||
if (
|
if (
|
||||||
message.includes("invalid") ||
|
message.includes("invalid") ||
|
||||||
|
|||||||
@ -1,4 +1,12 @@
|
|||||||
|
export * from "./api-error";
|
||||||
|
export * from "./conflict-api-error";
|
||||||
export * from "./domain-validation-error";
|
export * from "./domain-validation-error";
|
||||||
|
export * from "./duplicate-entity-error";
|
||||||
export * from "./error-mapper";
|
export * from "./error-mapper";
|
||||||
|
export * from "./forbidden-api-error";
|
||||||
|
export * from "./internal-api-error";
|
||||||
|
export * from "./not-found-api-error";
|
||||||
|
export * from "./unauthorized-api-error";
|
||||||
|
export * from "./unavailable-api-error";
|
||||||
export * from "./validation-api-error";
|
export * from "./validation-api-error";
|
||||||
export * from "./validation-error-collection";
|
export * from "./validation-error-collection";
|
||||||
|
|||||||
@ -41,6 +41,7 @@ export const validateRequest = <T extends "body" | "query" | "params">(
|
|||||||
): RequestHandler => {
|
): RequestHandler => {
|
||||||
return async (req, res, next) => {
|
return async (req, res, next) => {
|
||||||
console.debug(`Validating request ${source} with schema.`);
|
console.debug(`Validating request ${source} with schema.`);
|
||||||
|
console.debug(req[source]);
|
||||||
const result = schema.safeParse(req[source]);
|
const result = schema.safeParse(req[source]);
|
||||||
|
|
||||||
if (!result.success) {
|
if (!result.success) {
|
||||||
|
|||||||
@ -41,7 +41,8 @@ export abstract class SequelizeMapper<
|
|||||||
source: TModel[],
|
source: TModel[],
|
||||||
params?: MapperParamsType
|
params?: MapperParamsType
|
||||||
): Result<Collection<TEntity>, Error> {
|
): Result<Collection<TEntity>, Error> {
|
||||||
return this.mapArrayAndCountToDomain(source, source.length, params);
|
const items = source ?? [];
|
||||||
|
return this.mapArrayAndCountToDomain(items, items.length, params);
|
||||||
}
|
}
|
||||||
|
|
||||||
public mapArrayAndCountToDomain(
|
public mapArrayAndCountToDomain(
|
||||||
@ -49,12 +50,14 @@ export abstract class SequelizeMapper<
|
|||||||
totalCount: number,
|
totalCount: number,
|
||||||
params?: MapperParamsType
|
params?: MapperParamsType
|
||||||
): Result<Collection<TEntity>, Error> {
|
): Result<Collection<TEntity>, Error> {
|
||||||
|
const _source = source ?? [];
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (source.length === 0) {
|
if (_source.length === 0) {
|
||||||
return Result.ok(new Collection([], totalCount));
|
return Result.ok(new Collection([], totalCount));
|
||||||
}
|
}
|
||||||
|
|
||||||
const items = source.map(
|
const items = _source.map(
|
||||||
(value, index) => this.mapToDomain(value, { index, ...params }).data
|
(value, index) => this.mapToDomain(value, { index, ...params }).data
|
||||||
);
|
);
|
||||||
return Result.ok(new Collection(items, totalCount));
|
return Result.ok(new Collection(items, totalCount));
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { ITransactionManager } from "@erp/core/api";
|
import { DuplicateEntityError, ITransactionManager } from "@erp/core/api";
|
||||||
import { CreateCustomerInvoiceCommandDTO } from "@erp/customer-invoices/common/dto";
|
import { CreateCustomerInvoiceCommandDTO } from "@erp/customer-invoices/common/dto";
|
||||||
import { Result } from "@repo/rdx-utils";
|
import { Result } from "@repo/rdx-utils";
|
||||||
import { Transaction } from "sequelize";
|
import { Transaction } from "sequelize";
|
||||||
@ -8,19 +8,21 @@ import { CreateCustomerInvoicesPresenter } from "./presenter";
|
|||||||
|
|
||||||
export class CreateCustomerInvoiceUseCase {
|
export class CreateCustomerInvoiceUseCase {
|
||||||
constructor(
|
constructor(
|
||||||
private readonly customerInvoiceService: ICustomerInvoiceService,
|
private readonly service: ICustomerInvoiceService,
|
||||||
private readonly transactionManager: ITransactionManager,
|
private readonly transactionManager: ITransactionManager,
|
||||||
private readonly presenter: CreateCustomerInvoicesPresenter
|
private readonly presenter: CreateCustomerInvoicesPresenter
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
public execute(dto: CreateCustomerInvoiceCommandDTO) {
|
public execute(dto: CreateCustomerInvoiceCommandDTO) {
|
||||||
const invoicePropOrError = mapDTOToCustomerInvoiceProps(dto);
|
const invoicePropsOrError = mapDTOToCustomerInvoiceProps(dto);
|
||||||
|
|
||||||
if (invoicePropOrError.isFailure) {
|
if (invoicePropsOrError.isFailure) {
|
||||||
return Result.fail(invoicePropOrError.error);
|
return Result.fail(invoicePropsOrError.error);
|
||||||
}
|
}
|
||||||
|
|
||||||
const invoiceOrError = this.customerInvoiceService.build(invoicePropOrError.data);
|
const { props, id } = invoicePropsOrError.data;
|
||||||
|
|
||||||
|
const invoiceOrError = this.service.build(props, id);
|
||||||
|
|
||||||
if (invoiceOrError.isFailure) {
|
if (invoiceOrError.isFailure) {
|
||||||
return Result.fail(invoiceOrError.error);
|
return Result.fail(invoiceOrError.error);
|
||||||
@ -29,13 +31,27 @@ export class CreateCustomerInvoiceUseCase {
|
|||||||
const newInvoice = invoiceOrError.data;
|
const newInvoice = invoiceOrError.data;
|
||||||
|
|
||||||
return this.transactionManager.complete(async (transaction: Transaction) => {
|
return this.transactionManager.complete(async (transaction: Transaction) => {
|
||||||
const result = await this.customerInvoiceService.save(newInvoice, transaction);
|
try {
|
||||||
if (result.isFailure) {
|
const duplicateCheck = await this.service.existsById(id, transaction);
|
||||||
return Result.fail(result.error);
|
|
||||||
}
|
|
||||||
|
|
||||||
const viewDTO = this.presenter.toDTO(newInvoice);
|
if (duplicateCheck.isFailure) {
|
||||||
return Result.ok(viewDTO);
|
return Result.fail(duplicateCheck.error);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (duplicateCheck.data) {
|
||||||
|
return Result.fail(new DuplicateEntityError("CustomerInvoice", id.toString()));
|
||||||
|
}
|
||||||
|
|
||||||
|
const result = await this.service.save(newInvoice, transaction);
|
||||||
|
if (result.isFailure) {
|
||||||
|
return Result.fail(result.error);
|
||||||
|
}
|
||||||
|
|
||||||
|
const viewDTO = this.presenter.toDTO(newInvoice);
|
||||||
|
return Result.ok(viewDTO);
|
||||||
|
} catch (error: unknown) {
|
||||||
|
return Result.fail(error as Error);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,24 +1,34 @@
|
|||||||
import { UniqueID } from "@/core/common/domain";
|
import { ITransactionManager } from "@erp/core/api";
|
||||||
import { ITransactionManager } from "@/core/common/infrastructure/database";
|
import { GetCustomerInvoiceByIdQueryDTO } from "@erp/customer-invoices/common/dto";
|
||||||
import { logger } from "@/lib/logger";
|
import { UniqueID } from "@repo/rdx-ddd";
|
||||||
import { Result } from "@repo/rdx-utils";
|
import { Result } from "@repo/rdx-utils";
|
||||||
import { CustomerInvoice, ICustomerInvoiceService } from "../domain";
|
import { ICustomerInvoiceService } from "../../domain";
|
||||||
|
import { GetCustomerInvoicePresenter } from "./presenter";
|
||||||
|
|
||||||
export class GetCustomerInvoiceUseCase {
|
export class GetCustomerInvoiceUseCase {
|
||||||
constructor(
|
constructor(
|
||||||
private readonly customerInvoiceService: ICustomerInvoiceService,
|
private readonly service: ICustomerInvoiceService,
|
||||||
private readonly transactionManager: ITransactionManager
|
private readonly transactionManager: ITransactionManager,
|
||||||
|
private readonly presenter: GetCustomerInvoicePresenter
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
public execute(customerInvoiceID: UniqueID): Promise<Result<CustomerInvoice, Error>> {
|
public execute(dto: GetCustomerInvoiceByIdQueryDTO) {
|
||||||
|
const idOrError = UniqueID.create(dto.id);
|
||||||
|
|
||||||
|
if (idOrError.isFailure) {
|
||||||
|
return Result.fail(idOrError.error);
|
||||||
|
}
|
||||||
|
|
||||||
return this.transactionManager.complete(async (transaction) => {
|
return this.transactionManager.complete(async (transaction) => {
|
||||||
try {
|
try {
|
||||||
return await this.customerInvoiceService.findCustomerInvoiceById(
|
const invoiceOrError = await this.service.getById(idOrError.data, transaction);
|
||||||
customerInvoiceID,
|
if (invoiceOrError.isFailure) {
|
||||||
transaction
|
return Result.fail(invoiceOrError.error);
|
||||||
);
|
}
|
||||||
|
|
||||||
|
const getDTO = this.presenter.toDTO(invoiceOrError.data);
|
||||||
|
return Result.ok(getDTO);
|
||||||
} catch (error: unknown) {
|
} catch (error: unknown) {
|
||||||
logger.error(error as Error);
|
|
||||||
return Result.fail(error as Error);
|
return Result.fail(error as Error);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@ -1 +1,2 @@
|
|||||||
export * from "./get-customer-invoice.use-case";
|
export * from "./get-customer-invoice.use-case";
|
||||||
|
export * from "./presenter";
|
||||||
|
|||||||
@ -1,25 +1,31 @@
|
|||||||
import { IGetCustomerInvoiceResponseDTO } from "../../../../common/dto";
|
import { GetCustomerInvoiceResultDTO } from "../../../../common/dto";
|
||||||
import { CustomerInvoice, CustomerInvoiceItem } from "../../../domain";
|
import { CustomerInvoice } from "../../../domain";
|
||||||
|
|
||||||
export interface IGetCustomerInvoicePresenter {
|
export interface GetCustomerInvoicePresenter {
|
||||||
toDTO: (customerInvoice: CustomerInvoice) => IGetCustomerInvoiceResponseDTO;
|
toDTO: (customerInvoice: CustomerInvoice) => GetCustomerInvoiceResultDTO;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const getCustomerInvoicePresenter: IGetCustomerInvoicePresenter = {
|
export const getCustomerInvoicePresenter: GetCustomerInvoicePresenter = {
|
||||||
toDTO: (customerInvoice: CustomerInvoice): IGetCustomerInvoiceResponseDTO => ({
|
toDTO: (customerInvoice: CustomerInvoice): GetCustomerInvoiceResultDTO => ({
|
||||||
id: customerInvoice.id.toPrimitive(),
|
id: customerInvoice.id.toPrimitive(),
|
||||||
|
|
||||||
customerInvoice_status: customerInvoice.status.toString(),
|
invoice_status: customerInvoice.status.toString(),
|
||||||
customerInvoice_number: customerInvoice.invoiceNumber.toString(),
|
invoice_number: customerInvoice.invoiceNumber.toString(),
|
||||||
customerInvoice_series: customerInvoice.invoiceSeries.toString(),
|
invoice_series: customerInvoice.invoiceSeries.toString(),
|
||||||
issue_date: customerInvoice.issueDate.toDateString(),
|
issue_date: customerInvoice.issueDate.toDateString(),
|
||||||
operation_date: customerInvoice.operationDate.toDateString(),
|
operation_date: customerInvoice.operationDate.toDateString(),
|
||||||
language_code: "ES",
|
language_code: "ES",
|
||||||
currency: customerInvoice.customerInvoiceCurrency.toString(),
|
currency: customerInvoice.currency,
|
||||||
subtotal: customerInvoice.calculateSubtotal().toPrimitive(),
|
|
||||||
total: customerInvoice.calculateTotal().toPrimitive(),
|
|
||||||
|
|
||||||
items:
|
metadata: {
|
||||||
|
entity: "customer-invoices",
|
||||||
|
},
|
||||||
|
|
||||||
|
//subtotal: customerInvoice.calculateSubtotal().toPrimitive(),
|
||||||
|
|
||||||
|
//total: customerInvoice.calculateTotal().toPrimitive(),
|
||||||
|
|
||||||
|
/*items:
|
||||||
customerInvoice.items.size() > 0
|
customerInvoice.items.size() > 0
|
||||||
? customerInvoice.items.map((item: CustomerInvoiceItem) => ({
|
? customerInvoice.items.map((item: CustomerInvoiceItem) => ({
|
||||||
description: item.description.toString(),
|
description: item.description.toString(),
|
||||||
@ -30,7 +36,7 @@ export const getCustomerInvoicePresenter: IGetCustomerInvoicePresenter = {
|
|||||||
//tax_amount: item.calculateTaxAmount().toPrimitive(),
|
//tax_amount: item.calculateTaxAmount().toPrimitive(),
|
||||||
total: item.calculateTotal().toPrimitive(),
|
total: item.calculateTotal().toPrimitive(),
|
||||||
}))
|
}))
|
||||||
: [],
|
: [],*/
|
||||||
|
|
||||||
//sender: {}, //await CustomerInvoiceParticipantPresenter(customerInvoice.senderId, context),
|
//sender: {}, //await CustomerInvoiceParticipantPresenter(customerInvoice.senderId, context),
|
||||||
|
|
||||||
@ -1,5 +1,5 @@
|
|||||||
import { ValidationErrorCollection, ValidationErrorDetail } from "@erp/core/api";
|
import { ValidationErrorCollection, ValidationErrorDetail } from "@erp/core/api";
|
||||||
import { UtcDate } from "@repo/rdx-ddd";
|
import { UniqueID, UtcDate } from "@repo/rdx-ddd";
|
||||||
import { Result } from "@repo/rdx-utils";
|
import { Result } from "@repo/rdx-utils";
|
||||||
import { CreateCustomerInvoiceCommandDTO } from "../../../common/dto";
|
import { CreateCustomerInvoiceCommandDTO } from "../../../common/dto";
|
||||||
import {
|
import {
|
||||||
@ -16,16 +16,15 @@ import { mapDTOToCustomerInvoiceItemsProps } from "./map-dto-to-customer-invoice
|
|||||||
* No construye directamente el agregado.
|
* No construye directamente el agregado.
|
||||||
*
|
*
|
||||||
* @param dto - DTO con los datos de la factura de cliente
|
* @param dto - DTO con los datos de la factura de cliente
|
||||||
* @returns CustomerInvoiceProps - Las propiedades para crear una factura de cliente o error
|
* @returns
|
||||||
|
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export function mapDTOToCustomerInvoiceProps(
|
export function mapDTOToCustomerInvoiceProps(dto: CreateCustomerInvoiceCommandDTO) {
|
||||||
dto: CreateCustomerInvoiceCommandDTO
|
|
||||||
): Result<CustomerInvoiceProps, Error> {
|
|
||||||
const errors: ValidationErrorDetail[] = [];
|
const errors: ValidationErrorDetail[] = [];
|
||||||
|
|
||||||
//const invoiceId = extractOrPushError(UniqueID.create(dto.id), "invoice_id", errors);
|
const invoiceId = extractOrPushError(UniqueID.create(dto.id), "id", errors);
|
||||||
|
|
||||||
const invoiceNumber = extractOrPushError(
|
const invoiceNumber = extractOrPushError(
|
||||||
CustomerInvoiceNumber.create(dto.invoice_number),
|
CustomerInvoiceNumber.create(dto.invoice_number),
|
||||||
@ -66,7 +65,7 @@ export function mapDTOToCustomerInvoiceProps(
|
|||||||
currency,
|
currency,
|
||||||
};
|
};
|
||||||
|
|
||||||
return Result.ok(invoiceProps);
|
return Result.ok({ id: invoiceId!, props: invoiceProps });
|
||||||
|
|
||||||
/*if (hasNoUndefinedFields(invoiceProps)) {
|
/*if (hasNoUndefinedFields(invoiceProps)) {
|
||||||
const invoiceOrError = CustomerInvoice.create(invoiceProps, invoiceId);
|
const invoiceOrError = CustomerInvoice.create(invoiceProps, invoiceId);
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
export * from "./create-customer-invoice";
|
export * from "./create-customer-invoice";
|
||||||
//export * from "./delete-customer-invoice";
|
//export * from "./delete-customer-invoice";
|
||||||
//export * from "./get-customer-invoice";
|
export * from "./get-customer-invoice";
|
||||||
export * from "./list-customer-invoices";
|
export * from "./list-customer-invoices";
|
||||||
//export * from "./update-customer-invoice";
|
//export * from "./update-customer-invoice";
|
||||||
|
|||||||
@ -16,10 +16,7 @@ export class ListCustomerInvoicesUseCase {
|
|||||||
public execute(criteria: Criteria): Promise<Result<ListCustomerInvoicesResultDTO, Error>> {
|
public execute(criteria: Criteria): Promise<Result<ListCustomerInvoicesResultDTO, Error>> {
|
||||||
return this.transactionManager.complete(async (transaction: Transaction) => {
|
return this.transactionManager.complete(async (transaction: Transaction) => {
|
||||||
try {
|
try {
|
||||||
const result = await this.customerInvoiceService.findCustomerInvoices(
|
const result = await this.customerInvoiceService.findByCriteria(criteria, transaction);
|
||||||
criteria,
|
|
||||||
transaction
|
|
||||||
);
|
|
||||||
|
|
||||||
if (result.isFailure) {
|
if (result.isFailure) {
|
||||||
return Result.fail(result.error);
|
return Result.fail(result.error);
|
||||||
|
|||||||
@ -1,20 +1,20 @@
|
|||||||
import { ListCustomerInvoicesViewDTO } from "@erp/customer-invoices/common/dto";
|
|
||||||
import { Criteria } from "@repo/rdx-criteria/server";
|
import { Criteria } from "@repo/rdx-criteria/server";
|
||||||
import { Collection } from "@repo/rdx-utils";
|
import { Collection } from "@repo/rdx-utils";
|
||||||
|
import { ListCustomerInvoicesResultDTO } from "../../../../common/dto";
|
||||||
import { CustomerInvoice } from "../../../domain";
|
import { CustomerInvoice } from "../../../domain";
|
||||||
|
|
||||||
export interface ListCustomerInvoicesPresenter {
|
export interface ListCustomerInvoicesPresenter {
|
||||||
toDTO: (
|
toDTO: (
|
||||||
customerInvoices: Collection<CustomerInvoice>,
|
customerInvoices: Collection<CustomerInvoice>,
|
||||||
criteria: Criteria
|
criteria: Criteria
|
||||||
) => ListCustomerInvoicesViewDTO;
|
) => ListCustomerInvoicesResultDTO;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const listCustomerInvoicesPresenter: ListCustomerInvoicesPresenter = {
|
export const listCustomerInvoicesPresenter: ListCustomerInvoicesPresenter = {
|
||||||
toDTO: (
|
toDTO: (
|
||||||
customerInvoices: Collection<CustomerInvoice>,
|
customerInvoices: Collection<CustomerInvoice>,
|
||||||
criteria: Criteria
|
criteria: Criteria
|
||||||
): ListCustomerInvoicesViewDTO => {
|
): ListCustomerInvoicesResultDTO => {
|
||||||
const items = customerInvoices.map((invoice) => {
|
const items = customerInvoices.map((invoice) => {
|
||||||
return {
|
return {
|
||||||
id: invoice.id.toPrimitive(),
|
id: invoice.id.toPrimitive(),
|
||||||
@ -25,7 +25,7 @@ export const listCustomerInvoicesPresenter: ListCustomerInvoicesPresenter = {
|
|||||||
issue_date: invoice.issueDate.toISOString(),
|
issue_date: invoice.issueDate.toISOString(),
|
||||||
operation_date: invoice.operationDate.toISOString(),
|
operation_date: invoice.operationDate.toISOString(),
|
||||||
language_code: "ES",
|
language_code: "ES",
|
||||||
currency: invoice.customerInvoiceCurrency.toString(),
|
currency: "EUR",
|
||||||
|
|
||||||
subtotal_price: invoice.calculateSubtotal().toPrimitive(),
|
subtotal_price: invoice.calculateSubtotal().toPrimitive(),
|
||||||
total_price: invoice.calculateTotal().toPrimitive(),
|
total_price: invoice.calculateTotal().toPrimitive(),
|
||||||
|
|||||||
@ -2,12 +2,15 @@ import { SequelizeTransactionManager } from "@erp/core/api";
|
|||||||
import { Sequelize } from "sequelize";
|
import { Sequelize } from "sequelize";
|
||||||
import { CreateCustomerInvoiceUseCase, CreateCustomerInvoicesPresenter } from "../../application/";
|
import { CreateCustomerInvoiceUseCase, CreateCustomerInvoicesPresenter } from "../../application/";
|
||||||
import { CustomerInvoiceService } from "../../domain";
|
import { CustomerInvoiceService } from "../../domain";
|
||||||
import { CustomerInvoiceRepository, customerInvoiceMapper } from "../../infrastructure";
|
import { CustomerInvoiceMapper, CustomerInvoiceRepository } from "../../infrastructure";
|
||||||
import { CreateCustomerInvoiceController } from "./create-customer-invoice";
|
import { CreateCustomerInvoiceController } from "./create-customer-invoice";
|
||||||
|
|
||||||
export const buildCreateCustomerInvoicesController = (database: Sequelize) => {
|
export const buildCreateCustomerInvoicesController = (database: Sequelize) => {
|
||||||
const transactionManager = new SequelizeTransactionManager(database);
|
const transactionManager = new SequelizeTransactionManager(database);
|
||||||
const customerInvoiceRepository = new CustomerInvoiceRepository(database, customerInvoiceMapper);
|
const customerInvoiceRepository = new CustomerInvoiceRepository(
|
||||||
|
database,
|
||||||
|
new CustomerInvoiceMapper()
|
||||||
|
);
|
||||||
const customerInvoiceService = new CustomerInvoiceService(customerInvoiceRepository);
|
const customerInvoiceService = new CustomerInvoiceService(customerInvoiceRepository);
|
||||||
const presenter = new CreateCustomerInvoicesPresenter();
|
const presenter = new CreateCustomerInvoicesPresenter();
|
||||||
|
|
||||||
|
|||||||
@ -1,47 +1,30 @@
|
|||||||
import { ExpressController } from "@erp/core/api";
|
import { ExpressController, errorMapper } from "@erp/core/api";
|
||||||
import { UniqueID } from "@repo/rdx-ddd";
|
|
||||||
import { GetCustomerInvoiceUseCase } from "../../application";
|
import { GetCustomerInvoiceUseCase } from "../../application";
|
||||||
import { IGetCustomerInvoicePresenter } from "./presenter";
|
|
||||||
|
|
||||||
export class GetCustomerInvoiceController extends ExpressController {
|
export class GetCustomerInvoiceController extends ExpressController {
|
||||||
public constructor(
|
public constructor(private readonly getCustomerInvoice: GetCustomerInvoiceUseCase) {
|
||||||
private readonly getCustomerInvoice: GetCustomerInvoiceUseCase,
|
|
||||||
private readonly presenter: IGetCustomerInvoicePresenter
|
|
||||||
) {
|
|
||||||
super();
|
super();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected async executeImpl() {
|
protected async executeImpl() {
|
||||||
const { customerInvoiceId } = this.req.params;
|
const { id } = this.req.params;
|
||||||
|
|
||||||
// Validar ID
|
/*
|
||||||
const customerInvoiceIdOrError = UniqueID.create(customerInvoiceId);
|
const user = this.req.user; // asumimos middleware authenticateJWT inyecta user
|
||||||
if (customerInvoiceIdOrError.isFailure)
|
|
||||||
return this.invalidInputError("CustomerInvoice ID not valid");
|
|
||||||
|
|
||||||
const customerInvoiceOrError = await this.getCustomerInvoice.execute(
|
if (!user || !user.companyId) {
|
||||||
customerInvoiceIdOrError.data
|
this.unauthorized(res, "Unauthorized: user or company not found");
|
||||||
);
|
return;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
if (customerInvoiceOrError.isFailure) {
|
const result = await this.getCustomerInvoice.execute({ id });
|
||||||
return this.handleError(customerInvoiceOrError.error);
|
|
||||||
|
if (result.isFailure) {
|
||||||
|
const apiError = errorMapper.toApiError(result.error);
|
||||||
|
return this.handleApiError(apiError);
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.ok(this.presenter.toDTO(customerInvoiceOrError.data));
|
return this.ok(result.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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,19 +1,21 @@
|
|||||||
import { SequelizeTransactionManager } from "@erp/core/api";
|
import { SequelizeTransactionManager } from "@erp/core/api";
|
||||||
import { Sequelize } from "sequelize";
|
import { Sequelize } from "sequelize";
|
||||||
|
import { GetCustomerInvoiceUseCase, getCustomerInvoicePresenter } from "../../application";
|
||||||
import { CustomerInvoiceService } from "../../domain";
|
import { CustomerInvoiceService } from "../../domain";
|
||||||
import { CustomerInvoiceRepository, customerInvoiceMapper } from "../../infrastructure";
|
import { CustomerInvoiceRepository, customerInvoiceMapper } from "../../infrastructure";
|
||||||
|
|
||||||
import { GetCustomerInvoiceUseCase } from "../../application";
|
|
||||||
import { GetCustomerInvoiceController } from "./get-invoice.controller";
|
import { GetCustomerInvoiceController } from "./get-invoice.controller";
|
||||||
import { getCustomerInvoicePresenter } from "./presenter";
|
|
||||||
|
|
||||||
export const buildGetCustomerInvoiceController = (database: Sequelize) => {
|
export const buildGetCustomerInvoiceController = (database: Sequelize) => {
|
||||||
const transactionManager = new SequelizeTransactionManager(database);
|
const transactionManager = new SequelizeTransactionManager(database);
|
||||||
const customerInvoiceRepository = new CustomerInvoiceRepository(database, customerInvoiceMapper);
|
const customerInvoiceRepository = new CustomerInvoiceRepository(database, customerInvoiceMapper);
|
||||||
const customerInvoiceService = new CustomerInvoiceService(customerInvoiceRepository);
|
const customerInvoiceService = new CustomerInvoiceService(customerInvoiceRepository);
|
||||||
|
|
||||||
const useCase = new GetCustomerInvoiceUseCase(customerInvoiceService, transactionManager);
|
|
||||||
const presenter = getCustomerInvoicePresenter;
|
const presenter = getCustomerInvoicePresenter;
|
||||||
|
|
||||||
return new GetCustomerInvoiceController(useCase, presenter);
|
const useCase = new GetCustomerInvoiceUseCase(
|
||||||
|
customerInvoiceService,
|
||||||
|
transactionManager,
|
||||||
|
presenter
|
||||||
|
);
|
||||||
|
|
||||||
|
return new GetCustomerInvoiceController(useCase);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,6 +1,5 @@
|
|||||||
export * from "./aggregates";
|
export * from "./aggregates";
|
||||||
export * from "./entities";
|
export * from "./entities";
|
||||||
export * from "./errors";
|
|
||||||
export * from "./repositories";
|
export * from "./repositories";
|
||||||
export * from "./services";
|
export * from "./services";
|
||||||
export * from "./value-objects";
|
export * from "./value-objects";
|
||||||
|
|||||||
@ -4,6 +4,8 @@ import { Collection, Result } from "@repo/rdx-utils";
|
|||||||
import { CustomerInvoice } from "../aggregates";
|
import { CustomerInvoice } from "../aggregates";
|
||||||
|
|
||||||
export interface ICustomerInvoiceRepository {
|
export interface ICustomerInvoiceRepository {
|
||||||
|
existsById(id: UniqueID, transaction?: any): Promise<Result<boolean, Error>>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* Persiste una nueva factura o actualiza una existente.
|
* Persiste una nueva factura o actualiza una existente.
|
||||||
|
|||||||
@ -4,10 +4,12 @@ import { Collection, Result } from "@repo/rdx-utils";
|
|||||||
import { CustomerInvoice, CustomerInvoiceProps } from "../aggregates";
|
import { CustomerInvoice, CustomerInvoiceProps } from "../aggregates";
|
||||||
|
|
||||||
export interface ICustomerInvoiceService {
|
export interface ICustomerInvoiceService {
|
||||||
build(props: CustomerInvoiceProps): Result<CustomerInvoice, Error>;
|
build(props: CustomerInvoiceProps, id?: UniqueID): Result<CustomerInvoice, Error>;
|
||||||
|
|
||||||
save(invoice: CustomerInvoice, transaction: any): Promise<Result<CustomerInvoice, Error>>;
|
save(invoice: CustomerInvoice, transaction: any): Promise<Result<CustomerInvoice, Error>>;
|
||||||
|
|
||||||
|
existsById(id: UniqueID, transaction?: any): Promise<Result<boolean, Error>>;
|
||||||
|
|
||||||
findByCriteria(
|
findByCriteria(
|
||||||
criteria: Criteria,
|
criteria: Criteria,
|
||||||
transaction?: any
|
transaction?: any
|
||||||
|
|||||||
@ -13,10 +13,11 @@ export class CustomerInvoiceService implements ICustomerInvoiceService {
|
|||||||
* Construye un nuevo agregado CustomerInvoice a partir de props validadas.
|
* Construye un nuevo agregado CustomerInvoice a partir de props validadas.
|
||||||
*
|
*
|
||||||
* @param props - Las propiedades ya validadas para crear la factura.
|
* @param props - Las propiedades ya validadas para crear la factura.
|
||||||
|
* @param id - Identificador UUID de la factura (opcional).
|
||||||
* @returns Result<CustomerInvoice, Error> - El agregado construido o un error si falla la creación.
|
* @returns Result<CustomerInvoice, Error> - El agregado construido o un error si falla la creación.
|
||||||
*/
|
*/
|
||||||
build(props: CustomerInvoiceProps): Result<CustomerInvoice, Error> {
|
build(props: CustomerInvoiceProps, id?: UniqueID): Result<CustomerInvoice, Error> {
|
||||||
return CustomerInvoice.create(props);
|
return CustomerInvoice.create(props, id);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -31,6 +32,19 @@ export class CustomerInvoiceService implements ICustomerInvoiceService {
|
|||||||
return saved.isSuccess ? Result.ok(invoice) : Result.fail(saved.error);
|
return saved.isSuccess ? Result.ok(invoice) : Result.fail(saved.error);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Comprueba si existe o no en persistencia una factura con el ID proporcionado
|
||||||
|
*
|
||||||
|
* @param id - Identificador UUID de la factura.
|
||||||
|
* @param transaction - Transacción activa para la operación.
|
||||||
|
* @returns Result<Boolean, Error> - Existe la factura o no.
|
||||||
|
*/
|
||||||
|
|
||||||
|
async existsById(id: UniqueID, transaction?: any): Promise<Result<boolean, Error>> {
|
||||||
|
return this.repository.existsById(id, transaction);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Obtiene una colección de facturas que cumplen con los filtros definidos en un objeto Criteria.
|
* Obtiene una colección de facturas que cumplen con los filtros definidos en un objeto Criteria.
|
||||||
*
|
*
|
||||||
@ -62,7 +76,7 @@ export class CustomerInvoiceService implements ICustomerInvoiceService {
|
|||||||
* @returns Result<CustomerInvoice, Error> - Factura encontrada o error.
|
* @returns Result<CustomerInvoice, Error> - Factura encontrada o error.
|
||||||
*/
|
*/
|
||||||
async getById(id: UniqueID, transaction?: Transaction): Promise<Result<CustomerInvoice>> {
|
async getById(id: UniqueID, transaction?: Transaction): Promise<Result<CustomerInvoice>> {
|
||||||
return await this.repository.getById(id, transaction);
|
return await this.repository.findById(id, transaction);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -3,10 +3,12 @@ import { Application, NextFunction, Request, Response, Router } from "express";
|
|||||||
import { Sequelize } from "sequelize";
|
import { Sequelize } from "sequelize";
|
||||||
import {
|
import {
|
||||||
CreateCustomerInvoiceCommandSchema,
|
CreateCustomerInvoiceCommandSchema,
|
||||||
|
GetCustomerInvoiceByIdQuerySchema,
|
||||||
ListCustomerInvoicesQuerySchema,
|
ListCustomerInvoicesQuerySchema,
|
||||||
} from "../../../common/dto";
|
} from "../../../common/dto";
|
||||||
import {
|
import {
|
||||||
buildCreateCustomerInvoicesController,
|
buildCreateCustomerInvoicesController,
|
||||||
|
buildGetCustomerInvoiceController,
|
||||||
buildListCustomerInvoicesController,
|
buildListCustomerInvoicesController,
|
||||||
} from "../../controllers";
|
} from "../../controllers";
|
||||||
|
|
||||||
@ -24,21 +26,21 @@ export const customerInvoicesRouter = (params: ModuleParams) => {
|
|||||||
"/",
|
"/",
|
||||||
//checkTabContext,
|
//checkTabContext,
|
||||||
//checkUser,
|
//checkUser,
|
||||||
validateRequest(ListCustomerInvoicesQuerySchema, "query"),
|
validateRequest(ListCustomerInvoicesQuerySchema, "params"),
|
||||||
(req: Request, res: Response, next: NextFunction) => {
|
(req: Request, res: Response, next: NextFunction) => {
|
||||||
buildListCustomerInvoicesController(database).execute(req, res, next);
|
buildListCustomerInvoicesController(database).execute(req, res, next);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
/*routes.get(
|
routes.get(
|
||||||
"/:customerInvoiceId",
|
"/:id",
|
||||||
//checkTabContext,
|
//checkTabContext,
|
||||||
//checkUser,
|
//checkUser,
|
||||||
validateRequest(GetCustomerInvoiceByIdQuerySchema, "query"),
|
validateRequest(GetCustomerInvoiceByIdQuerySchema, "params"),
|
||||||
(req: Request, res: Response, next: NextFunction) => {
|
(req: Request, res: Response, next: NextFunction) => {
|
||||||
buildGetCustomerInvoiceController(database).execute(req, res, next);
|
buildGetCustomerInvoiceController(database).execute(req, res, next);
|
||||||
}
|
}
|
||||||
);*/
|
);
|
||||||
|
|
||||||
routes.post(
|
routes.post(
|
||||||
"/",
|
"/",
|
||||||
|
|||||||
@ -67,11 +67,11 @@ export class CustomerInvoiceMapper
|
|||||||
return CustomerInvoice.create(
|
return CustomerInvoice.create(
|
||||||
{
|
{
|
||||||
status: statusOrError.data,
|
status: statusOrError.data,
|
||||||
customerInvoiceSeries: customerInvoiceSeriesOrError.data,
|
invoiceSeries: customerInvoiceSeriesOrError.data,
|
||||||
customerInvoiceNumber: customerInvoiceNumberOrError.data,
|
invoiceNumber: customerInvoiceNumberOrError.data,
|
||||||
issueDate: issueDateOrError.data,
|
issueDate: issueDateOrError.data,
|
||||||
operationDate: operationDateOrError.data,
|
operationDate: operationDateOrError.data,
|
||||||
customerInvoiceCurrency,
|
currency: customerInvoiceCurrency,
|
||||||
items: itemsOrErrors.data,
|
items: itemsOrErrors.data,
|
||||||
},
|
},
|
||||||
idOrError.data
|
idOrError.data
|
||||||
@ -95,7 +95,7 @@ export class CustomerInvoiceMapper
|
|||||||
issue_date: source.issueDate.toPrimitive(),
|
issue_date: source.issueDate.toPrimitive(),
|
||||||
operation_date: source.operationDate.toPrimitive(),
|
operation_date: source.operationDate.toPrimitive(),
|
||||||
invoice_language: "es",
|
invoice_language: "es",
|
||||||
invoice_currency: source.customerInvoiceCurrency || "EUR",
|
invoice_currency: source.currency || "EUR",
|
||||||
|
|
||||||
subtotal_amount: subtotal.amount,
|
subtotal_amount: subtotal.amount,
|
||||||
subtotal_scale: subtotal.scale,
|
subtotal_scale: subtotal.scale,
|
||||||
|
|||||||
@ -11,16 +11,26 @@ export class CustomerInvoiceRepository
|
|||||||
extends SequelizeRepository<CustomerInvoice>
|
extends SequelizeRepository<CustomerInvoice>
|
||||||
implements ICustomerInvoiceRepository
|
implements ICustomerInvoiceRepository
|
||||||
{
|
{
|
||||||
private readonly model: typeof CustomerInvoiceModel;
|
//private readonly model: typeof CustomerInvoiceModel;
|
||||||
private readonly mapper!: ICustomerInvoiceMapper;
|
private readonly mapper!: ICustomerInvoiceMapper;
|
||||||
|
|
||||||
constructor(database: Sequelize, mapper: ICustomerInvoiceMapper) {
|
constructor(database: Sequelize, mapper: ICustomerInvoiceMapper) {
|
||||||
super(database);
|
super(database);
|
||||||
|
|
||||||
this.model = database.model("CustomerInvoice") as typeof CustomerInvoiceModel;
|
//CustomerInvoice = database.model("CustomerInvoice") as typeof CustomerInvoiceModel;
|
||||||
this.mapper = mapper;
|
this.mapper = mapper;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async existsById(id: UniqueID, transaction?: Transaction): Promise<Result<boolean, Error>> {
|
||||||
|
try {
|
||||||
|
const result = await this._exists(CustomerInvoiceModel, "id", id.toString(), transaction);
|
||||||
|
|
||||||
|
return Result.ok(Boolean(result));
|
||||||
|
} catch (err: unknown) {
|
||||||
|
return Result.fail(errorMapper.toDomainError(err));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* Persiste una nueva factura o actualiza una existente.
|
* Persiste una nueva factura o actualiza una existente.
|
||||||
@ -35,7 +45,7 @@ export class CustomerInvoiceRepository
|
|||||||
): Promise<Result<CustomerInvoice, Error>> {
|
): Promise<Result<CustomerInvoice, Error>> {
|
||||||
try {
|
try {
|
||||||
const data = this.mapper.mapToPersistence(invoice);
|
const data = this.mapper.mapToPersistence(invoice);
|
||||||
await this.model.upsert(data, { transaction });
|
await CustomerInvoiceModel.upsert(data, { transaction });
|
||||||
return Result.ok(invoice);
|
return Result.ok(invoice);
|
||||||
} catch (err: unknown) {
|
} catch (err: unknown) {
|
||||||
return Result.fail(errorMapper.toDomainError(err));
|
return Result.fail(errorMapper.toDomainError(err));
|
||||||
@ -51,7 +61,7 @@ export class CustomerInvoiceRepository
|
|||||||
*/
|
*/
|
||||||
async findById(id: UniqueID, transaction: Transaction): Promise<Result<CustomerInvoice, Error>> {
|
async findById(id: UniqueID, transaction: Transaction): Promise<Result<CustomerInvoice, Error>> {
|
||||||
try {
|
try {
|
||||||
const rawData = await this._findById(this.model, id.toString(), { transaction });
|
const rawData = await this._findById(CustomerInvoiceModel, id.toString(), { transaction });
|
||||||
|
|
||||||
if (!rawData) {
|
if (!rawData) {
|
||||||
return Result.fail(new Error(`Invoice with id ${id} not found.`));
|
return Result.fail(new Error(`Invoice with id ${id} not found.`));
|
||||||
@ -80,7 +90,7 @@ export class CustomerInvoiceRepository
|
|||||||
const converter = new CriteriaToSequelizeConverter();
|
const converter = new CriteriaToSequelizeConverter();
|
||||||
const query = converter.convert(criteria);
|
const query = converter.convert(criteria);
|
||||||
|
|
||||||
const instances = await this.model.findAll({
|
const instances = await CustomerInvoiceModel.findAll({
|
||||||
...query,
|
...query,
|
||||||
transaction,
|
transaction,
|
||||||
});
|
});
|
||||||
@ -100,7 +110,7 @@ export class CustomerInvoiceRepository
|
|||||||
*/
|
*/
|
||||||
async deleteById(id: UniqueID, transaction: any): Promise<Result<void, Error>> {
|
async deleteById(id: UniqueID, transaction: any): Promise<Result<void, Error>> {
|
||||||
try {
|
try {
|
||||||
await this._deleteById(this.model, id, false, transaction);
|
await this._deleteById(CustomerInvoiceModel, id, false, transaction);
|
||||||
return Result.ok<void>();
|
return Result.ok<void>();
|
||||||
} catch (err: unknown) {
|
} catch (err: unknown) {
|
||||||
return Result.fail(errorMapper.toDomainError(err));
|
return Result.fail(errorMapper.toDomainError(err));
|
||||||
|
|||||||
@ -0,0 +1,13 @@
|
|||||||
|
import * as z from "zod/v4";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Este DTO es utilizado por el endpoint:
|
||||||
|
* `GET /customer-invoices/:id` (consultar una factura por ID).
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
export const GetCustomerInvoiceByIdQuerySchema = z.object({
|
||||||
|
id: z.string(),
|
||||||
|
});
|
||||||
|
|
||||||
|
export type GetCustomerInvoiceByIdQueryDTO = z.infer<typeof GetCustomerInvoiceByIdQuerySchema>;
|
||||||
@ -1,2 +1,3 @@
|
|||||||
export * from "./create-customer-invoice.command.dto";
|
export * from "./create-customer-invoice.command.dto";
|
||||||
|
export * from "./get-customer-invoice.query.dto";
|
||||||
export * from "./list-customer-invoices.query.dto";
|
export * from "./list-customer-invoices.query.dto";
|
||||||
|
|||||||
@ -0,0 +1,17 @@
|
|||||||
|
import { MetadataSchema } from "@erp/core";
|
||||||
|
import * as z from "zod/v4";
|
||||||
|
|
||||||
|
export const GetCustomerInvoiceResultSchema = z.object({
|
||||||
|
id: z.uuid(),
|
||||||
|
invoice_status: z.string(),
|
||||||
|
invoice_number: z.string(),
|
||||||
|
invoice_series: z.string(),
|
||||||
|
issue_date: z.iso.datetime({ offset: true }),
|
||||||
|
operation_date: z.iso.datetime({ offset: true }),
|
||||||
|
language_code: z.string(),
|
||||||
|
currency: z.string(),
|
||||||
|
|
||||||
|
metadata: MetadataSchema.optional(),
|
||||||
|
});
|
||||||
|
|
||||||
|
export type GetCustomerInvoiceResultDTO = z.infer<typeof GetCustomerInvoiceResultSchema>;
|
||||||
@ -1,2 +1,3 @@
|
|||||||
export * from "./customer-invoice-creation.result.dto";
|
export * from "./customer-invoice-creation.result.dto";
|
||||||
|
export * from "./get-customer-invoice.result.dto";
|
||||||
export * from "./list-customer-invoices.result.dto";
|
export * from "./list-customer-invoices.result.dto";
|
||||||
|
|||||||
@ -75,7 +75,7 @@ importers:
|
|||||||
specifier: ^9.0.2
|
specifier: ^9.0.2
|
||||||
version: 9.0.2
|
version: 9.0.2
|
||||||
luxon:
|
luxon:
|
||||||
specifier: ^3.5.0
|
specifier: ^3.6.1
|
||||||
version: 3.6.1
|
version: 3.6.1
|
||||||
module-alias:
|
module-alias:
|
||||||
specifier: ^2.2.3
|
specifier: ^2.2.3
|
||||||
@ -151,7 +151,7 @@ importers:
|
|||||||
specifier: ^9.0.8
|
specifier: ^9.0.8
|
||||||
version: 9.0.10
|
version: 9.0.10
|
||||||
'@types/luxon':
|
'@types/luxon':
|
||||||
specifier: ^3.4.2
|
specifier: ^3.6.2
|
||||||
version: 3.6.2
|
version: 3.6.2
|
||||||
'@types/node':
|
'@types/node':
|
||||||
specifier: ^22.15.12
|
specifier: ^22.15.12
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user