Facturas de cliente
This commit is contained in:
parent
d17a22dc9f
commit
2e4bb56458
@ -1,3 +1,5 @@
|
|||||||
export * from "./spain-tax-catalog-provider";
|
export * from "./json-tax-catalog.provider";
|
||||||
export * from "./tax-catalog-provider";
|
export * from "./spain-tax-catalog.provider";
|
||||||
export * from "./tax-catalog-types";
|
export * from "./tax-catalog-types";
|
||||||
|
export * from "./tax-catalog.provider";
|
||||||
|
|
||||||
|
|||||||
@ -1,8 +1,8 @@
|
|||||||
// --- Adaptador que carga el catálogo JSON en memoria e indexa por code ---
|
// --- Adaptador que carga el catálogo JSON en memoria e indexa por code ---
|
||||||
|
|
||||||
import { Maybe } from "@repo/rdx-utils";
|
import { Maybe } from "@repo/rdx-utils";
|
||||||
import { TaxCatalogProvider } from "./tax-catalog-provider";
|
|
||||||
import { TaxCatalogType, TaxItemType } from "./tax-catalog-types";
|
import { TaxCatalogType, TaxItemType } from "./tax-catalog-types";
|
||||||
|
import { TaxCatalogProvider } from "./tax-catalog.provider";
|
||||||
|
|
||||||
// Si quieres habilitar la carga desde fichero en Node:
|
// Si quieres habilitar la carga desde fichero en Node:
|
||||||
// import * as fs from "node:fs";
|
// import * as fs from "node:fs";
|
||||||
@ -1,4 +1,4 @@
|
|||||||
import { JsonTaxCatalogProvider } from "./json-tax-catalog-provider";
|
import { JsonTaxCatalogProvider } from "./json-tax-catalog.provider";
|
||||||
import spainTaxCatalog from "./spain-tax-catalog.json";
|
import spainTaxCatalog from "./spain-tax-catalog.json";
|
||||||
|
|
||||||
export const spainTaxCatalogProvider = new JsonTaxCatalogProvider(spainTaxCatalog);
|
export const spainTaxCatalogProvider = new JsonTaxCatalogProvider(spainTaxCatalog);
|
||||||
@ -1,3 +1,4 @@
|
|||||||
|
import { JsonTaxCatalogProvider } from "@erp/core";
|
||||||
import { DuplicateEntityError, ITransactionManager } from "@erp/core/api";
|
import { DuplicateEntityError, ITransactionManager } from "@erp/core/api";
|
||||||
import { UniqueID } from "@repo/rdx-ddd";
|
import { UniqueID } from "@repo/rdx-ddd";
|
||||||
import { Result } from "@repo/rdx-utils";
|
import { Result } from "@repo/rdx-utils";
|
||||||
@ -5,7 +6,7 @@ import { Transaction } from "sequelize";
|
|||||||
import { CreateCustomerInvoiceRequestDTO } from "../../../common/dto";
|
import { CreateCustomerInvoiceRequestDTO } from "../../../common/dto";
|
||||||
import { CustomerInvoiceService } from "../../domain";
|
import { CustomerInvoiceService } from "../../domain";
|
||||||
import { CreateCustomerInvoiceAssembler } from "./assembler";
|
import { CreateCustomerInvoiceAssembler } from "./assembler";
|
||||||
import { mapDTOToCreateCustomerInvoiceProps } from "./map-dto-to-create-customer-invoice-props";
|
import { CreateCustomerInvoicePropsMapper } from "./map-dto-to-create-customer-invoice-props";
|
||||||
|
|
||||||
type CreateCustomerInvoiceUseCaseInput = {
|
type CreateCustomerInvoiceUseCaseInput = {
|
||||||
companyId: UniqueID;
|
companyId: UniqueID;
|
||||||
@ -16,14 +17,17 @@ export class CreateCustomerInvoiceUseCase {
|
|||||||
constructor(
|
constructor(
|
||||||
private readonly service: CustomerInvoiceService,
|
private readonly service: CustomerInvoiceService,
|
||||||
private readonly transactionManager: ITransactionManager,
|
private readonly transactionManager: ITransactionManager,
|
||||||
private readonly assembler: CreateCustomerInvoiceAssembler
|
private readonly assembler: CreateCustomerInvoiceAssembler,
|
||||||
|
private readonly taxCatalog: JsonTaxCatalogProvider,
|
||||||
|
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
public execute(params: CreateCustomerInvoiceUseCaseInput) {
|
public execute(params: CreateCustomerInvoiceUseCaseInput) {
|
||||||
const { dto, companyId } = params;
|
const { dto, companyId } = params;
|
||||||
|
const dtoMapper = new CreateCustomerInvoicePropsMapper({ taxCatalog: this.taxCatalog });
|
||||||
|
|
||||||
// 1) Mapear DTO → props de dominio
|
// 1) Mapear DTO → props de dominio
|
||||||
const dtoResult = mapDTOToCreateCustomerInvoiceProps(dto);
|
const dtoResult = dtoMapper.map(dto);
|
||||||
if (dtoResult.isFailure) {
|
if (dtoResult.isFailure) {
|
||||||
return Result.fail(dtoResult.error);
|
return Result.fail(dtoResult.error);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { spainTaxCatalogProvider } from "@erp/core";
|
import { JsonTaxCatalogProvider } from "@erp/core";
|
||||||
import {
|
import {
|
||||||
DomainError,
|
DomainError,
|
||||||
Tax,
|
Tax,
|
||||||
@ -45,181 +45,189 @@ import {
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export function mapDTOToCreateCustomerInvoiceProps(dto: CreateCustomerInvoiceRequestDTO) {
|
export class CreateCustomerInvoicePropsMapper {
|
||||||
try {
|
private readonly taxCatalog: JsonTaxCatalogProvider;
|
||||||
const errors: ValidationErrorDetail[] = [];
|
private errors: ValidationErrorDetail[] = [];
|
||||||
|
private languageCode?: LanguageCode;
|
||||||
|
private currencyCode?: CurrencyCode;
|
||||||
|
|
||||||
const customerId = extractOrPushError(UniqueID.create(dto.id), "id", errors);
|
constructor(params: {taxCatalog: JsonTaxCatalogProvider}) {
|
||||||
const companyId = extractOrPushError(UniqueID.create(dto.company_id), "company_id", errors);
|
this.taxCatalog = params.taxCatalog;
|
||||||
|
this.errors = [];
|
||||||
|
}
|
||||||
|
|
||||||
const invoiceNumber = extractOrPushError(
|
public map(dto: CreateCustomerInvoiceRequestDTO) {
|
||||||
CustomerInvoiceNumber.create(dto.invoice_number),
|
try {
|
||||||
"invoice_number",
|
this.errors = [];
|
||||||
errors
|
|
||||||
);
|
|
||||||
const status = extractOrPushError(CustomerInvoiceStatus.create(dto.status), "status", errors);
|
|
||||||
|
|
||||||
const series = extractOrPushError(
|
const defaultStatus = CustomerInvoiceStatus.createDraft();
|
||||||
maybeFromNullableVO(dto.series, (value) => CustomerInvoiceSerie.create(value)),
|
|
||||||
"series",
|
|
||||||
errors
|
|
||||||
);
|
|
||||||
|
|
||||||
const invoiceDate = extractOrPushError(
|
const invoiceId = extractOrPushError(UniqueID.create(dto.id), "id", this.errors);
|
||||||
UtcDate.createFromISO(dto.invoice_date),
|
const companyId = extractOrPushError(UniqueID.create(dto.company_id), "company_id", this.errors);
|
||||||
"invoice_date",
|
const customerId = extractOrPushError(UniqueID.create(dto.customer_id), "customer_id", this.errors);
|
||||||
errors
|
|
||||||
);
|
|
||||||
|
|
||||||
const operationDate = extractOrPushError(
|
const invoiceNumber = extractOrPushError(
|
||||||
maybeFromNullableVO(dto.operation_date, (value) => UtcDate.createFromISO(value)),
|
CustomerInvoiceNumber.create(dto.invoice_number),
|
||||||
"operation_date",
|
"invoice_number",
|
||||||
errors
|
this.errors
|
||||||
);
|
|
||||||
|
|
||||||
const notes = extractOrPushError(
|
|
||||||
maybeFromNullableVO(dto.notes, (value) => TextValue.create(value)),
|
|
||||||
"notes",
|
|
||||||
errors
|
|
||||||
);
|
|
||||||
|
|
||||||
const languageCode = extractOrPushError(
|
|
||||||
LanguageCode.create(dto.language_code),
|
|
||||||
"language_code",
|
|
||||||
errors
|
|
||||||
);
|
|
||||||
|
|
||||||
const currencyCode = extractOrPushError(
|
|
||||||
CurrencyCode.create(dto.currency_code),
|
|
||||||
"currency_code",
|
|
||||||
errors
|
|
||||||
);
|
|
||||||
|
|
||||||
const discountPercentage = extractOrPushError(
|
|
||||||
Percentage.create({
|
|
||||||
value: Number(dto.discount_percentage.value),
|
|
||||||
scale: Number(dto.discount_percentage.scale),
|
|
||||||
}),
|
|
||||||
"discount_percentage",
|
|
||||||
errors
|
|
||||||
);
|
|
||||||
|
|
||||||
const items = _mapDTOtoInvoiceItems(dto.items, languageCode!, currencyCode!, errors);
|
|
||||||
|
|
||||||
if (errors.length > 0) {
|
|
||||||
return Result.fail(
|
|
||||||
new ValidationErrorCollection("Customer invoice props mapping failed", errors)
|
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const series = extractOrPushError(
|
||||||
|
maybeFromNullableVO(dto.series, (value) => CustomerInvoiceSerie.create(value)),
|
||||||
|
"series",
|
||||||
|
this.errors
|
||||||
|
);
|
||||||
|
|
||||||
|
const invoiceDate = extractOrPushError(
|
||||||
|
UtcDate.createFromISO(dto.invoice_date),
|
||||||
|
"invoice_date",
|
||||||
|
this.errors
|
||||||
|
);
|
||||||
|
|
||||||
|
const operationDate = extractOrPushError(
|
||||||
|
maybeFromNullableVO(dto.operation_date, (value) => UtcDate.createFromISO(value)),
|
||||||
|
"operation_date",
|
||||||
|
this.errors
|
||||||
|
);
|
||||||
|
|
||||||
|
const notes = extractOrPushError(
|
||||||
|
maybeFromNullableVO(dto.notes, (value) => TextValue.create(value)),
|
||||||
|
"notes",
|
||||||
|
this.errors
|
||||||
|
);
|
||||||
|
|
||||||
|
this.languageCode = extractOrPushError(
|
||||||
|
LanguageCode.create(dto.language_code),
|
||||||
|
"language_code",
|
||||||
|
this.errors
|
||||||
|
);
|
||||||
|
|
||||||
|
this.currencyCode = extractOrPushError(
|
||||||
|
CurrencyCode.create(dto.currency_code),
|
||||||
|
"currency_code",
|
||||||
|
this.errors
|
||||||
|
);
|
||||||
|
|
||||||
|
const discountPercentage = extractOrPushError(
|
||||||
|
Percentage.create({
|
||||||
|
value: Number(dto.discount_percentage.value),
|
||||||
|
scale: Number(dto.discount_percentage.scale),
|
||||||
|
}),
|
||||||
|
"discount_percentage",
|
||||||
|
this.errors
|
||||||
|
);
|
||||||
|
|
||||||
|
const items = this.mapItems(dto.items);
|
||||||
|
|
||||||
|
if (this.errors.length > 0) {
|
||||||
|
return Result.fail(
|
||||||
|
new ValidationErrorCollection("Customer invoice props mapping failed", this.errors)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const invoiceProps: CustomerInvoiceProps = {
|
||||||
|
companyId: companyId!,
|
||||||
|
status: defaultStatus!,
|
||||||
|
|
||||||
|
invoiceNumber: invoiceNumber!,
|
||||||
|
invoiceDate: invoiceDate!,
|
||||||
|
|
||||||
|
operationDate: operationDate!,
|
||||||
|
series: series!,
|
||||||
|
|
||||||
|
notes: notes!,
|
||||||
|
|
||||||
|
customerId: customerId!,
|
||||||
|
|
||||||
|
languageCode: this.languageCode!,
|
||||||
|
currencyCode: this.currencyCode!,
|
||||||
|
|
||||||
|
discountPercentage: discountPercentage!,
|
||||||
|
|
||||||
|
taxes: Taxes.create({ items: [] }),
|
||||||
|
items: items,
|
||||||
|
};
|
||||||
|
|
||||||
|
return Result.ok({ id: invoiceId!, props: invoiceProps });
|
||||||
|
} catch (err: unknown) {
|
||||||
|
return Result.fail(new DomainError("Customer invoice props mapping failed", { cause: err }));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const invoiceProps: CustomerInvoiceProps = {
|
private mapItems(items: CreateCustomerInvoiceItemRequestDTO[]) {
|
||||||
companyId: companyId!,
|
const invoiceItems = CustomerInvoiceItems.create({
|
||||||
status: status!,
|
currencyCode: this.currencyCode!,
|
||||||
|
languageCode: this.languageCode!,
|
||||||
|
items: [],
|
||||||
|
});
|
||||||
|
|
||||||
invoiceNumber: invoiceNumber!,
|
items.forEach((item, index) => {
|
||||||
invoiceDate: invoiceDate!,
|
const description = extractOrPushError(
|
||||||
|
maybeFromNullableVO(item.description, (value) =>
|
||||||
|
CustomerInvoiceItemDescription.create(value)
|
||||||
|
),
|
||||||
|
"description",
|
||||||
|
this.errors
|
||||||
|
);
|
||||||
|
|
||||||
operationDate: operationDate!,
|
const quantity = extractOrPushError(
|
||||||
series: series!,
|
maybeFromNullableVO(item.quantity, (value) => ItemQuantity.create(value)),
|
||||||
|
"quantity",
|
||||||
|
this.errors
|
||||||
|
);
|
||||||
|
|
||||||
notes: notes!,
|
const unitAmount = extractOrPushError(
|
||||||
|
maybeFromNullableVO(item.unit_amount, (value) => ItemAmount.create(value)),
|
||||||
|
"unit_amount",
|
||||||
|
this.errors
|
||||||
|
);
|
||||||
|
|
||||||
languageCode: languageCode!,
|
const discountPercentage = extractOrPushError(
|
||||||
currencyCode: currencyCode!,
|
maybeFromNullableVO(item.discount_percentage, (value) => ItemDiscount.create(value)),
|
||||||
|
"discount_percentage",
|
||||||
|
this.errors
|
||||||
|
);
|
||||||
|
|
||||||
discountPercentage: discountPercentage!,
|
const taxes = this.mapTaxes(item, index);
|
||||||
|
|
||||||
taxes: Taxes.create({ items: [] }),
|
const itemProps: CustomerInvoiceItemProps = {
|
||||||
items: items,
|
currencyCode: this.currencyCode!,
|
||||||
};
|
languageCode: this.languageCode!,
|
||||||
|
description: description!,
|
||||||
|
quantity: quantity!,
|
||||||
|
unitAmount: unitAmount!,
|
||||||
|
discountPercentage: discountPercentage!,
|
||||||
|
taxes,
|
||||||
|
};
|
||||||
|
|
||||||
return Result.ok({ id: customerId!, props: invoiceProps });
|
const itemResult = CustomerInvoiceItem.create(itemProps);
|
||||||
} catch (err: unknown) {
|
if (itemResult.isSuccess) {
|
||||||
return Result.fail(new DomainError("Customer invoice props mapping failed", { cause: err }));
|
invoiceItems.add(itemResult.data);
|
||||||
|
} else {
|
||||||
|
this.errors.push({
|
||||||
|
path: `items[${index}]`,
|
||||||
|
message: itemResult.error.message,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return invoiceItems;
|
||||||
|
}
|
||||||
|
|
||||||
|
private mapTaxes(item: CreateCustomerInvoiceItemRequestDTO, itemIndex: number) {
|
||||||
|
const taxes = Taxes.create({ items: [] });
|
||||||
|
|
||||||
|
item.taxes.split(",").every((tax_code, taxIndex) => {
|
||||||
|
const taxResult = Tax.createFromCode(tax_code, this.taxCatalog);
|
||||||
|
if (taxResult.isSuccess) {
|
||||||
|
taxes.add(taxResult.data);
|
||||||
|
} else {
|
||||||
|
this.errors.push({
|
||||||
|
path: `items[${itemIndex}].taxes[${taxIndex}]`,
|
||||||
|
message: taxResult.error.message,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return taxes;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function _mapDTOtoInvoiceItems(
|
|
||||||
items: CreateCustomerInvoiceItemRequestDTO[],
|
|
||||||
languageCode: LanguageCode,
|
|
||||||
currencyCode: CurrencyCode,
|
|
||||||
errors: ValidationErrorDetail[]
|
|
||||||
) {
|
|
||||||
const invoiceItems = CustomerInvoiceItems.create({
|
|
||||||
currencyCode,
|
|
||||||
languageCode,
|
|
||||||
items: [],
|
|
||||||
});
|
|
||||||
|
|
||||||
items.forEach((item, index) => {
|
|
||||||
const description = extractOrPushError(
|
|
||||||
maybeFromNullableVO(item.description, (value) =>
|
|
||||||
CustomerInvoiceItemDescription.create(value)
|
|
||||||
),
|
|
||||||
"description",
|
|
||||||
errors
|
|
||||||
);
|
|
||||||
|
|
||||||
const quantity = extractOrPushError(
|
|
||||||
maybeFromNullableVO(item.quantity, (value) => ItemQuantity.create(value)),
|
|
||||||
"quantity",
|
|
||||||
errors
|
|
||||||
);
|
|
||||||
|
|
||||||
const unitAmount = extractOrPushError(
|
|
||||||
maybeFromNullableVO(item.unit_amount, (value) => ItemAmount.create(value)),
|
|
||||||
"unit_amount",
|
|
||||||
errors
|
|
||||||
);
|
|
||||||
|
|
||||||
const discountPercentage = extractOrPushError(
|
|
||||||
maybeFromNullableVO(item.discount_percentage, (value) => ItemDiscount.create(value)),
|
|
||||||
"discount_percentage",
|
|
||||||
errors
|
|
||||||
);
|
|
||||||
|
|
||||||
const taxes = _mapDTOtoTaxes(item, index, errors);
|
|
||||||
|
|
||||||
const itemProps: CustomerInvoiceItemProps = {
|
|
||||||
currencyCode: currencyCode!,
|
|
||||||
languageCode: languageCode!,
|
|
||||||
description: description!,
|
|
||||||
quantity: quantity!,
|
|
||||||
unitAmount: unitAmount!,
|
|
||||||
discountPercentage: discountPercentage!,
|
|
||||||
taxes,
|
|
||||||
};
|
|
||||||
|
|
||||||
const itemResult = CustomerInvoiceItem.create(itemProps);
|
|
||||||
if (itemResult.isSuccess) {
|
|
||||||
invoiceItems.add(itemResult.data);
|
|
||||||
} else {
|
|
||||||
errors.push({
|
|
||||||
path: `items[${index}]`,
|
|
||||||
message: itemResult.error.message,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return invoiceItems;
|
|
||||||
}
|
|
||||||
|
|
||||||
function _mapDTOtoTaxes(
|
|
||||||
item: CreateCustomerInvoiceItemRequestDTO,
|
|
||||||
itemIndex: number,
|
|
||||||
errors: ValidationErrorDetail[]
|
|
||||||
) {
|
|
||||||
const taxes = Taxes.create({ items: [] });
|
|
||||||
|
|
||||||
item.taxes.split(",").every((tax_code, taxIndex) => {
|
|
||||||
const taxResult = Tax.createFromCode(tax_code, spainTaxCatalogProvider);
|
|
||||||
if (taxResult.isSuccess) {
|
|
||||||
taxes.add(taxResult.data);
|
|
||||||
} else {
|
|
||||||
errors.push({
|
|
||||||
path: `items[${itemIndex}].taxes[${taxIndex}]`,
|
|
||||||
message: taxResult.error.message,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return taxes;
|
|
||||||
}
|
|
||||||
|
|||||||
@ -13,7 +13,7 @@ export class GetCustomerInvoiceUseCase {
|
|||||||
constructor(
|
constructor(
|
||||||
private readonly service: CustomerInvoiceService,
|
private readonly service: CustomerInvoiceService,
|
||||||
private readonly transactionManager: ITransactionManager,
|
private readonly transactionManager: ITransactionManager,
|
||||||
private readonly assembler: GetCustomerInvoiceAssembler
|
private readonly assembler: GetCustomerInvoiceAssembler,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
public execute(params: GetCustomerInvoiceUseCaseInput) {
|
public execute(params: GetCustomerInvoiceUseCaseInput) {
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { Taxes } from "@erp/core/api";
|
import { DomainValidationError, Taxes } from "@erp/core/api";
|
||||||
import {
|
import {
|
||||||
AggregateRoot,
|
AggregateRoot,
|
||||||
CurrencyCode,
|
CurrencyCode,
|
||||||
@ -10,7 +10,7 @@ import {
|
|||||||
UtcDate,
|
UtcDate,
|
||||||
} from "@repo/rdx-ddd";
|
} from "@repo/rdx-ddd";
|
||||||
import { Maybe, Result } from "@repo/rdx-utils";
|
import { Maybe, Result } from "@repo/rdx-utils";
|
||||||
import { CustomerInvoiceItems } from "../entities";
|
import { CustomerInvoiceItems, InvoiceRecipient } from "../entities";
|
||||||
import {
|
import {
|
||||||
CustomerInvoiceNumber,
|
CustomerInvoiceNumber,
|
||||||
CustomerInvoiceSerie,
|
CustomerInvoiceSerie,
|
||||||
@ -27,6 +27,10 @@ export interface CustomerInvoiceProps {
|
|||||||
invoiceDate: UtcDate;
|
invoiceDate: UtcDate;
|
||||||
operationDate: Maybe<UtcDate>;
|
operationDate: Maybe<UtcDate>;
|
||||||
|
|
||||||
|
customerId: UniqueID;
|
||||||
|
|
||||||
|
recipient: Maybe<InvoiceRecipient>;
|
||||||
|
|
||||||
notes: Maybe<TextValue>;
|
notes: Maybe<TextValue>;
|
||||||
|
|
||||||
//dueDate: UtcDate; // ? --> depende de la forma de pago
|
//dueDate: UtcDate; // ? --> depende de la forma de pago
|
||||||
@ -52,7 +56,7 @@ export interface CustomerInvoiceProps {
|
|||||||
|
|
||||||
//totalAmount: MoneyValue;
|
//totalAmount: MoneyValue;
|
||||||
|
|
||||||
//customer?: CustomerInvoiceCustomer;
|
|
||||||
items: CustomerInvoiceItems;
|
items: CustomerInvoiceItems;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -75,9 +79,17 @@ export class CustomerInvoice extends AggregateRoot<CustomerInvoiceProps> {
|
|||||||
const customerInvoice = new CustomerInvoice(props, id);
|
const customerInvoice = new CustomerInvoice(props, id);
|
||||||
|
|
||||||
// Reglas de negocio / validaciones
|
// Reglas de negocio / validaciones
|
||||||
// ...
|
|
||||||
// ...
|
|
||||||
|
|
||||||
|
|
||||||
|
if (!customerInvoice.isDraft() && !customerInvoice.hasRecipient()) {
|
||||||
|
return Result.fail(
|
||||||
|
new DomainValidationError(
|
||||||
|
"MISSING_CUSTOMER_DATA",
|
||||||
|
"customerData",
|
||||||
|
"Customer data must be provided for non-draft invoices"
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
// 🔹 Disparar evento de dominio "CustomerInvoiceAuthenticatedEvent"
|
// 🔹 Disparar evento de dominio "CustomerInvoiceAuthenticatedEvent"
|
||||||
//const { customerInvoice } = props;
|
//const { customerInvoice } = props;
|
||||||
//user.addDomainEvent(new CustomerInvoiceAuthenticatedEvent(id, customerInvoice.toString()));
|
//user.addDomainEvent(new CustomerInvoiceAuthenticatedEvent(id, customerInvoice.toString()));
|
||||||
@ -93,6 +105,10 @@ export class CustomerInvoice extends AggregateRoot<CustomerInvoiceProps> {
|
|||||||
return this.props.companyId;
|
return this.props.companyId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public get customerId(): UniqueID {
|
||||||
|
return this.props.customerId;
|
||||||
|
}
|
||||||
|
|
||||||
public get status(): CustomerInvoiceStatus {
|
public get status(): CustomerInvoiceStatus {
|
||||||
return this.props.status;
|
return this.props.status;
|
||||||
}
|
}
|
||||||
@ -117,6 +133,10 @@ export class CustomerInvoice extends AggregateRoot<CustomerInvoiceProps> {
|
|||||||
return this.props.notes;
|
return this.props.notes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public get recipient(): Maybe<InvoiceRecipient> {
|
||||||
|
return this.props.recipient;
|
||||||
|
}
|
||||||
|
|
||||||
public get languageCode(): LanguageCode {
|
public get languageCode(): LanguageCode {
|
||||||
return this.props.languageCode;
|
return this.props.languageCode;
|
||||||
}
|
}
|
||||||
@ -154,6 +174,14 @@ export class CustomerInvoice extends AggregateRoot<CustomerInvoiceProps> {
|
|||||||
return this._items;
|
return this._items;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public isDraft() {
|
||||||
|
return this.status.isDraft();
|
||||||
|
}
|
||||||
|
|
||||||
|
public hasRecipient() {
|
||||||
|
return this.recipient.isSome()
|
||||||
|
}
|
||||||
|
|
||||||
/*get senderId(): UniqueID {
|
/*get senderId(): UniqueID {
|
||||||
return this.props.senderId;
|
return this.props.senderId;
|
||||||
}*/
|
}*/
|
||||||
|
|||||||
@ -1,2 +1,4 @@
|
|||||||
export * from "./customer-invoice-items";
|
export * from "./customer-invoice-items";
|
||||||
export * from "./invoice-customer";
|
export * from "./invoice-customer";
|
||||||
|
export * from "./invoice-recipient";
|
||||||
|
|
||||||
|
|||||||
@ -0,0 +1,3 @@
|
|||||||
|
export * from "./invoice-recipient";
|
||||||
|
|
||||||
|
|
||||||
@ -0,0 +1,103 @@
|
|||||||
|
import {
|
||||||
|
City,
|
||||||
|
Country,
|
||||||
|
Name,
|
||||||
|
PostalCode,
|
||||||
|
Province,
|
||||||
|
Street,
|
||||||
|
TINNumber,
|
||||||
|
ValueObject
|
||||||
|
} from "@repo/rdx-ddd";
|
||||||
|
import { Maybe, Result } from "@repo/rdx-utils";
|
||||||
|
import * as z from "zod/v4";
|
||||||
|
|
||||||
|
export interface InvoiceRecipientProps {
|
||||||
|
name: Name;
|
||||||
|
tin: TINNumber;
|
||||||
|
street: Maybe<Street>;
|
||||||
|
street2: Maybe<Street>;
|
||||||
|
city: Maybe<City>;
|
||||||
|
postalCode: Maybe<PostalCode>;
|
||||||
|
province: Maybe<Province>;
|
||||||
|
country: Maybe<Country>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class InvoiceRecipient extends ValueObject<InvoiceRecipientProps> {
|
||||||
|
protected static validate(values: InvoiceRecipientProps) {
|
||||||
|
const schema = z.object({
|
||||||
|
name: z.string(),
|
||||||
|
tin: z.string(),
|
||||||
|
street: z.string().optional(),
|
||||||
|
street2: z.string().optional(),
|
||||||
|
city: z.string().optional(),
|
||||||
|
postalCode: z.string().optional(),
|
||||||
|
province: z.string().optional(),
|
||||||
|
country: z.string().optional(),
|
||||||
|
})
|
||||||
|
|
||||||
|
return schema.safeParse(values);
|
||||||
|
}
|
||||||
|
|
||||||
|
static create(values: InvoiceRecipientProps): Result<InvoiceRecipient, Error> {
|
||||||
|
const valueIsValid = InvoiceRecipient.validate(values)
|
||||||
|
|
||||||
|
if (!valueIsValid.success) {
|
||||||
|
return Result.fail(new Error(valueIsValid.error.issues[0].message));
|
||||||
|
}
|
||||||
|
|
||||||
|
return Result.ok(new InvoiceRecipient(values));
|
||||||
|
}
|
||||||
|
|
||||||
|
public update(partial: Partial<InvoiceRecipientProps>): Result<InvoiceRecipient, Error> {
|
||||||
|
const updatedProps = {
|
||||||
|
...this.props,
|
||||||
|
...partial,
|
||||||
|
} as InvoiceRecipientProps;
|
||||||
|
|
||||||
|
return InvoiceRecipient.create(updatedProps);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public get name(): Name {
|
||||||
|
return this.props.name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get tin(): TINNumber {
|
||||||
|
return this.props.tin;
|
||||||
|
}
|
||||||
|
|
||||||
|
get street(): Maybe<Street> {
|
||||||
|
return this.props.street;
|
||||||
|
}
|
||||||
|
|
||||||
|
get street2(): Maybe<Street> {
|
||||||
|
return this.props.street2;
|
||||||
|
}
|
||||||
|
|
||||||
|
get city(): Maybe<City> {
|
||||||
|
return this.props.city;
|
||||||
|
}
|
||||||
|
|
||||||
|
get postalCode(): Maybe<PostalCode> {
|
||||||
|
return this.props.postalCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
get province(): Maybe<Province> {
|
||||||
|
return this.props.province;
|
||||||
|
}
|
||||||
|
|
||||||
|
get country(): Maybe<Country> {
|
||||||
|
return this.props.country;
|
||||||
|
}
|
||||||
|
|
||||||
|
getProps(): InvoiceRecipientProps {
|
||||||
|
return this.props;
|
||||||
|
}
|
||||||
|
|
||||||
|
toPrimitive() {
|
||||||
|
return this.getProps();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -71,6 +71,10 @@ export class CustomerInvoiceStatus extends ValueObject<ICustomerInvoiceStatusPro
|
|||||||
return new CustomerInvoiceStatus({ value: INVOICE_STATUS.REJECTED });
|
return new CustomerInvoiceStatus({ value: INVOICE_STATUS.REJECTED });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
isDraft(): boolean {
|
||||||
|
return this.props.value === INVOICE_STATUS.DRAFT
|
||||||
|
}
|
||||||
|
|
||||||
getProps(): string {
|
getProps(): string {
|
||||||
return this.props.value;
|
return this.props.value;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,3 +1,4 @@
|
|||||||
|
import { JsonTaxCatalogProvider, spainTaxCatalogProvider } from "@erp/core";
|
||||||
import type { ModuleParams } from "@erp/core/api";
|
import type { ModuleParams } from "@erp/core/api";
|
||||||
import { SequelizeTransactionManager } from "@erp/core/api";
|
import { SequelizeTransactionManager } from "@erp/core/api";
|
||||||
import {
|
import {
|
||||||
@ -9,6 +10,7 @@ import {
|
|||||||
ListCustomerInvoicesAssembler,
|
ListCustomerInvoicesAssembler,
|
||||||
ListCustomerInvoicesUseCase,
|
ListCustomerInvoicesUseCase,
|
||||||
UpdateCustomerInvoiceAssembler,
|
UpdateCustomerInvoiceAssembler,
|
||||||
|
UpdateCustomerInvoiceUseCase,
|
||||||
} from "../application";
|
} from "../application";
|
||||||
import { CustomerInvoiceService } from "../domain";
|
import { CustomerInvoiceService } from "../domain";
|
||||||
import { CustomerInvoiceMapper } from "./mappers";
|
import { CustomerInvoiceMapper } from "./mappers";
|
||||||
@ -19,6 +21,9 @@ type InvoiceDeps = {
|
|||||||
repo: CustomerInvoiceRepository;
|
repo: CustomerInvoiceRepository;
|
||||||
mapper: CustomerInvoiceMapper;
|
mapper: CustomerInvoiceMapper;
|
||||||
service: CustomerInvoiceService;
|
service: CustomerInvoiceService;
|
||||||
|
catalogs: {
|
||||||
|
taxes: JsonTaxCatalogProvider;
|
||||||
|
};
|
||||||
assemblers: {
|
assemblers: {
|
||||||
list: ListCustomerInvoicesAssembler;
|
list: ListCustomerInvoicesAssembler;
|
||||||
get: GetCustomerInvoiceAssembler;
|
get: GetCustomerInvoiceAssembler;
|
||||||
@ -41,6 +46,7 @@ let _repo: CustomerInvoiceRepository | null = null;
|
|||||||
let _mapper: CustomerInvoiceMapper | null = null;
|
let _mapper: CustomerInvoiceMapper | null = null;
|
||||||
let _service: CustomerInvoiceService | null = null;
|
let _service: CustomerInvoiceService | null = null;
|
||||||
let _assemblers: InvoiceDeps["assemblers"] | null = null;
|
let _assemblers: InvoiceDeps["assemblers"] | null = null;
|
||||||
|
let _catalogs: InvoiceDeps["catalogs"] | null = null;
|
||||||
|
|
||||||
export function getInvoiceDependencies(params: ModuleParams): InvoiceDeps {
|
export function getInvoiceDependencies(params: ModuleParams): InvoiceDeps {
|
||||||
const { database } = params;
|
const { database } = params;
|
||||||
@ -49,6 +55,7 @@ export function getInvoiceDependencies(params: ModuleParams): InvoiceDeps {
|
|||||||
if (!_mapper) _mapper = new CustomerInvoiceMapper();
|
if (!_mapper) _mapper = new CustomerInvoiceMapper();
|
||||||
if (!_repo) _repo = new CustomerInvoiceRepository(_mapper);
|
if (!_repo) _repo = new CustomerInvoiceRepository(_mapper);
|
||||||
if (!_service) _service = new CustomerInvoiceService(_repo);
|
if (!_service) _service = new CustomerInvoiceService(_repo);
|
||||||
|
if (!_catalogs) _catalogs = { taxes: spainTaxCatalogProvider };
|
||||||
|
|
||||||
if (!_assemblers) {
|
if (!_assemblers) {
|
||||||
_assemblers = {
|
_assemblers = {
|
||||||
@ -65,12 +72,18 @@ export function getInvoiceDependencies(params: ModuleParams): InvoiceDeps {
|
|||||||
mapper: _mapper,
|
mapper: _mapper,
|
||||||
service: _service,
|
service: _service,
|
||||||
assemblers: _assemblers,
|
assemblers: _assemblers,
|
||||||
|
catalogs: _catalogs,
|
||||||
build: {
|
build: {
|
||||||
list: () =>
|
list: () =>
|
||||||
new ListCustomerInvoicesUseCase(_service!, transactionManager!, _assemblers!.list),
|
new ListCustomerInvoicesUseCase(_service!, transactionManager!, _assemblers!.list),
|
||||||
get: () => new GetCustomerInvoiceUseCase(_service!, transactionManager!, _assemblers!.get),
|
get: () => new GetCustomerInvoiceUseCase(_service!, transactionManager!, _assemblers!.get),
|
||||||
create: () =>
|
create: () =>
|
||||||
new CreateCustomerInvoiceUseCase(_service!, transactionManager!, _assemblers!.create),
|
new CreateCustomerInvoiceUseCase(
|
||||||
|
_service!,
|
||||||
|
transactionManager!,
|
||||||
|
_assemblers!.create,
|
||||||
|
_catalogs!.taxes
|
||||||
|
),
|
||||||
update: () =>
|
update: () =>
|
||||||
new UpdateCustomerInvoiceUseCase(_service!, transactionManager!, _assemblers!.update),
|
new UpdateCustomerInvoiceUseCase(_service!, transactionManager!, _assemblers!.update),
|
||||||
delete: () => new DeleteCustomerInvoiceUseCase(_service!, transactionManager!),
|
delete: () => new DeleteCustomerInvoiceUseCase(_service!, transactionManager!),
|
||||||
|
|||||||
@ -7,9 +7,16 @@ import {
|
|||||||
extractOrPushError,
|
extractOrPushError,
|
||||||
} from "@erp/core/api";
|
} from "@erp/core/api";
|
||||||
import {
|
import {
|
||||||
|
City,
|
||||||
|
Country,
|
||||||
CurrencyCode,
|
CurrencyCode,
|
||||||
LanguageCode,
|
LanguageCode,
|
||||||
|
Name,
|
||||||
Percentage,
|
Percentage,
|
||||||
|
PostalCode,
|
||||||
|
Province,
|
||||||
|
Street,
|
||||||
|
TINNumber,
|
||||||
TextValue,
|
TextValue,
|
||||||
UniqueID,
|
UniqueID,
|
||||||
UtcDate,
|
UtcDate,
|
||||||
@ -117,11 +124,60 @@ export class CustomerInvoiceMapper
|
|||||||
errors
|
errors
|
||||||
);
|
);
|
||||||
|
|
||||||
if (errors.length > 0) {
|
// Customer
|
||||||
return Result.fail(
|
const customerId = extractOrPushError(
|
||||||
new ValidationErrorCollection("Customer invoice props mapping failed", errors)
|
UniqueID.create(source.customer_id),
|
||||||
);
|
"customer_id",
|
||||||
}
|
errors
|
||||||
|
);
|
||||||
|
|
||||||
|
const customerName = extractOrPushError(
|
||||||
|
maybeFromNullableVO(source.customer_name, (value) => Name.create(value)),
|
||||||
|
"customer_name",
|
||||||
|
errors
|
||||||
|
);
|
||||||
|
|
||||||
|
const customerTin = extractOrPushError(
|
||||||
|
maybeFromNullableVO(source.customer_tin, (value) => TINNumber.create(value)),
|
||||||
|
"customer_tin",
|
||||||
|
errors
|
||||||
|
);
|
||||||
|
|
||||||
|
const customerStreet = extractOrPushError(
|
||||||
|
maybeFromNullableVO(source.customer_street, (value) => Street.create(value)),
|
||||||
|
"customer_street",
|
||||||
|
errors
|
||||||
|
);
|
||||||
|
|
||||||
|
const customerStreet2 = extractOrPushError(
|
||||||
|
maybeFromNullableVO(source.customer_street2, (value) => Street.create(value)),
|
||||||
|
"customer_street2",
|
||||||
|
errors
|
||||||
|
);
|
||||||
|
|
||||||
|
const customerCity = extractOrPushError(
|
||||||
|
maybeFromNullableVO(source.customer_city, (value) => City.create(value)),
|
||||||
|
"customer_city",
|
||||||
|
errors
|
||||||
|
);
|
||||||
|
|
||||||
|
const customerProvince = extractOrPushError(
|
||||||
|
maybeFromNullableVO(source.customer_province, (value) => Province.create(value)),
|
||||||
|
"customer_province",
|
||||||
|
errors
|
||||||
|
);
|
||||||
|
|
||||||
|
const customerPostalCode = extractOrPushError(
|
||||||
|
maybeFromNullableVO(source.customer_postal_code, (value) => PostalCode.create(value)),
|
||||||
|
"customer_postal_code",
|
||||||
|
errors
|
||||||
|
);
|
||||||
|
|
||||||
|
const customerCountry = extractOrPushError(
|
||||||
|
maybeFromNullableVO(source.customer_country, (value) => Country.create(value)),
|
||||||
|
"customer_country",
|
||||||
|
errors
|
||||||
|
);
|
||||||
|
|
||||||
// Mapear los items de la factura
|
// Mapear los items de la factura
|
||||||
const items = this._itemsMapper.mapArrayToDomain(source.items, {
|
const items = this._itemsMapper.mapArrayToDomain(source.items, {
|
||||||
@ -130,6 +186,8 @@ export class CustomerInvoiceMapper
|
|||||||
...params,
|
...params,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Mapear los impuestos
|
||||||
|
|
||||||
if (errors.length > 0) {
|
if (errors.length > 0) {
|
||||||
return Result.fail(
|
return Result.fail(
|
||||||
new ValidationErrorCollection("Customer invoice item props mapping failed", errors)
|
new ValidationErrorCollection("Customer invoice item props mapping failed", errors)
|
||||||
@ -144,6 +202,8 @@ export class CustomerInvoiceMapper
|
|||||||
invoiceDate: invoiceDate!,
|
invoiceDate: invoiceDate!,
|
||||||
operationDate: operationDate!,
|
operationDate: operationDate!,
|
||||||
|
|
||||||
|
customerId: customerId!,
|
||||||
|
|
||||||
notes: notes!,
|
notes: notes!,
|
||||||
|
|
||||||
languageCode: languageCode!,
|
languageCode: languageCode!,
|
||||||
@ -167,11 +227,30 @@ export class CustomerInvoiceMapper
|
|||||||
source: CustomerInvoice,
|
source: CustomerInvoice,
|
||||||
params?: MapperParamsType
|
params?: MapperParamsType
|
||||||
): CustomerInvoiceCreationAttributes {
|
): CustomerInvoiceCreationAttributes {
|
||||||
//const subtotal = source.calculateSubtotal();
|
|
||||||
//const total = source.calculateTotal();
|
|
||||||
|
|
||||||
const items = this._itemsMapper.mapCollectionToPersistence(source.items, params);
|
const items = this._itemsMapper.mapCollectionToPersistence(source.items, params);
|
||||||
|
|
||||||
|
const customer = source.recipient.match((recipient) => ({
|
||||||
|
customer_id: recipient.id.toPrimitive(),
|
||||||
|
customer_tin: recipient.tin.toPrimitive(),
|
||||||
|
customer_name: recipient.name.toPrimitive(),
|
||||||
|
customer_street: toNullable(recipient.address.street, (street) => street.toPrimitive()),
|
||||||
|
customer_street2: toNullable(recipient.address.street2, (street2) => street2.toPrimitive()),
|
||||||
|
customer_city: toNullable(recipient.address.city, (city) => city.toPrimitive()),
|
||||||
|
customer_province: toNullable(recipient.address.province, (province) => province.toPrimitive()),
|
||||||
|
customer_postal_code: toNullable(recipient.address.postalCode, (postalCode) => postalCode.toPrimitive()),
|
||||||
|
customer_country: toNullable(recipient.address.country, (country) => country.toPrimitive()),
|
||||||
|
}) as any, () => ({
|
||||||
|
customer_id: source.customerId.toPrimitive(),
|
||||||
|
customer_tin: null,
|
||||||
|
customer_name: null,
|
||||||
|
customer_street: null,
|
||||||
|
customer_street2: null,
|
||||||
|
customer_city: null,
|
||||||
|
customer_province: null,
|
||||||
|
customer_postal_code: null,
|
||||||
|
customer_country: null,
|
||||||
|
})) as any
|
||||||
|
|
||||||
return {
|
return {
|
||||||
id: source.id.toPrimitive(),
|
id: source.id.toPrimitive(),
|
||||||
company_id: source.companyId.toPrimitive(),
|
company_id: source.companyId.toPrimitive(),
|
||||||
@ -194,16 +273,23 @@ export class CustomerInvoiceMapper
|
|||||||
subtotal_amount_value: 0, //subtotal.amount,
|
subtotal_amount_value: 0, //subtotal.amount,
|
||||||
subtotal_amount_scale: 2, //subtotal.scale,
|
subtotal_amount_scale: 2, //subtotal.scale,
|
||||||
|
|
||||||
/*discount_percentage_value: source.discountPercentage.value,
|
discount_percentage_value: source.discountPercentage.value,
|
||||||
discount_percentage_scale: source.discountPercentage.scale,
|
discount_percentage_scale: source.discountPercentage.scale,
|
||||||
|
|
||||||
discount_amount_value: source.discountAmount.value,
|
discount_amount_value: source.discountAmount.value,
|
||||||
discount_amount_scale: source.discountAmount.scale,*/
|
discount_amount_scale: source.discountAmount.scale,
|
||||||
|
|
||||||
|
taxable_amount_value: source.taxableAmount.value,
|
||||||
|
taxable_amount_scale: source.taxableAmount.value,
|
||||||
|
tax_amount_value: source.taxAmount.value,
|
||||||
|
tax_amount_scale: source.taxAmount.value,
|
||||||
|
|
||||||
total_amount_value: 0, //total.amount,
|
total_amount_value: 0, //total.amount,
|
||||||
total_amount_scale: 2, //total.scale,
|
total_amount_scale: 2, //total.scale,
|
||||||
|
|
||||||
items,
|
items,
|
||||||
|
...customer,
|
||||||
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -59,6 +59,17 @@ export class CustomerInvoiceModel extends Model<
|
|||||||
declare total_amount_value: number;
|
declare total_amount_value: number;
|
||||||
declare total_amount_scale: number;
|
declare total_amount_scale: number;
|
||||||
|
|
||||||
|
// Customer
|
||||||
|
declare customer_id: string;
|
||||||
|
declare customer_tin: string;
|
||||||
|
declare customer_name: string;
|
||||||
|
declare customer_street: string;
|
||||||
|
declare customer_street2: string;
|
||||||
|
declare customer_city: string;
|
||||||
|
declare customer_province: string;
|
||||||
|
declare customer_postal_code: string;
|
||||||
|
declare customer_country: string;
|
||||||
|
|
||||||
// Relaciones
|
// Relaciones
|
||||||
declare items: NonAttribute<CustomerInvoiceItemModel[]>;
|
declare items: NonAttribute<CustomerInvoiceItemModel[]>;
|
||||||
//declare customer: NonAttribute<CustomerInvoiceParticipant_Model[]>;
|
//declare customer: NonAttribute<CustomerInvoiceParticipant_Model[]>;
|
||||||
@ -216,6 +227,51 @@ export default (database: Sequelize) => {
|
|||||||
allowNull: false,
|
allowNull: false,
|
||||||
defaultValue: 2,
|
defaultValue: 2,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
customer_id: {
|
||||||
|
type: DataTypes.UUID,
|
||||||
|
allowNull: false,
|
||||||
|
},
|
||||||
|
customer_tin: {
|
||||||
|
type: DataTypes.STRING,
|
||||||
|
allowNull: true,
|
||||||
|
defaultValue: null,
|
||||||
|
},
|
||||||
|
customer_name: {
|
||||||
|
type: DataTypes.STRING,
|
||||||
|
allowNull: true,
|
||||||
|
defaultValue: null,
|
||||||
|
},
|
||||||
|
customer_street: {
|
||||||
|
type: DataTypes.STRING,
|
||||||
|
allowNull: true,
|
||||||
|
defaultValue: null,
|
||||||
|
},
|
||||||
|
customer_street2: {
|
||||||
|
type: DataTypes.STRING,
|
||||||
|
allowNull: true,
|
||||||
|
defaultValue: null,
|
||||||
|
},
|
||||||
|
customer_city: {
|
||||||
|
type: DataTypes.STRING,
|
||||||
|
allowNull: true,
|
||||||
|
defaultValue: null,
|
||||||
|
},
|
||||||
|
customer_province: {
|
||||||
|
type: DataTypes.STRING,
|
||||||
|
allowNull: true,
|
||||||
|
defaultValue: null,
|
||||||
|
},
|
||||||
|
customer_postal_code: {
|
||||||
|
type: DataTypes.STRING,
|
||||||
|
allowNull: true,
|
||||||
|
defaultValue: null,
|
||||||
|
},
|
||||||
|
customer_country: {
|
||||||
|
type: DataTypes.STRING,
|
||||||
|
allowNull: true,
|
||||||
|
defaultValue: null,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
sequelize: database,
|
sequelize: database,
|
||||||
|
|||||||
@ -16,12 +16,13 @@ export const CreateCustomerInvoiceRequestSchema = z.object({
|
|||||||
company_id: z.uuid(),
|
company_id: z.uuid(),
|
||||||
|
|
||||||
invoice_number: z.string(),
|
invoice_number: z.string(),
|
||||||
status: z.string().default("draft"),
|
|
||||||
series: z.string().default(""),
|
series: z.string().default(""),
|
||||||
|
|
||||||
invoice_date: z.string(),
|
invoice_date: z.string(),
|
||||||
operation_date: z.string().default(""),
|
operation_date: z.string().default(""),
|
||||||
|
|
||||||
|
customer_id: z.uuid(),
|
||||||
|
|
||||||
notes: z.string().default(""),
|
notes: z.string().default(""),
|
||||||
|
|
||||||
language_code: z.string().toLowerCase().default("es"),
|
language_code: z.string().toLowerCase().default("es"),
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user