Clientes
This commit is contained in:
parent
7e63288e12
commit
a0f75a4a8f
@ -30,8 +30,6 @@ export class CreateCustomerUseCase {
|
||||
|
||||
const { props, id } = dtoResult.data;
|
||||
|
||||
console.debug("Creating customer with props:", props);
|
||||
|
||||
// 3) Construir entidad de dominio
|
||||
const buildResult = this.service.buildCustomerInCompany(companyId, props, id);
|
||||
if (buildResult.isFailure) {
|
||||
@ -40,18 +38,18 @@ export class CreateCustomerUseCase {
|
||||
|
||||
const newCustomer = buildResult.data;
|
||||
|
||||
console.debug("Built new customer entity:", newCustomer);
|
||||
console.debug("Built new customer entity:", id, newCustomer);
|
||||
|
||||
// 4) Ejecutar bajo transacción: verificar duplicado → persistir → ensamblar vista
|
||||
return this.transactionManager.complete(async (tx: Transaction) => {
|
||||
const existsGuard = await this.ensureNotExists(companyId, id, tx);
|
||||
return this.transactionManager.complete(async (transaction: Transaction) => {
|
||||
const existsGuard = await this.ensureNotExists(companyId, id, transaction);
|
||||
if (existsGuard.isFailure) {
|
||||
return Result.fail(existsGuard.error);
|
||||
}
|
||||
|
||||
console.debug("No existing customer with same ID found, proceeding to save.");
|
||||
|
||||
const saveResult = await this.service.saveCustomer(newCustomer, tx);
|
||||
const saveResult = await this.service.saveCustomer(newCustomer, transaction);
|
||||
if (saveResult.isFailure) {
|
||||
return Result.fail(saveResult.error);
|
||||
}
|
||||
|
||||
@ -23,7 +23,7 @@ import {
|
||||
UniqueID,
|
||||
maybeFromNullableVO,
|
||||
} from "@repo/rdx-ddd";
|
||||
import { Collection, Result } from "@repo/rdx-utils";
|
||||
import { Collection, Result, isNullishOrEmpty } from "@repo/rdx-utils";
|
||||
import { CreateCustomerRequestDTO } from "../../../common/dto";
|
||||
import { CustomerProps, CustomerStatus } from "../../domain";
|
||||
|
||||
@ -146,12 +146,14 @@ export function mapDTOToCreateCustomerProps(dto: CreateCustomerRequestDTO) {
|
||||
|
||||
const defaultTaxes = new Collection<TaxCode>();
|
||||
|
||||
dto.default_taxes.split(",").map((taxCode, index) => {
|
||||
const tax = extractOrPushError(TaxCode.create(taxCode), `default_taxes.${index}`, errors);
|
||||
if (tax) {
|
||||
defaultTaxes.add(tax!);
|
||||
}
|
||||
});
|
||||
if (!isNullishOrEmpty(dto.default_taxes)) {
|
||||
dto.default_taxes.split(",").map((taxCode, index) => {
|
||||
const tax = extractOrPushError(TaxCode.create(taxCode), `default_taxes.${index}`, errors);
|
||||
if (tax) {
|
||||
defaultTaxes.add(tax!);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (errors.length > 0) {
|
||||
console.error(errors);
|
||||
|
||||
@ -5,7 +5,7 @@ import { CustomerService } from "../../domain";
|
||||
|
||||
type DeleteCustomerUseCaseInput = {
|
||||
companyId: UniqueID;
|
||||
id: string;
|
||||
customer_id: string;
|
||||
};
|
||||
|
||||
export class DeleteCustomerUseCase {
|
||||
@ -15,19 +15,23 @@ export class DeleteCustomerUseCase {
|
||||
) {}
|
||||
|
||||
public execute(params: DeleteCustomerUseCaseInput) {
|
||||
const { companyId, id } = params;
|
||||
const { companyId, customer_id } = params;
|
||||
|
||||
const idOrError = UniqueID.create(id);
|
||||
const idOrError = UniqueID.create(customer_id);
|
||||
|
||||
if (idOrError.isFailure) {
|
||||
return Result.fail(idOrError.error);
|
||||
}
|
||||
|
||||
const validId = idOrError.data;
|
||||
const customerId = idOrError.data;
|
||||
|
||||
return this.transactionManager.complete(async (transaction) => {
|
||||
try {
|
||||
const existsCheck = await this.service.existsByIdInCompany(companyId, validId, transaction);
|
||||
const existsCheck = await this.service.existsByIdInCompany(
|
||||
companyId,
|
||||
customerId,
|
||||
transaction
|
||||
);
|
||||
|
||||
if (existsCheck.isFailure) {
|
||||
return Result.fail(existsCheck.error);
|
||||
@ -36,10 +40,10 @@ export class DeleteCustomerUseCase {
|
||||
const customerExists = existsCheck.data;
|
||||
|
||||
if (!customerExists) {
|
||||
return Result.fail(new EntityNotFoundError("Customer", "id", validId.toString()));
|
||||
return Result.fail(new EntityNotFoundError("Customer", "id", customerId.toString()));
|
||||
}
|
||||
|
||||
return await this.service.deleteCustomerByIdInCompany(validId, companyId, transaction);
|
||||
return await this.service.deleteCustomerByIdInCompany(customerId, companyId, transaction);
|
||||
} catch (error: unknown) {
|
||||
return Result.fail(error as Error);
|
||||
}
|
||||
|
||||
@ -6,7 +6,7 @@ import { GetCustomerAssembler } from "./assembler";
|
||||
|
||||
type GetCustomerUseCaseInput = {
|
||||
companyId: UniqueID;
|
||||
id: string;
|
||||
customer_id: string;
|
||||
};
|
||||
|
||||
export class GetCustomerUseCase {
|
||||
@ -18,19 +18,21 @@ export class GetCustomerUseCase {
|
||||
|
||||
public execute(params: GetCustomerUseCaseInput) {
|
||||
console.log(params);
|
||||
const { id, companyId } = params;
|
||||
const { customer_id, companyId } = params;
|
||||
|
||||
const idOrError = UniqueID.create(id);
|
||||
const idOrError = UniqueID.create(customer_id);
|
||||
|
||||
if (idOrError.isFailure) {
|
||||
return Result.fail(idOrError.error);
|
||||
}
|
||||
|
||||
const customerId = idOrError.data;
|
||||
|
||||
return this.transactionManager.complete(async (transaction) => {
|
||||
try {
|
||||
const customerOrError = await this.service.getCustomerByIdInCompany(
|
||||
companyId,
|
||||
idOrError.data,
|
||||
customerId,
|
||||
transaction
|
||||
);
|
||||
|
||||
|
||||
@ -164,7 +164,7 @@ export function mapDTOToUpdateCustomerPatchProps(dto: UpdateCustomerRequestDTO)
|
||||
return;
|
||||
}
|
||||
|
||||
defaultTaxes!.map((taxCode, index) => {
|
||||
defaultTaxes!.split(",").forEach((taxCode, index) => {
|
||||
const tax = extractOrPushError(TaxCode.create(taxCode), `default_taxes.${index}`, errors);
|
||||
if (tax && customerPatchProps.defaultTaxes) {
|
||||
customerPatchProps.defaultTaxes.add(tax);
|
||||
|
||||
@ -8,7 +8,7 @@ import { mapDTOToUpdateCustomerPatchProps } from "./map-dto-to-update-customer-p
|
||||
|
||||
type UpdateCustomerUseCaseInput = {
|
||||
companyId: UniqueID;
|
||||
id: string;
|
||||
customer_id: string;
|
||||
dto: UpdateCustomerRequestDTO;
|
||||
};
|
||||
|
||||
@ -20,9 +20,9 @@ export class UpdateCustomerUseCase {
|
||||
) {}
|
||||
|
||||
public execute(params: UpdateCustomerUseCaseInput) {
|
||||
const { companyId, id, dto } = params;
|
||||
const { companyId, customer_id, dto } = params;
|
||||
|
||||
const idOrError = UniqueID.create(id);
|
||||
const idOrError = UniqueID.create(customer_id);
|
||||
if (idOrError.isFailure) {
|
||||
return Result.fail(idOrError.error);
|
||||
}
|
||||
|
||||
@ -26,7 +26,7 @@ export class CustomerService {
|
||||
/**
|
||||
* Guarda una instancia de Customer en persistencia.
|
||||
*
|
||||
* @param customer - El agregado a guardar.
|
||||
* @param customer - El agregado a guardar (con el companyId ya asignado)
|
||||
* @param transaction - Transacción activa para la operación.
|
||||
* @returns Result<Customer, Error> - El agregado guardado o un error si falla la operación.
|
||||
*/
|
||||
|
||||
@ -10,9 +10,9 @@ export class DeleteCustomerController extends ExpressController {
|
||||
|
||||
async executeImpl(): Promise<any> {
|
||||
const companyId = this.getTenantId()!; // garantizado por tenantGuard
|
||||
const { id } = this.req.params;
|
||||
const { customer_id } = this.req.params;
|
||||
|
||||
const result = await this.useCase.execute({ id, companyId });
|
||||
const result = await this.useCase.execute({ customer_id, companyId });
|
||||
|
||||
return result.match(
|
||||
(data) => this.ok(data),
|
||||
|
||||
@ -10,11 +10,9 @@ export class GetCustomerController extends ExpressController {
|
||||
|
||||
protected async executeImpl() {
|
||||
const companyId = this.getTenantId()!; // garantizado por tenantGuard
|
||||
const { id } = this.req.params;
|
||||
const { customer_id } = this.req.params;
|
||||
|
||||
console.log(id);
|
||||
|
||||
const result = await this.useCase.execute({ id, companyId });
|
||||
const result = await this.useCase.execute({ customer_id, companyId });
|
||||
|
||||
return result.match(
|
||||
(data) => this.ok(data),
|
||||
|
||||
@ -11,10 +11,10 @@ export class UpdateCustomerController extends ExpressController {
|
||||
|
||||
protected async executeImpl() {
|
||||
const companyId = this.getTenantId()!; // garantizado por tenantGuard
|
||||
const { id } = this.req.params;
|
||||
const { customer_id } = this.req.params;
|
||||
const dto = this.req.body as UpdateCustomerRequestDTO;
|
||||
|
||||
const result = await this.useCase.execute({ id, companyId, dto });
|
||||
const result = await this.useCase.execute({ customer_id, companyId, dto });
|
||||
|
||||
return result.match(
|
||||
(data) => this.created(data),
|
||||
|
||||
@ -7,6 +7,7 @@ import {
|
||||
CustomerListRequestSchema,
|
||||
DeleteCustomerByIdRequestSchema,
|
||||
GetCustomerByIdRequestSchema,
|
||||
UpdateCustomerParamsRequestSchema,
|
||||
UpdateCustomerRequestSchema,
|
||||
} from "../../../common/dto";
|
||||
import { getCustomerDependencies } from "../dependencies";
|
||||
@ -51,7 +52,7 @@ export const customersRouter = (params: ModuleParams) => {
|
||||
);
|
||||
|
||||
router.get(
|
||||
"/:id",
|
||||
"/:customer_id",
|
||||
//checkTabContext,
|
||||
|
||||
validateRequest(GetCustomerByIdRequestSchema, "params"),
|
||||
@ -66,7 +67,7 @@ export const customersRouter = (params: ModuleParams) => {
|
||||
"/",
|
||||
//checkTabContext,
|
||||
|
||||
validateRequest(CreateCustomerRequestSchema),
|
||||
validateRequest(CreateCustomerRequestSchema, "body"),
|
||||
(req: Request, res: Response, next: NextFunction) => {
|
||||
const useCase = deps.build.create();
|
||||
const controller = new CreateCustomerController(useCase);
|
||||
@ -75,10 +76,10 @@ export const customersRouter = (params: ModuleParams) => {
|
||||
);
|
||||
|
||||
router.put(
|
||||
"/:customerId",
|
||||
"/:customer_id",
|
||||
//checkTabContext,
|
||||
|
||||
validateRequest(UpdateCustomerRequestSchema),
|
||||
validateRequest(UpdateCustomerParamsRequestSchema, "params"),
|
||||
validateRequest(UpdateCustomerRequestSchema, "body"),
|
||||
(req: Request, res: Response, next: NextFunction) => {
|
||||
const useCase = deps.build.update();
|
||||
const controller = new UpdateCustomerController(useCase);
|
||||
@ -87,7 +88,7 @@ export const customersRouter = (params: ModuleParams) => {
|
||||
);
|
||||
|
||||
router.delete(
|
||||
"/:id",
|
||||
"/:customer_id",
|
||||
//checkTabContext,
|
||||
|
||||
validateRequest(DeleteCustomerByIdRequestSchema, "params"),
|
||||
|
||||
@ -211,41 +211,42 @@ export class CustomerMapper
|
||||
}
|
||||
|
||||
public mapToPersistence(source: Customer, params?: MapperParamsType): CustomerCreationAttributes {
|
||||
return {
|
||||
const customerValues: Partial<CustomerCreationAttributes> = {
|
||||
id: source.id.toPrimitive(),
|
||||
company_id: source.companyId.toPrimitive(),
|
||||
|
||||
reference: source.reference.match(
|
||||
(value) => value.toPrimitive(),
|
||||
() => ""
|
||||
),
|
||||
|
||||
reference: toNullable(source.reference, (reference) => reference.toPrimitive()),
|
||||
is_company: source.isCompany,
|
||||
name: source.name.toPrimitive(),
|
||||
trade_name: toNullable(source.tradeName, (trade_name) => trade_name.toPrimitive()),
|
||||
trade_name: toNullable(source.tradeName, (tradeName) => tradeName.toPrimitive()),
|
||||
tin: toNullable(source.tin, (tin) => tin.toPrimitive()),
|
||||
|
||||
street: toNullable(source.address.street, (street) => street.toPrimitive()),
|
||||
street2: toNullable(source.address.street2, (street2) => street2.toPrimitive()),
|
||||
city: toNullable(source.address.city, (city) => city.toPrimitive()),
|
||||
province: toNullable(source.address.province, (province) => province.toPrimitive()),
|
||||
postal_code: toNullable(source.address.postalCode, (postal_code) =>
|
||||
postal_code.toPrimitive()
|
||||
),
|
||||
country: toNullable(source.address.country, (country) => country.toPrimitive()),
|
||||
|
||||
email: toNullable(source.email, (email) => email.toPrimitive()),
|
||||
phone: toNullable(source.phone, (phone) => phone.toPrimitive()),
|
||||
fax: toNullable(source.fax, (fax) => fax.toPrimitive()),
|
||||
website: toNullable(source.website, (website) => website.toPrimitive()),
|
||||
|
||||
legal_record: toNullable(source.legalRecord, (legal_record) => legal_record.toPrimitive()),
|
||||
|
||||
default_taxes: source.defaultTaxes.map((item) => item.toPrimitive()).join(", "),
|
||||
legal_record: toNullable(source.legalRecord, (legalRecord) => legalRecord.toPrimitive()),
|
||||
default_taxes: source.defaultTaxes.map((taxItem) => taxItem.toPrimitive()).join(", "),
|
||||
|
||||
status: source.isActive ? "active" : "inactive",
|
||||
language_code: source.languageCode.toPrimitive(),
|
||||
currency_code: source.currencyCode.toPrimitive(),
|
||||
};
|
||||
|
||||
if (source.address) {
|
||||
Object.assign(customerValues, {
|
||||
street: toNullable(source.address.street, (street) => street.toPrimitive()),
|
||||
street2: toNullable(source.address.street2, (street2) => street2.toPrimitive()),
|
||||
city: toNullable(source.address.city, (city) => city.toPrimitive()),
|
||||
province: toNullable(source.address.province, (province) => province.toPrimitive()),
|
||||
postal_code: toNullable(source.address.postalCode, (postalCode) =>
|
||||
postalCode.toPrimitive()
|
||||
),
|
||||
country: toNullable(source.address.country, (country) => country.toPrimitive()),
|
||||
});
|
||||
}
|
||||
|
||||
return customerValues as CustomerCreationAttributes;
|
||||
}
|
||||
}
|
||||
|
||||
@ -57,8 +57,8 @@ export default (database: Sequelize) => {
|
||||
},
|
||||
reference: {
|
||||
type: DataTypes.STRING,
|
||||
allowNull: false,
|
||||
defaultValue: "",
|
||||
allowNull: true,
|
||||
defaultValue: null,
|
||||
},
|
||||
is_company: {
|
||||
type: DataTypes.BOOLEAN,
|
||||
@ -71,82 +71,82 @@ export default (database: Sequelize) => {
|
||||
},
|
||||
trade_name: {
|
||||
type: DataTypes.STRING,
|
||||
allowNull: false,
|
||||
defaultValue: "",
|
||||
allowNull: true,
|
||||
defaultValue: null,
|
||||
},
|
||||
tin: {
|
||||
type: DataTypes.STRING,
|
||||
allowNull: false,
|
||||
defaultValue: "",
|
||||
allowNull: true,
|
||||
defaultValue: null,
|
||||
},
|
||||
|
||||
street: {
|
||||
type: DataTypes.STRING,
|
||||
allowNull: false,
|
||||
defaultValue: "",
|
||||
allowNull: true,
|
||||
defaultValue: null,
|
||||
},
|
||||
street2: {
|
||||
type: DataTypes.STRING,
|
||||
allowNull: false,
|
||||
defaultValue: "",
|
||||
allowNull: true,
|
||||
defaultValue: null,
|
||||
},
|
||||
city: {
|
||||
type: DataTypes.STRING,
|
||||
allowNull: false,
|
||||
defaultValue: "",
|
||||
allowNull: true,
|
||||
defaultValue: null,
|
||||
},
|
||||
province: {
|
||||
type: DataTypes.STRING,
|
||||
allowNull: false,
|
||||
defaultValue: "",
|
||||
allowNull: true,
|
||||
defaultValue: null,
|
||||
},
|
||||
postal_code: {
|
||||
type: DataTypes.STRING,
|
||||
allowNull: false,
|
||||
defaultValue: "",
|
||||
allowNull: true,
|
||||
defaultValue: null,
|
||||
},
|
||||
country: {
|
||||
type: DataTypes.STRING,
|
||||
allowNull: false,
|
||||
defaultValue: "",
|
||||
allowNull: true,
|
||||
defaultValue: null,
|
||||
},
|
||||
|
||||
email: {
|
||||
type: DataTypes.STRING,
|
||||
allowNull: false,
|
||||
defaultValue: "",
|
||||
allowNull: true,
|
||||
defaultValue: null,
|
||||
validate: {
|
||||
isEmail: true,
|
||||
},
|
||||
},
|
||||
phone: {
|
||||
type: DataTypes.STRING,
|
||||
allowNull: false,
|
||||
defaultValue: "",
|
||||
allowNull: true,
|
||||
defaultValue: null,
|
||||
},
|
||||
fax: {
|
||||
type: DataTypes.STRING,
|
||||
allowNull: false,
|
||||
defaultValue: "",
|
||||
allowNull: true,
|
||||
defaultValue: null,
|
||||
},
|
||||
website: {
|
||||
type: DataTypes.STRING,
|
||||
allowNull: false,
|
||||
defaultValue: "",
|
||||
allowNull: true,
|
||||
defaultValue: null,
|
||||
validate: {
|
||||
isUrl: true,
|
||||
},
|
||||
},
|
||||
legal_record: {
|
||||
type: DataTypes.TEXT,
|
||||
allowNull: false,
|
||||
defaultValue: "",
|
||||
defaultValue: null,
|
||||
allowNull: true,
|
||||
},
|
||||
|
||||
default_taxes: {
|
||||
type: DataTypes.STRING,
|
||||
allowNull: true,
|
||||
defaultValue: null,
|
||||
allowNull: true,
|
||||
},
|
||||
|
||||
language_code: {
|
||||
|
||||
@ -7,7 +7,7 @@ import * as z from "zod/v4";
|
||||
*/
|
||||
|
||||
export const DeleteCustomerByIdRequestSchema = z.object({
|
||||
id: z.string(),
|
||||
customer_id: z.string(),
|
||||
});
|
||||
|
||||
export type DeleteCustomerByIdRequestDTO = z.infer<typeof DeleteCustomerByIdRequestSchema>;
|
||||
|
||||
@ -2,12 +2,12 @@ import * as z from "zod/v4";
|
||||
|
||||
/**
|
||||
* Este DTO es utilizado por el endpoint:
|
||||
* `GET /customers/:id` (consultar una factura por ID).
|
||||
* `GET /customers/:customer_id` (consultar una factura por ID).
|
||||
*
|
||||
*/
|
||||
|
||||
export const GetCustomerByIdRequestSchema = z.object({
|
||||
id: z.string(),
|
||||
customer_id: z.string(),
|
||||
});
|
||||
|
||||
export type GetCustomerByIdRequestDTO = z.infer<typeof GetCustomerByIdRequestSchema>;
|
||||
|
||||
@ -1,5 +1,9 @@
|
||||
import * as z from "zod/v4";
|
||||
|
||||
export const UpdateCustomerParamsRequestSchema = z.object({
|
||||
customer_id: z.string(),
|
||||
});
|
||||
|
||||
export const UpdateCustomerRequestSchema = z.object({
|
||||
reference: z.string().optional(),
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user