.
This commit is contained in:
parent
b3c5e650fc
commit
3c1010adad
@ -1,8 +1,8 @@
|
|||||||
import { ITransactionManager } from "@erp/core/api";
|
import { ITransactionManager } from "@erp/core/api";
|
||||||
import { CustomerInvoiceListResponseDTO } from "@erp/customer-invoices/common/dto";
|
|
||||||
import { Criteria } from "@repo/rdx-criteria/server";
|
import { Criteria } from "@repo/rdx-criteria/server";
|
||||||
import { Result } from "@repo/rdx-utils";
|
import { Result } from "@repo/rdx-utils";
|
||||||
import { Transaction } from "sequelize";
|
import { Transaction } from "sequelize";
|
||||||
|
import { CustomerInvoiceListResponseDTO } from "../../../common/dto";
|
||||||
import { ICustomerInvoiceService } from "../../domain";
|
import { ICustomerInvoiceService } from "../../domain";
|
||||||
import { ListCustomerInvoicesAssembler } from "./assembler";
|
import { ListCustomerInvoicesAssembler } from "./assembler";
|
||||||
|
|
||||||
@ -31,7 +31,7 @@ export class ListCustomerInvoicesUseCase {
|
|||||||
return Result.fail(result.error);
|
return Result.fail(result.error);
|
||||||
}
|
}
|
||||||
|
|
||||||
const dto: CustomerInvoiceListResponseDTO = this.assembler.toDTO(result.data, criteria);
|
const dto = this.assembler.toDTO(result.data, criteria);
|
||||||
return Result.ok(dto);
|
return Result.ok(dto);
|
||||||
} catch (error: unknown) {
|
} catch (error: unknown) {
|
||||||
return Result.fail(error as Error);
|
return Result.fail(error as Error);
|
||||||
|
|||||||
@ -32,6 +32,7 @@
|
|||||||
"@dnd-kit/core": "^6.3.1",
|
"@dnd-kit/core": "^6.3.1",
|
||||||
"@dnd-kit/sortable": "^10.0.0",
|
"@dnd-kit/sortable": "^10.0.0",
|
||||||
"@dnd-kit/utilities": "^3.2.2",
|
"@dnd-kit/utilities": "^3.2.2",
|
||||||
|
"@erp/auth": "workspace:*",
|
||||||
"@erp/customers": "workspace:*",
|
"@erp/customers": "workspace:*",
|
||||||
"@hookform/resolvers": "^5.0.1",
|
"@hookform/resolvers": "^5.0.1",
|
||||||
"@repo/rdx-criteria": "workspace:*",
|
"@repo/rdx-criteria": "workspace:*",
|
||||||
|
|||||||
@ -2,20 +2,20 @@ import { Customer } from "@erp/customers/api/domain";
|
|||||||
import { CustomersCreationResultDTO } from "@erp/customers/common/dto";
|
import { CustomersCreationResultDTO } from "@erp/customers/common/dto";
|
||||||
|
|
||||||
export class CreateCustomersAssembler {
|
export class CreateCustomersAssembler {
|
||||||
public toDTO(invoice: Customer): CustomersCreationResultDTO {
|
public toDTO(customer: Customer): CustomersCreationResultDTO {
|
||||||
return {
|
return {
|
||||||
id: invoice.id.toPrimitive(),
|
id: customer.id.toPrimitive(),
|
||||||
|
|
||||||
invoice_status: invoice.status.toString(),
|
customer_status: customer.status.toString(),
|
||||||
invoice_number: invoice.invoiceNumber.toString(),
|
customer_number: customer.customerNumber.toString(),
|
||||||
invoice_series: invoice.invoiceSeries.toString(),
|
customer_series: customer.customerSeries.toString(),
|
||||||
issue_date: invoice.issueDate.toISOString(),
|
issue_date: customer.issueDate.toISOString(),
|
||||||
operation_date: invoice.operationDate.toISOString(),
|
operation_date: customer.operationDate.toISOString(),
|
||||||
language_code: "ES",
|
language_code: "ES",
|
||||||
currency: "EUR",
|
currency: "EUR",
|
||||||
|
|
||||||
//subtotal_price: invoice.calculateSubtotal().toPrimitive(),
|
//subtotal_price: customer.calculateSubtotal().toPrimitive(),
|
||||||
//total_price: invoice.calculateTotal().toPrimitive(),
|
//total_price: customer.calculateTotal().toPrimitive(),
|
||||||
|
|
||||||
//recipient: CustomerParticipantAssembler(customer.recipient),
|
//recipient: CustomerParticipantAssembler(customer.recipient),
|
||||||
|
|
||||||
|
|||||||
@ -14,21 +14,21 @@ export class CreateCustomerUseCase {
|
|||||||
) {}
|
) {}
|
||||||
|
|
||||||
public execute(dto: CreateCustomerCommandDTO) {
|
public execute(dto: CreateCustomerCommandDTO) {
|
||||||
const invoicePropsOrError = mapDTOToCustomerProps(dto);
|
const customerPropsOrError = mapDTOToCustomerProps(dto);
|
||||||
|
|
||||||
if (invoicePropsOrError.isFailure) {
|
if (customerPropsOrError.isFailure) {
|
||||||
return Result.fail(invoicePropsOrError.error);
|
return Result.fail(customerPropsOrError.error);
|
||||||
}
|
}
|
||||||
|
|
||||||
const { props, id } = invoicePropsOrError.data;
|
const { props, id } = customerPropsOrError.data;
|
||||||
|
|
||||||
const invoiceOrError = this.service.build(props, id);
|
const customerOrError = this.service.build(props, id);
|
||||||
|
|
||||||
if (invoiceOrError.isFailure) {
|
if (customerOrError.isFailure) {
|
||||||
return Result.fail(invoiceOrError.error);
|
return Result.fail(customerOrError.error);
|
||||||
}
|
}
|
||||||
|
|
||||||
const newInvoice = invoiceOrError.data;
|
const newCustomer = customerOrError.data;
|
||||||
|
|
||||||
return this.transactionManager.complete(async (transaction: Transaction) => {
|
return this.transactionManager.complete(async (transaction: Transaction) => {
|
||||||
try {
|
try {
|
||||||
@ -42,12 +42,12 @@ export class CreateCustomerUseCase {
|
|||||||
return Result.fail(new DuplicateEntityError("Customer", id.toString()));
|
return Result.fail(new DuplicateEntityError("Customer", id.toString()));
|
||||||
}
|
}
|
||||||
|
|
||||||
const result = await this.service.save(newInvoice, transaction);
|
const result = await this.service.save(newCustomer, transaction);
|
||||||
if (result.isFailure) {
|
if (result.isFailure) {
|
||||||
return Result.fail(result.error);
|
return Result.fail(result.error);
|
||||||
}
|
}
|
||||||
|
|
||||||
const viewDTO = this.assembler.toDTO(newInvoice);
|
const viewDTO = this.assembler.toDTO(newCustomer);
|
||||||
return Result.ok(viewDTO);
|
return Result.ok(viewDTO);
|
||||||
} catch (error: unknown) {
|
} catch (error: unknown) {
|
||||||
return Result.fail(error as Error);
|
return Result.fail(error as Error);
|
||||||
|
|||||||
@ -6,9 +6,9 @@ export class GetCustomerAssembler {
|
|||||||
return {
|
return {
|
||||||
id: customer.id.toPrimitive(),
|
id: customer.id.toPrimitive(),
|
||||||
|
|
||||||
invoice_status: customer.status.toString(),
|
customer_status: customer.status.toString(),
|
||||||
invoice_number: customer.invoiceNumber.toString(),
|
customer_number: customer.customerNumber.toString(),
|
||||||
invoice_series: customer.invoiceSeries.toString(),
|
customer_series: customer.customerSeries.toString(),
|
||||||
issue_date: customer.issueDate.toDateString(),
|
issue_date: customer.issueDate.toDateString(),
|
||||||
operation_date: customer.operationDate.toDateString(),
|
operation_date: customer.operationDate.toDateString(),
|
||||||
language_code: "ES",
|
language_code: "ES",
|
||||||
|
|||||||
@ -1 +1 @@
|
|||||||
export * from "./get-invoice.assembler";
|
export * from "./get-customer.assembler";
|
||||||
|
|||||||
@ -21,12 +21,12 @@ export class GetCustomerUseCase {
|
|||||||
|
|
||||||
return this.transactionManager.complete(async (transaction) => {
|
return this.transactionManager.complete(async (transaction) => {
|
||||||
try {
|
try {
|
||||||
const invoiceOrError = await this.service.getById(idOrError.data, transaction);
|
const customerOrError = await this.service.getById(idOrError.data, transaction);
|
||||||
if (invoiceOrError.isFailure) {
|
if (customerOrError.isFailure) {
|
||||||
return Result.fail(invoiceOrError.error);
|
return Result.fail(customerOrError.error);
|
||||||
}
|
}
|
||||||
|
|
||||||
const getDTO = this.assembler.toDTO(invoiceOrError.data);
|
const getDTO = this.assembler.toDTO(customerOrError.data);
|
||||||
return Result.ok(getDTO);
|
return Result.ok(getDTO);
|
||||||
} catch (error: unknown) {
|
} catch (error: unknown) {
|
||||||
return Result.fail(error as Error);
|
return Result.fail(error as Error);
|
||||||
|
|||||||
@ -19,16 +19,16 @@ import { mapDTOToCustomerItemsProps } from "./map-dto-to-customer-items-props";
|
|||||||
export function mapDTOToCustomerProps(dto: CreateCustomerCommandDTO) {
|
export function mapDTOToCustomerProps(dto: CreateCustomerCommandDTO) {
|
||||||
const errors: ValidationErrorDetail[] = [];
|
const errors: ValidationErrorDetail[] = [];
|
||||||
|
|
||||||
const invoiceId = extractOrPushError(UniqueID.create(dto.id), "id", errors);
|
const customerId = extractOrPushError(UniqueID.create(dto.id), "id", errors);
|
||||||
|
|
||||||
const invoiceNumber = extractOrPushError(
|
const customerNumber = extractOrPushError(
|
||||||
CustomerNumber.create(dto.invoice_number),
|
CustomerNumber.create(dto.customer_number),
|
||||||
"invoice_number",
|
"customer_number",
|
||||||
errors
|
errors
|
||||||
);
|
);
|
||||||
const invoiceSeries = extractOrPushError(
|
const customerSeries = extractOrPushError(
|
||||||
CustomerSerie.create(dto.invoice_series),
|
CustomerSerie.create(dto.customer_series),
|
||||||
"invoice_series",
|
"customer_series",
|
||||||
errors
|
errors
|
||||||
);
|
);
|
||||||
const issueDate = extractOrPushError(UtcDate.createFromISO(dto.issue_date), "issue_date", errors);
|
const issueDate = extractOrPushError(UtcDate.createFromISO(dto.issue_date), "issue_date", errors);
|
||||||
@ -51,23 +51,23 @@ export function mapDTOToCustomerProps(dto: CreateCustomerCommandDTO) {
|
|||||||
return Result.fail(new ValidationErrorCollection(errors));
|
return Result.fail(new ValidationErrorCollection(errors));
|
||||||
}
|
}
|
||||||
|
|
||||||
const invoiceProps: CustomerProps = {
|
const customerProps: CustomerProps = {
|
||||||
invoiceNumber: invoiceNumber!,
|
customerNumber: customerNumber!,
|
||||||
invoiceSeries: invoiceSeries!,
|
customerSeries: customerSeries!,
|
||||||
issueDate: issueDate!,
|
issueDate: issueDate!,
|
||||||
operationDate: operationDate!,
|
operationDate: operationDate!,
|
||||||
status: CustomerStatus.createDraft(),
|
status: CustomerStatus.createDraft(),
|
||||||
currency,
|
currency,
|
||||||
};
|
};
|
||||||
|
|
||||||
return Result.ok({ id: invoiceId!, props: invoiceProps });
|
return Result.ok({ id: customerId!, props: customerProps });
|
||||||
|
|
||||||
/*if (hasNoUndefinedFields(invoiceProps)) {
|
/*if (hasNoUndefinedFields(customerProps)) {
|
||||||
const invoiceOrError = Customer.create(invoiceProps, invoiceId);
|
const customerOrError = Customer.create(customerProps, customerId);
|
||||||
if (invoiceOrError.isFailure) {
|
if (customerOrError.isFailure) {
|
||||||
return Result.fail(invoiceOrError.error);
|
return Result.fail(customerOrError.error);
|
||||||
}
|
}
|
||||||
return Result.ok(invoiceOrError.data);
|
return Result.ok(customerOrError.data);
|
||||||
}
|
}
|
||||||
|
|
||||||
return Result.fail(
|
return Result.fail(
|
||||||
|
|||||||
@ -1 +1 @@
|
|||||||
export * from "./list-invoices.assembler";
|
export * from "./list-customers.assembler";
|
||||||
|
|||||||
@ -0,0 +1,70 @@
|
|||||||
|
import { Criteria } from "@repo/rdx-criteria/server";
|
||||||
|
import { Collection } from "@repo/rdx-utils";
|
||||||
|
import { CustomerListResponsetDTO } from "../../../../common/dto";
|
||||||
|
import { Customer } from "../../../domain";
|
||||||
|
|
||||||
|
export class ListCustomersAssembler {
|
||||||
|
toDTO(customers: Collection<Customer>, criteria: Criteria): CustomerListResponsetDTO {
|
||||||
|
const items: CustomerListResponsetDTO["items"] = customers.map((customer) => {
|
||||||
|
const address = customer.address.toPrimitive();
|
||||||
|
|
||||||
|
return {
|
||||||
|
id: customer.id.toPrimitive(),
|
||||||
|
reference: customer.reference,
|
||||||
|
|
||||||
|
is_freelancer: customer.isFreelancer,
|
||||||
|
name: customer.name,
|
||||||
|
trade_name: customer.tradeName.getOrUndefined(),
|
||||||
|
tin: customer.tin.toString(),
|
||||||
|
|
||||||
|
street: address.street,
|
||||||
|
city: address.city,
|
||||||
|
state: address.state,
|
||||||
|
postal_code: address.postalCode,
|
||||||
|
country: address.country,
|
||||||
|
|
||||||
|
email: customer.email.getValue(),
|
||||||
|
phone: customer.phone.getValue(),
|
||||||
|
fax: customer.fax.getOrUndefined(),
|
||||||
|
website: customer.website.getOrUndefined(),
|
||||||
|
|
||||||
|
legal_record: customer.legalRecord,
|
||||||
|
|
||||||
|
default_tax: customer.defaultTax,
|
||||||
|
status: customer.isActive ? 'active' : 'inactive',
|
||||||
|
lang_code: customer.langCode,
|
||||||
|
currency_code: customer.currencyCode,
|
||||||
|
|
||||||
|
metadata: {
|
||||||
|
entity: "customer",
|
||||||
|
id: customer.id.toPrimitive(),
|
||||||
|
//created_at: customer.createdAt.toPrimitive(),
|
||||||
|
//updated_at: customer.updatedAt.toPrimitive()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
const totalItems = customers.total();
|
||||||
|
|
||||||
|
return {
|
||||||
|
page: criteria.pageNumber,
|
||||||
|
per_page: criteria.pageSize,
|
||||||
|
total_pages: Math.ceil(totalItems / criteria.pageSize),
|
||||||
|
total_items: totalItems,
|
||||||
|
items: items,
|
||||||
|
metadata: {
|
||||||
|
entity: "customers",
|
||||||
|
criteria: criteria.toJSON(),
|
||||||
|
//links: {
|
||||||
|
// self: `/api/customers?page=${criteria.pageNumber}&per_page=${criteria.pageSize}`,
|
||||||
|
// first: `/api/customers?page=1&per_page=${criteria.pageSize}`,
|
||||||
|
// last: `/api/customers?page=${Math.ceil(totalItems / criteria.pageSize)}&per_page=${criteria.pageSize}`,
|
||||||
|
//},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
},
|
||||||
|
}
|
||||||
@ -1,51 +0,0 @@
|
|||||||
import { Criteria } from "@repo/rdx-criteria/server";
|
|
||||||
import { Collection } from "@repo/rdx-utils";
|
|
||||||
import { CustomerListResponsetDTO } from "../../../../common/dto";
|
|
||||||
import { Customer } from "../../../domain";
|
|
||||||
|
|
||||||
|
|
||||||
export class ListCustomersAssembler {
|
|
||||||
toDTO(customers: Collection<Customer>, criteria: Criteria): CustomerListResponsetDTO {
|
|
||||||
const items = customers.map((invoice) => {
|
|
||||||
return {
|
|
||||||
id: invoice.id.toPrimitive(),
|
|
||||||
|
|
||||||
invoice_status: invoice.status.toString(),
|
|
||||||
invoice_number: invoice.invoiceNumber.toString(),
|
|
||||||
invoice_series: invoice.invoiceSeries.toString(),
|
|
||||||
issue_date: invoice.issueDate.toISOString(),
|
|
||||||
operation_date: invoice.operationDate.toISOString(),
|
|
||||||
language_code: "ES",
|
|
||||||
currency: "EUR",
|
|
||||||
|
|
||||||
subtotal_price: invoice.calculateSubtotal().toPrimitive(),
|
|
||||||
total_price: invoice.calculateTotal().toPrimitive(),
|
|
||||||
|
|
||||||
//recipient: CustomerParticipantAssembler(customer.recipient),
|
|
||||||
|
|
||||||
metadata: {
|
|
||||||
entity: "customer",
|
|
||||||
},
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
const totalItems = customers.total();
|
|
||||||
|
|
||||||
return {
|
|
||||||
page: criteria.pageNumber,
|
|
||||||
per_page: criteria.pageSize,
|
|
||||||
total_pages: Math.ceil(totalItems / criteria.pageSize),
|
|
||||||
total_items: totalItems,
|
|
||||||
items: items,
|
|
||||||
metadata: {
|
|
||||||
entity: "customers",
|
|
||||||
criteria: criteria.toJSON(),
|
|
||||||
//links: {
|
|
||||||
// self: `/api/customers?page=${criteria.pageNumber}&per_page=${criteria.pageSize}`,
|
|
||||||
// first: `/api/customers?page=1&per_page=${criteria.pageSize}`,
|
|
||||||
// last: `/api/customers?page=${Math.ceil(totalItems / criteria.pageSize)}&per_page=${criteria.pageSize}`,
|
|
||||||
//},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
},
|
|
||||||
};
|
|
||||||
@ -1,11 +1,16 @@
|
|||||||
import { ITransactionManager } from "@erp/core/api";
|
import { ITransactionManager } from "@erp/core/api";
|
||||||
import { ListCustomersResultDTO } from "@erp/customers/common/dto";
|
|
||||||
import { Criteria } from "@repo/rdx-criteria/server";
|
import { Criteria } from "@repo/rdx-criteria/server";
|
||||||
import { Result } from "@repo/rdx-utils";
|
import { Result } from "@repo/rdx-utils";
|
||||||
import { Transaction } from "sequelize";
|
import { Transaction } from "sequelize";
|
||||||
|
import { CustomerListResponsetDTO } from "../../../common/dto";
|
||||||
import { ICustomerService } from "../../domain";
|
import { ICustomerService } from "../../domain";
|
||||||
import { ListCustomersAssembler } from "./assembler";
|
import { ListCustomersAssembler } from "./assembler";
|
||||||
|
|
||||||
|
type ListCustomersUseCaseInput = {
|
||||||
|
tenantId: string;
|
||||||
|
criteria: Criteria;
|
||||||
|
};
|
||||||
|
|
||||||
export class ListCustomersUseCase {
|
export class ListCustomersUseCase {
|
||||||
constructor(
|
constructor(
|
||||||
private readonly customerService: ICustomerService,
|
private readonly customerService: ICustomerService,
|
||||||
@ -13,17 +18,20 @@ export class ListCustomersUseCase {
|
|||||||
private readonly assembler: ListCustomersAssembler
|
private readonly assembler: ListCustomersAssembler
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
public execute(criteria: Criteria): Promise<Result<ListCustomersResultDTO, Error>> {
|
public execute(
|
||||||
|
params: ListCustomersUseCaseInput
|
||||||
|
): Promise<Result<CustomerListResponsetDTO, Error>> {
|
||||||
|
const { criteria, tenantId } = params;
|
||||||
|
|
||||||
return this.transactionManager.complete(async (transaction: Transaction) => {
|
return this.transactionManager.complete(async (transaction: Transaction) => {
|
||||||
try {
|
try {
|
||||||
const result = await this.customerService.findByCriteria(criteria, transaction);
|
const result = await this.customerService.findByCriteria(criteria, transaction);
|
||||||
|
|
||||||
if (result.isFailure) {
|
if (result.isFailure) {
|
||||||
console.error(result.error);
|
|
||||||
return Result.fail(result.error);
|
return Result.fail(result.error);
|
||||||
}
|
}
|
||||||
|
|
||||||
const dto: ListCustomersResultDTO = this.assembler.toDTO(result.data, criteria);
|
const dto = this.assembler.toDTO(result.data, criteria);
|
||||||
return Result.ok(dto);
|
return Result.ok(dto);
|
||||||
} catch (error: unknown) {
|
} catch (error: unknown) {
|
||||||
return Result.fail(error as Error);
|
return Result.fail(error as Error);
|
||||||
|
|||||||
@ -5,7 +5,7 @@ import {
|
|||||||
forbidQueryFieldGuard,
|
forbidQueryFieldGuard,
|
||||||
tenantGuard,
|
tenantGuard,
|
||||||
} from "@erp/core/api";
|
} from "@erp/core/api";
|
||||||
import { ListCustomersUseCase } from "../../../../application";
|
import { ListCustomersUseCase } from "../../../application";
|
||||||
|
|
||||||
export class ListCustomersController extends ExpressController {
|
export class ListCustomersController extends ExpressController {
|
||||||
public constructor(private readonly listCustomers: ListCustomersUseCase) {
|
public constructor(private readonly listCustomers: ListCustomersUseCase) {
|
||||||
|
|||||||
@ -1,3 +1,4 @@
|
|||||||
|
import { enforceTenant } from "@erp/auth/api";
|
||||||
import { ILogger, ModuleParams, validateRequest } from "@erp/core/api";
|
import { ILogger, ModuleParams, validateRequest } 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";
|
||||||
|
|||||||
@ -3,7 +3,7 @@ import * as z from "zod/v4";
|
|||||||
|
|
||||||
export const CustomerListResponseSchema = createListViewResponseSchema(
|
export const CustomerListResponseSchema = createListViewResponseSchema(
|
||||||
z.object({
|
z.object({
|
||||||
id: z.string(),
|
id: z.uuid(),
|
||||||
reference: z.string(),
|
reference: z.string(),
|
||||||
|
|
||||||
is_freelancer: z.boolean(),
|
is_freelancer: z.boolean(),
|
||||||
|
|||||||
@ -583,6 +583,9 @@ importers:
|
|||||||
'@dnd-kit/utilities':
|
'@dnd-kit/utilities':
|
||||||
specifier: ^3.2.2
|
specifier: ^3.2.2
|
||||||
version: 3.2.2(react@19.1.0)
|
version: 3.2.2(react@19.1.0)
|
||||||
|
'@erp/auth':
|
||||||
|
specifier: workspace:*
|
||||||
|
version: link:../auth
|
||||||
'@erp/core':
|
'@erp/core':
|
||||||
specifier: workspace:*
|
specifier: workspace:*
|
||||||
version: link:../core
|
version: link:../core
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user