Facturas de cliente
This commit is contained in:
parent
096abdccb2
commit
ac11eaffdf
@ -0,0 +1,12 @@
|
|||||||
|
import { MoneyDTO } from "@erp/core";
|
||||||
|
import { MoneyValue } from "@repo/rdx-ddd";
|
||||||
|
|
||||||
|
export function formatMoneyDTO(amount: MoneyDTO, locale: string) {
|
||||||
|
const money = MoneyValue.create({
|
||||||
|
value: Number(amount.value),
|
||||||
|
currency_code: amount.currency_code,
|
||||||
|
scale: Number(amount.scale),
|
||||||
|
}).data;
|
||||||
|
|
||||||
|
return money.format(locale);
|
||||||
|
}
|
||||||
@ -1 +1,2 @@
|
|||||||
|
export * from "./format-money-dto";
|
||||||
export * from "./map-dto-to-customer-invoice-props";
|
export * from "./map-dto-to-customer-invoice-props";
|
||||||
|
|||||||
@ -1,16 +1,21 @@
|
|||||||
import { ValidationErrorCollection, ValidationErrorDetail } from "@repo/rdx-ddd";
|
import {
|
||||||
|
ValidationErrorCollection,
|
||||||
|
ValidationErrorDetail,
|
||||||
|
extractOrPushError,
|
||||||
|
} from "@repo/rdx-ddd";
|
||||||
import { Result } from "@repo/rdx-utils";
|
import { Result } from "@repo/rdx-utils";
|
||||||
|
import { CreateCustomerInvoiceRequestDTO } from "../../../common";
|
||||||
import {
|
import {
|
||||||
CustomerInvoiceItem,
|
CustomerInvoiceItem,
|
||||||
CustomerInvoiceItemDescription,
|
CustomerInvoiceItemDescription,
|
||||||
ItemAmount,
|
ItemAmount,
|
||||||
ItemDiscount,
|
ItemDiscount,
|
||||||
|
ItemQuantity,
|
||||||
} from "../../domain";
|
} from "../../domain";
|
||||||
import { extractOrPushError } from "./extract-or-push-error";
|
|
||||||
import { hasNoUndefinedFields } from "./has-no-undefined-fields";
|
import { hasNoUndefinedFields } from "./has-no-undefined-fields";
|
||||||
|
|
||||||
export function mapDTOToCustomerInvoiceItemsProps(
|
export function mapDTOToCustomerInvoiceItemsProps(
|
||||||
dtoItems: Pick<CreateCustomerInvoiceCommandDTO, "items">["items"]
|
dtoItems: Pick<CreateCustomerInvoiceRequestDTO, "items">["items"]
|
||||||
): Result<CustomerInvoiceItem[], ValidationErrorCollection> {
|
): Result<CustomerInvoiceItem[], ValidationErrorCollection> {
|
||||||
const errors: ValidationErrorDetail[] = [];
|
const errors: ValidationErrorDetail[] = [];
|
||||||
const items: CustomerInvoiceItem[] = [];
|
const items: CustomerInvoiceItem[] = [];
|
||||||
@ -25,9 +30,8 @@ export function mapDTOToCustomerInvoiceItemsProps(
|
|||||||
);
|
);
|
||||||
|
|
||||||
const quantity = extractOrPushError(
|
const quantity = extractOrPushError(
|
||||||
CustomerInvoiceItemQuantity.create({
|
ItemQuantity.create({
|
||||||
amount: item.quantity.amount,
|
value: Number(item.quantity),
|
||||||
scale: item.quantity.scale,
|
|
||||||
}),
|
}),
|
||||||
path("quantity"),
|
path("quantity"),
|
||||||
errors
|
errors
|
||||||
|
|||||||
@ -1,14 +1,20 @@
|
|||||||
import { ValidationErrorCollection, ValidationErrorDetail } from "@erp/core/api";
|
import {
|
||||||
import { UniqueID, UtcDate } from "@repo/rdx-ddd";
|
CurrencyCode,
|
||||||
|
UniqueID,
|
||||||
|
UtcDate,
|
||||||
|
ValidationErrorCollection,
|
||||||
|
ValidationErrorDetail,
|
||||||
|
extractOrPushError,
|
||||||
|
maybeFromNullableVO,
|
||||||
|
} from "@repo/rdx-ddd";
|
||||||
import { Result } from "@repo/rdx-utils";
|
import { Result } from "@repo/rdx-utils";
|
||||||
import { CreateCustomerInvoiceCommandDTO } from "../../../common/dto";
|
import { CreateCustomerInvoiceRequestDTO } from "../../../common";
|
||||||
import {
|
import {
|
||||||
CustomerInvoiceNumber,
|
CustomerInvoiceNumber,
|
||||||
CustomerInvoiceProps,
|
CustomerInvoiceProps,
|
||||||
CustomerInvoiceSerie,
|
CustomerInvoiceSerie,
|
||||||
CustomerInvoiceStatus,
|
CustomerInvoiceStatus,
|
||||||
} from "../../domain";
|
} from "../../domain";
|
||||||
import { extractOrPushError } from "./extract-or-push-error";
|
|
||||||
import { mapDTOToCustomerInvoiceItemsProps } from "./map-dto-to-customer-invoice-items-props";
|
import { mapDTOToCustomerInvoiceItemsProps } from "./map-dto-to-customer-invoice-items-props";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -21,7 +27,7 @@ import { mapDTOToCustomerInvoiceItemsProps } from "./map-dto-to-customer-invoice
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export function mapDTOToCustomerInvoiceProps(dto: CreateCustomerInvoiceCommandDTO) {
|
export function mapDTOToCustomerInvoiceProps(dto: CreateCustomerInvoiceRequestDTO) {
|
||||||
const errors: ValidationErrorDetail[] = [];
|
const errors: ValidationErrorDetail[] = [];
|
||||||
|
|
||||||
const invoiceId = extractOrPushError(UniqueID.create(dto.id), "id", errors);
|
const invoiceId = extractOrPushError(UniqueID.create(dto.id), "id", errors);
|
||||||
@ -32,7 +38,7 @@ export function mapDTOToCustomerInvoiceProps(dto: CreateCustomerInvoiceCommandDT
|
|||||||
errors
|
errors
|
||||||
);
|
);
|
||||||
const invoiceSeries = extractOrPushError(
|
const invoiceSeries = extractOrPushError(
|
||||||
CustomerInvoiceSerie.create(dto.invoice_series),
|
maybeFromNullableVO(dto.invoice_series, (value) => CustomerInvoiceSerie.create(value)),
|
||||||
"invoice_series",
|
"invoice_series",
|
||||||
errors
|
errors
|
||||||
);
|
);
|
||||||
@ -42,13 +48,16 @@ export function mapDTOToCustomerInvoiceProps(dto: CreateCustomerInvoiceCommandDT
|
|||||||
errors
|
errors
|
||||||
);
|
);
|
||||||
const operationDate = extractOrPushError(
|
const operationDate = extractOrPushError(
|
||||||
UtcDate.createFromISO(dto.operation_date),
|
maybeFromNullableVO(dto.operation_date, (value) => UtcDate.createFromISO(value)),
|
||||||
"operation_date",
|
"operation_date",
|
||||||
errors
|
errors
|
||||||
);
|
);
|
||||||
|
|
||||||
//const currency = extractOrPushError(Currency.(dto.currency), "currency", errors);
|
const currencyCode = extractOrPushError(
|
||||||
const currency = dto.currency;
|
CurrencyCode.create(dto.currency_code),
|
||||||
|
"currency",
|
||||||
|
errors
|
||||||
|
);
|
||||||
|
|
||||||
// 🔄 Validar y construir los items de factura con helper especializado
|
// 🔄 Validar y construir los items de factura con helper especializado
|
||||||
const itemsResult = mapDTOToCustomerInvoiceItemsProps(dto.items);
|
const itemsResult = mapDTOToCustomerInvoiceItemsProps(dto.items);
|
||||||
@ -57,16 +66,16 @@ export function mapDTOToCustomerInvoiceProps(dto: CreateCustomerInvoiceCommandDT
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (errors.length > 0) {
|
if (errors.length > 0) {
|
||||||
return Result.fail(new ValidationErrorCollection(errors));
|
return Result.fail(new ValidationErrorCollection("Customer dto mapping failed", errors));
|
||||||
}
|
}
|
||||||
|
|
||||||
const invoiceProps: CustomerInvoiceProps = {
|
const invoiceProps: CustomerInvoiceProps = {
|
||||||
invoiceNumber: invoiceNumber!,
|
invoiceNumber: invoiceNumber!,
|
||||||
invoiceSeries: invoiceSeries!,
|
series: invoiceSeries!,
|
||||||
invoiceDate: invoiceDate!,
|
invoiceDate: invoiceDate!,
|
||||||
operationDate: operationDate!,
|
operationDate: operationDate!,
|
||||||
status: CustomerInvoiceStatus.createDraft(),
|
status: CustomerInvoiceStatus.createDraft(),
|
||||||
currency,
|
currencyCode: currencyCode!,
|
||||||
};
|
};
|
||||||
|
|
||||||
return Result.ok({ id: invoiceId!, props: invoiceProps });
|
return Result.ok({ id: invoiceId!, props: invoiceProps });
|
||||||
|
|||||||
@ -0,0 +1,17 @@
|
|||||||
|
import { Presenter } from "@erp/core/api";
|
||||||
|
import { GetCustomerInvoiceByIdResponseDTO } from "../../../../common/dto";
|
||||||
|
import { formatMoneyDTO } from "../../helpers";
|
||||||
|
|
||||||
|
export class CustomerInvoiceReportPresenter extends Presenter<
|
||||||
|
GetCustomerInvoiceByIdResponseDTO,
|
||||||
|
unknown
|
||||||
|
> {
|
||||||
|
toOutput(invoiceDTO: GetCustomerInvoiceByIdResponseDTO) {
|
||||||
|
const locale = invoiceDTO.language_code;
|
||||||
|
|
||||||
|
return {
|
||||||
|
...invoiceDTO,
|
||||||
|
total_amount: formatMoneyDTO(invoiceDTO.total_amount, locale),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1 +1,2 @@
|
|||||||
|
export * from "./customer-invoice.report.presenter";
|
||||||
export * from "./list-customer-invoices.presenter";
|
export * from "./list-customer-invoices.presenter";
|
||||||
|
|||||||
@ -11,13 +11,20 @@ export class CustomerInvoiceReportHTMLPresenter extends Presenter {
|
|||||||
projection: "FULL",
|
projection: "FULL",
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const prePresenter = this.presenterRegistry.getPresenter({
|
||||||
|
resource: "customer-invoice",
|
||||||
|
projection: "REPORT",
|
||||||
|
format: "JSON",
|
||||||
|
});
|
||||||
|
|
||||||
const invoiceDTO = dtoPresenter.toOutput(customerInvoice);
|
const invoiceDTO = dtoPresenter.toOutput(customerInvoice);
|
||||||
|
const prettyDTO = prePresenter.toOutput(invoiceDTO);
|
||||||
|
|
||||||
// Obtener y compilar la plantilla HTML
|
// Obtener y compilar la plantilla HTML
|
||||||
const templateHtml = readFileSync(
|
const templateHtml = readFileSync(
|
||||||
path.join(__dirname, "./templates/customer-invoice/template.hbs")
|
path.join(__dirname, "./templates/customer-invoice/template.hbs")
|
||||||
).toString();
|
).toString();
|
||||||
const template = handlebars.compile(templateHtml, {});
|
const template = handlebars.compile(templateHtml, {});
|
||||||
return template(invoiceDTO);
|
return template(prettyDTO);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -139,7 +139,7 @@
|
|||||||
<!-- Badge TOTAL superpuesto -->
|
<!-- Badge TOTAL superpuesto -->
|
||||||
<div class="absolute -top-7 right-0">
|
<div class="absolute -top-7 right-0">
|
||||||
<div class="relative bg-[#f08119] text-white text-sm font-semibold px-3 py-1 shadow">
|
<div class="relative bg-[#f08119] text-white text-sm font-semibold px-3 py-1 shadow">
|
||||||
TOTAL: {{total_amount.value}} €
|
TOTAL: {{total_amount}} €
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -14,6 +14,7 @@ import {
|
|||||||
CustomerInvoiceItemsFullPresenter,
|
CustomerInvoiceItemsFullPresenter,
|
||||||
CustomerInvoiceReportHTMLPresenter,
|
CustomerInvoiceReportHTMLPresenter,
|
||||||
CustomerInvoiceReportPDFPresenter,
|
CustomerInvoiceReportPDFPresenter,
|
||||||
|
CustomerInvoiceReportPresenter,
|
||||||
GetCustomerInvoiceUseCase,
|
GetCustomerInvoiceUseCase,
|
||||||
ListCustomerInvoicesPresenter,
|
ListCustomerInvoicesPresenter,
|
||||||
ListCustomerInvoicesUseCase,
|
ListCustomerInvoicesUseCase,
|
||||||
@ -99,6 +100,14 @@ export function buildCustomerInvoiceDependencies(params: ModuleParams): Customer
|
|||||||
},
|
},
|
||||||
presenter: new ListCustomerInvoicesPresenter(presenterRegistry),
|
presenter: new ListCustomerInvoicesPresenter(presenterRegistry),
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
key: {
|
||||||
|
resource: "customer-invoice",
|
||||||
|
projection: "REPORT",
|
||||||
|
format: "JSON",
|
||||||
|
},
|
||||||
|
presenter: new CustomerInvoiceReportPresenter(presenterRegistry),
|
||||||
|
},
|
||||||
{
|
{
|
||||||
key: {
|
key: {
|
||||||
resource: "customer-invoice",
|
resource: "customer-invoice",
|
||||||
|
|||||||
@ -119,7 +119,7 @@ export class CustomerInvoiceDomainMapper
|
|||||||
|
|
||||||
const discountPercentage = extractOrPushError(
|
const discountPercentage = extractOrPushError(
|
||||||
Percentage.create({
|
Percentage.create({
|
||||||
value: source.discount_amount_scale,
|
value: source.discount_percentage_value,
|
||||||
scale: source.discount_percentage_scale,
|
scale: source.discount_percentage_scale,
|
||||||
}),
|
}),
|
||||||
"discount_percentage_value",
|
"discount_percentage_value",
|
||||||
@ -206,9 +206,7 @@ export class CustomerInvoiceDomainMapper
|
|||||||
|
|
||||||
// 5) Si hubo errores de mapeo, devolvemos colección de validación
|
// 5) Si hubo errores de mapeo, devolvemos colección de validación
|
||||||
if (errors.length > 0) {
|
if (errors.length > 0) {
|
||||||
return Result.fail(
|
return Result.fail(new ValidationErrorCollection("Customer mapping failed", errors));
|
||||||
new ValidationErrorCollection("Customer invoice mapping failed", errors)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 6) Construcción del agregado (Dominio)
|
// 6) Construcción del agregado (Dominio)
|
||||||
|
|||||||
@ -207,7 +207,7 @@ export class MoneyValue extends ValueObject<MoneyValueProps> implements IMoneyVa
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Devuelve una cadena con el importe formateado.
|
* Devuelve una cadena con el importe formateado.
|
||||||
* Ejemplo: 123456 -> €1,234.56
|
* Ejemplo: 123456 -> 1.234,56 €
|
||||||
* @param locale Código de idioma y país (ej. "es-ES")
|
* @param locale Código de idioma y país (ej. "es-ES")
|
||||||
* @returns Importe formateado
|
* @returns Importe formateado
|
||||||
*/
|
*/
|
||||||
@ -222,6 +222,6 @@ export class MoneyValue extends ValueObject<MoneyValueProps> implements IMoneyVa
|
|||||||
minimumFractionDigits: scale,
|
minimumFractionDigits: scale,
|
||||||
maximumFractionDigits: scale,
|
maximumFractionDigits: scale,
|
||||||
useGrouping: true,
|
useGrouping: true,
|
||||||
}).format(value);
|
}).format(this.formattedValue);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user