Facturas de cliente y clientes
This commit is contained in:
parent
3c1010adad
commit
335c2764b7
@ -1,36 +1,33 @@
|
||||
import { ExpressController, errorMapper } from "@erp/core/api";
|
||||
import { CreateCustomerCommandDTO } from "../../../../../common/dto";
|
||||
import { CreateCustomerUseCase } from "../../../../application";
|
||||
import {
|
||||
ExpressController,
|
||||
authGuard,
|
||||
errorMapper,
|
||||
forbidQueryFieldGuard,
|
||||
tenantGuard,
|
||||
} from "@erp/core/api";
|
||||
import { CreateCustomerRequestDTO } from "../../../../common/dto";
|
||||
import { CreateCustomerUseCase } from "../../../application";
|
||||
|
||||
export class CreateCustomerController extends ExpressController {
|
||||
public constructor(private readonly createCustomer: CreateCustomerUseCase) {
|
||||
public constructor(private readonly useCase: CreateCustomerUseCase) {
|
||||
super();
|
||||
// 🔐 Reutiliza guards de auth/tenant y prohíbe 'companyId' en query
|
||||
this.useGuards(authGuard(), tenantGuard(), forbidQueryFieldGuard("companyId"));
|
||||
}
|
||||
|
||||
protected async executeImpl() {
|
||||
const dto = this.req.body as CreateCustomerCommandDTO;
|
||||
const tenantId = this.getTenantId()!; // garantizado por tenantGuard
|
||||
const dto = this.req.body as CreateCustomerRequestDTO;
|
||||
/*
|
||||
const user = this.req.user; // asumimos middleware authenticateJWT inyecta user
|
||||
|
||||
if (!user || !user.companyId) {
|
||||
this.unauthorized(res, "Unauthorized: user or company not found");
|
||||
return;
|
||||
}
|
||||
|
||||
// Inyectar empresa del usuario autenticado (ownership)
|
||||
dto.customerCompanyId = user.companyId;
|
||||
*/
|
||||
|
||||
const result = await this.createCustomer.execute(dto);
|
||||
const result = await this.useCase.execute(dto);
|
||||
|
||||
if (result.isFailure) {
|
||||
console.log(result.error);
|
||||
const apiError = errorMapper.toApiError(result.error);
|
||||
return this.handleApiError(apiError);
|
||||
}
|
||||
|
||||
return this.created(result.data);
|
||||
return result.match(
|
||||
(data) => this.created(data),
|
||||
(err) => this.handleApiError(errorMapper.toApiError(err))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,32 +1,28 @@
|
||||
import { ExpressController, errorMapper } from "@erp/core/api";
|
||||
import { DeleteCustomerUseCase } from "../../../../application";
|
||||
import {
|
||||
ExpressController,
|
||||
authGuard,
|
||||
errorMapper,
|
||||
forbidQueryFieldGuard,
|
||||
tenantGuard,
|
||||
} from "@erp/core/api";
|
||||
import { DeleteCustomerUseCase } from "../../../application";
|
||||
|
||||
export class DeleteCustomerController extends ExpressController {
|
||||
public constructor(private readonly deleteCustomer: DeleteCustomerUseCase) {
|
||||
public constructor(private readonly useCase: DeleteCustomerUseCase) {
|
||||
super();
|
||||
// 🔐 Reutiliza guards de auth/tenant y prohíbe 'companyId' en query
|
||||
this.useGuards(authGuard(), tenantGuard(), forbidQueryFieldGuard("companyId"));
|
||||
}
|
||||
|
||||
async executeImpl(): Promise<any> {
|
||||
const tenantId = this.getTenantId()!; // garantizado por tenantGuard
|
||||
const { id } = this.req.params;
|
||||
|
||||
/*
|
||||
const user = this.req.user; // asumimos middleware authenticateJWT inyecta user
|
||||
const result = await this.useCase.execute({ id, tenantId });
|
||||
|
||||
if (!user || !user.companyId) {
|
||||
this.unauthorized(res, "Unauthorized: user or company not found");
|
||||
return;
|
||||
}
|
||||
*/
|
||||
|
||||
const result = await this.deleteCustomer.execute({ id });
|
||||
|
||||
if (result.isFailure) {
|
||||
const apiError = errorMapper.toApiError(result.error);
|
||||
return this.handleApiError(apiError);
|
||||
}
|
||||
|
||||
return this.ok(result.data);
|
||||
return result.match(
|
||||
(data) => this.ok(data),
|
||||
(error) => this.handleApiError(errorMapper.toApiError(error))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,32 +1,28 @@
|
||||
import { ExpressController, errorMapper } from "@erp/core/api";
|
||||
import {
|
||||
ExpressController,
|
||||
authGuard,
|
||||
errorMapper,
|
||||
forbidQueryFieldGuard,
|
||||
tenantGuard,
|
||||
} from "@erp/core/api";
|
||||
import { GetCustomerUseCase } from "../../../application";
|
||||
|
||||
export class GetCustomerController extends ExpressController {
|
||||
public constructor(private readonly getCustomer: GetCustomerUseCase) {
|
||||
public constructor(private readonly useCase: GetCustomerUseCase) {
|
||||
super();
|
||||
// 🔐 Reutiliza guards de auth/tenant y prohíbe 'companyId' en query
|
||||
this.useGuards(authGuard(), tenantGuard(), forbidQueryFieldGuard("companyId"));
|
||||
}
|
||||
|
||||
protected async executeImpl() {
|
||||
const tenantId = this.getTenantId()!; // garantizado por tenantGuard
|
||||
const { id } = this.req.params;
|
||||
|
||||
/*
|
||||
const user = this.req.user; // asumimos middleware authenticateJWT inyecta user
|
||||
const result = await this.useCase.execute({ id, tenantId });
|
||||
|
||||
if (!user || !user.companyId) {
|
||||
this.unauthorized(res, "Unauthorized: user or company not found");
|
||||
return;
|
||||
}
|
||||
*/
|
||||
|
||||
const result = await this.getCustomer.execute({ id });
|
||||
|
||||
if (result.isFailure) {
|
||||
const apiError = errorMapper.toApiError(result.error);
|
||||
return this.handleApiError(apiError);
|
||||
}
|
||||
|
||||
return this.ok(result.data);
|
||||
return result.match(
|
||||
(data) => this.ok(data),
|
||||
(error) => this.handleApiError(errorMapper.toApiError(error))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -2,35 +2,30 @@ import * as z from "zod/v4";
|
||||
|
||||
export const CreateCustomerRequestSchema = z.object({
|
||||
id: z.uuid(),
|
||||
invoice_status: z.string(),
|
||||
invoice_number: z.string().min(1, "Customer invoice number is required"),
|
||||
invoice_series: z.string().min(1, "Customer invoice series is required"),
|
||||
issue_date: z.string().datetime({ offset: true, message: "Invalid issue date format" }),
|
||||
operation_date: z.string().datetime({ offset: true, message: "Invalid operation date format" }),
|
||||
description: z.string(),
|
||||
language_code: z.string().min(2, "Language code must be at least 2 characters long"),
|
||||
currency_code: z.string().min(3, "Currency code must be at least 3 characters long"),
|
||||
notes: z.string().optional(),
|
||||
items: z.array(
|
||||
z.object({
|
||||
description: z.string().min(1, "Item description is required"),
|
||||
quantity: z.object({
|
||||
amount: z.number().positive("Quantity amount must be positive"),
|
||||
scale: z.number().int().nonnegative("Quantity scale must be a non-negative integer"),
|
||||
}),
|
||||
unit_price: z.object({
|
||||
amount: z.number().positive("Unit price amount must be positive"),
|
||||
scale: z.number().int().nonnegative("Unit price scale must be a non-negative integer"),
|
||||
currency_code: z
|
||||
.string()
|
||||
.min(3, "Unit price currency code must be at least 3 characters long"),
|
||||
}),
|
||||
discount: z.object({
|
||||
amount: z.number().nonnegative("Discount amount cannot be negative"),
|
||||
scale: z.number().int().nonnegative("Discount scale must be a non-negative integer"),
|
||||
}),
|
||||
})
|
||||
),
|
||||
reference: z.string(),
|
||||
|
||||
is_freelancer: z.boolean(),
|
||||
name: z.string(),
|
||||
trade_name: z.string(),
|
||||
tin: z.string(),
|
||||
|
||||
street: z.string(),
|
||||
city: z.string(),
|
||||
state: z.string(),
|
||||
postal_code: z.string(),
|
||||
country: z.string(),
|
||||
|
||||
email: z.string(),
|
||||
phone: z.string(),
|
||||
fax: z.string(),
|
||||
website: z.string(),
|
||||
|
||||
legal_record: z.string(),
|
||||
|
||||
default_tax: z.number(),
|
||||
status: z.string(),
|
||||
lang_code: z.string(),
|
||||
currency_code: z.string(),
|
||||
});
|
||||
|
||||
export type CreateCustomerRequestDTO = z.infer<typeof CreateCustomerRequestSchema>;
|
||||
|
||||
@ -3,13 +3,30 @@ import * as z from "zod/v4";
|
||||
|
||||
export const CustomerCreationResponseSchema = 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(),
|
||||
reference: z.string(),
|
||||
|
||||
is_freelancer: z.boolean(),
|
||||
name: z.string(),
|
||||
trade_name: z.string(),
|
||||
tin: z.string(),
|
||||
|
||||
street: z.string(),
|
||||
city: z.string(),
|
||||
state: z.string(),
|
||||
postal_code: z.string(),
|
||||
country: z.string(),
|
||||
|
||||
email: z.string(),
|
||||
phone: z.string(),
|
||||
fax: z.string(),
|
||||
website: z.string(),
|
||||
|
||||
legal_record: z.string(),
|
||||
|
||||
default_tax: z.number(),
|
||||
status: z.string(),
|
||||
lang_code: z.string(),
|
||||
currency_code: z.string(),
|
||||
|
||||
metadata: MetadataSchema.optional(),
|
||||
});
|
||||
|
||||
@ -3,13 +3,30 @@ import * as z from "zod/v4";
|
||||
|
||||
export const GetCustomerByIdResponseSchema = 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(),
|
||||
reference: z.string(),
|
||||
|
||||
is_freelancer: z.boolean(),
|
||||
name: z.string(),
|
||||
trade_name: z.string(),
|
||||
tin: z.string(),
|
||||
|
||||
street: z.string(),
|
||||
city: z.string(),
|
||||
state: z.string(),
|
||||
postal_code: z.string(),
|
||||
country: z.string(),
|
||||
|
||||
email: z.string(),
|
||||
phone: z.string(),
|
||||
fax: z.string(),
|
||||
website: z.string(),
|
||||
|
||||
legal_record: z.string(),
|
||||
|
||||
default_tax: z.number(),
|
||||
status: z.string(),
|
||||
lang_code: z.string(),
|
||||
currency_code: z.string(),
|
||||
|
||||
metadata: MetadataSchema.optional(),
|
||||
});
|
||||
|
||||
@ -31,5 +31,5 @@
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
"packageManager": "pnpm@10.14.0"
|
||||
"packageManager": "pnpm@10.15.0"
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user