.
This commit is contained in:
parent
302f3293c6
commit
acd61cf6eb
@ -5,6 +5,7 @@ import {
|
|||||||
IssuedInvoiceFullSnapshotBuilder,
|
IssuedInvoiceFullSnapshotBuilder,
|
||||||
IssuedInvoiceItemsFullSnapshotBuilder,
|
IssuedInvoiceItemsFullSnapshotBuilder,
|
||||||
IssuedInvoiceRecipientFullSnapshotBuilder,
|
IssuedInvoiceRecipientFullSnapshotBuilder,
|
||||||
|
IssuedInvoiceTaxesFullSnapshotBuilder,
|
||||||
IssuedInvoiceVerifactuFullSnapshotBuilder,
|
IssuedInvoiceVerifactuFullSnapshotBuilder,
|
||||||
} from "../snapshot-builders/full";
|
} from "../snapshot-builders/full";
|
||||||
import {
|
import {
|
||||||
@ -16,6 +17,8 @@ import {
|
|||||||
export function buildIssuedInvoiceSnapshotBuilders() {
|
export function buildIssuedInvoiceSnapshotBuilders() {
|
||||||
const itemsBuilder = new IssuedInvoiceItemsFullSnapshotBuilder();
|
const itemsBuilder = new IssuedInvoiceItemsFullSnapshotBuilder();
|
||||||
|
|
||||||
|
const taxesBuilder = new IssuedInvoiceTaxesFullSnapshotBuilder();
|
||||||
|
|
||||||
const recipientBuilder = new IssuedInvoiceRecipientFullSnapshotBuilder();
|
const recipientBuilder = new IssuedInvoiceRecipientFullSnapshotBuilder();
|
||||||
|
|
||||||
const verifactuBuilder = new IssuedInvoiceVerifactuFullSnapshotBuilder();
|
const verifactuBuilder = new IssuedInvoiceVerifactuFullSnapshotBuilder();
|
||||||
@ -23,7 +26,8 @@ export function buildIssuedInvoiceSnapshotBuilders() {
|
|||||||
const fullSnapshotBuilder = new IssuedInvoiceFullSnapshotBuilder(
|
const fullSnapshotBuilder = new IssuedInvoiceFullSnapshotBuilder(
|
||||||
itemsBuilder,
|
itemsBuilder,
|
||||||
recipientBuilder,
|
recipientBuilder,
|
||||||
verifactuBuilder
|
verifactuBuilder,
|
||||||
|
taxesBuilder
|
||||||
);
|
);
|
||||||
|
|
||||||
const listSnapshotBuilder = new IssuedInvoiceListItemSnapshotBuilder();
|
const listSnapshotBuilder = new IssuedInvoiceListItemSnapshotBuilder();
|
||||||
|
|||||||
@ -2,7 +2,9 @@ export * from "./issued-invoice-full-snapshot.interface";
|
|||||||
export * from "./issued-invoice-full-snapshot-builder";
|
export * from "./issued-invoice-full-snapshot-builder";
|
||||||
export * from "./issued-invoice-item-full-snapshot.interface";
|
export * from "./issued-invoice-item-full-snapshot.interface";
|
||||||
export * from "./issued-invoice-items-full-snapshot-builder";
|
export * from "./issued-invoice-items-full-snapshot-builder";
|
||||||
export * from "./issued-invoice-recipient-full-snapshot.interfce";
|
export * from "./issued-invoice-recipient-full-snapshot.interface";
|
||||||
export * from "./issued-invoice-recipient-full-snapshot-builder";
|
export * from "./issued-invoice-recipient-full-snapshot-builder";
|
||||||
|
export * from "./issued-invoice-tax-full-snapshot-interface";
|
||||||
|
export * from "./issued-invoice-taxes-full-snapshot-builder";
|
||||||
export * from "./issued-invoice-verifactu-full-snapshot.interface";
|
export * from "./issued-invoice-verifactu-full-snapshot.interface";
|
||||||
export * from "./issued-invoice-verifactu-full-snapshot-builder";
|
export * from "./issued-invoice-verifactu-full-snapshot-builder";
|
||||||
|
|||||||
@ -1,11 +1,12 @@
|
|||||||
import type { ISnapshotBuilder } from "@erp/core/api";
|
import type { ISnapshotBuilder } from "@erp/core/api";
|
||||||
import { maybeToEmptyString } from "@repo/rdx-ddd";
|
import { maybeToEmptyString } from "@repo/rdx-ddd";
|
||||||
|
|
||||||
import { InvoiceAmount, type IssuedInvoice } from "../../../../domain";
|
import type { IssuedInvoice } from "../../../../domain";
|
||||||
|
|
||||||
import type { IIssuedInvoiceFullSnapshot } from "./issued-invoice-full-snapshot.interface";
|
import type { IIssuedInvoiceFullSnapshot } from "./issued-invoice-full-snapshot.interface";
|
||||||
import type { IIssuedInvoiceItemsFullSnapshotBuilder } from "./issued-invoice-items-full-snapshot-builder";
|
import type { IIssuedInvoiceItemsFullSnapshotBuilder } from "./issued-invoice-items-full-snapshot-builder";
|
||||||
import type { IIssuedInvoiceRecipientFullSnapshotBuilder } from "./issued-invoice-recipient-full-snapshot-builder";
|
import type { IIssuedInvoiceRecipientFullSnapshotBuilder } from "./issued-invoice-recipient-full-snapshot-builder";
|
||||||
|
import type { IIssuedInvoiceTaxesFullSnapshotBuilder } from "./issued-invoice-taxes-full-snapshot-builder";
|
||||||
import type { IIssuedInvoiceVerifactuFullSnapshotBuilder } from "./issued-invoice-verifactu-full-snapshot-builder";
|
import type { IIssuedInvoiceVerifactuFullSnapshotBuilder } from "./issued-invoice-verifactu-full-snapshot-builder";
|
||||||
|
|
||||||
export interface IIssuedInvoiceFullSnapshotBuilder
|
export interface IIssuedInvoiceFullSnapshotBuilder
|
||||||
@ -15,13 +16,15 @@ export class IssuedInvoiceFullSnapshotBuilder implements IIssuedInvoiceFullSnaps
|
|||||||
constructor(
|
constructor(
|
||||||
private readonly itemsBuilder: IIssuedInvoiceItemsFullSnapshotBuilder,
|
private readonly itemsBuilder: IIssuedInvoiceItemsFullSnapshotBuilder,
|
||||||
private readonly recipientBuilder: IIssuedInvoiceRecipientFullSnapshotBuilder,
|
private readonly recipientBuilder: IIssuedInvoiceRecipientFullSnapshotBuilder,
|
||||||
private readonly verifactuBuilder: IIssuedInvoiceVerifactuFullSnapshotBuilder
|
private readonly verifactuBuilder: IIssuedInvoiceVerifactuFullSnapshotBuilder,
|
||||||
|
private readonly taxesBuilder: IIssuedInvoiceTaxesFullSnapshotBuilder
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
toOutput(invoice: IssuedInvoice): IIssuedInvoiceFullSnapshot {
|
toOutput(invoice: IssuedInvoice): IIssuedInvoiceFullSnapshot {
|
||||||
const items = this.itemsBuilder.toOutput(invoice.items);
|
const items = this.itemsBuilder.toOutput(invoice.items);
|
||||||
const recipient = this.recipientBuilder.toOutput(invoice);
|
const recipient = this.recipientBuilder.toOutput(invoice);
|
||||||
const verifactu = this.verifactuBuilder.toOutput(invoice);
|
const verifactu = this.verifactuBuilder.toOutput(invoice);
|
||||||
|
const taxes = this.taxesBuilder.toOutput(invoice.taxes);
|
||||||
|
|
||||||
const payment = invoice.paymentMethod.match(
|
const payment = invoice.paymentMethod.match(
|
||||||
(payment) => {
|
(payment) => {
|
||||||
@ -34,57 +37,11 @@ export class IssuedInvoiceFullSnapshotBuilder implements IIssuedInvoiceFullSnaps
|
|||||||
() => undefined
|
() => undefined
|
||||||
);
|
);
|
||||||
|
|
||||||
let totalIvaAmount = InvoiceAmount.zero(invoice.currencyCode.code);
|
|
||||||
let totalRecAmount = InvoiceAmount.zero(invoice.currencyCode.code);
|
|
||||||
let totalRetentionAmount = InvoiceAmount.zero(invoice.currencyCode.code);
|
|
||||||
|
|
||||||
const invoiceTaxes = invoice.taxes().map((taxGroup) => {
|
|
||||||
const { ivaAmount, recAmount, retentionAmount, totalAmount } = taxGroup.calculateAmounts();
|
|
||||||
|
|
||||||
totalIvaAmount = totalIvaAmount.add(ivaAmount);
|
|
||||||
totalRecAmount = totalRecAmount.add(recAmount);
|
|
||||||
totalRetentionAmount = totalRetentionAmount.add(retentionAmount);
|
|
||||||
|
|
||||||
return {
|
|
||||||
taxable_amount: taxGroup.taxableAmount.toObjectString(),
|
|
||||||
|
|
||||||
iva_code: taxGroup.iva.code,
|
|
||||||
iva_percentage: taxGroup.iva.percentage.toObjectString(),
|
|
||||||
iva_amount: ivaAmount.toObjectString(),
|
|
||||||
|
|
||||||
rec_code: taxGroup.rec.match(
|
|
||||||
(rec) => rec.code,
|
|
||||||
() => ""
|
|
||||||
),
|
|
||||||
|
|
||||||
rec_percentage: taxGroup.rec.match(
|
|
||||||
(rec) => rec.percentage.toObjectString(),
|
|
||||||
() => ({ value: "", scale: "" })
|
|
||||||
),
|
|
||||||
|
|
||||||
rec_amount: recAmount.toObjectString(),
|
|
||||||
|
|
||||||
retention_code: taxGroup.retention.match(
|
|
||||||
(retention) => retention.code,
|
|
||||||
() => ""
|
|
||||||
),
|
|
||||||
|
|
||||||
retention_percentage: taxGroup.retention.match(
|
|
||||||
(retention) => retention.percentage.toObjectString(),
|
|
||||||
() => ({ value: "", scale: "" })
|
|
||||||
),
|
|
||||||
|
|
||||||
retention_amount: retentionAmount.toObjectString(),
|
|
||||||
|
|
||||||
taxes_amount: totalAmount.toObjectString(),
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
id: invoice.id.toString(),
|
id: invoice.id.toString(),
|
||||||
company_id: invoice.companyId.toString(),
|
company_id: invoice.companyId.toString(),
|
||||||
|
|
||||||
is_proforma: invoice.isProforma ? "true" : "false",
|
is_proforma: "false",
|
||||||
invoice_number: invoice.invoiceNumber.toString(),
|
invoice_number: invoice.invoiceNumber.toString(),
|
||||||
status: invoice.status.toPrimitive(),
|
status: invoice.status.toPrimitive(),
|
||||||
series: maybeToEmptyString(invoice.series, (value) => value.toString()),
|
series: maybeToEmptyString(invoice.series, (value) => value.toString()),
|
||||||
@ -104,25 +61,26 @@ export class IssuedInvoiceFullSnapshotBuilder implements IIssuedInvoiceFullSnaps
|
|||||||
|
|
||||||
payment_method: payment,
|
payment_method: payment,
|
||||||
|
|
||||||
subtotal_amount: allAmounts.subtotalAmount.toObjectString(),
|
subtotal_amount: invoice.subtotalAmount.toObjectString(),
|
||||||
items_discount_amount: allAmounts.itemDiscountAmount.toObjectString(),
|
items_discount_amount: invoice.itemsDiscountAmount.toObjectString(),
|
||||||
|
|
||||||
discount_percentage: invoice.globalDiscountPercentage.toObjectString(),
|
global_discount_percentage: invoice.globalDiscountPercentage.toObjectString(),
|
||||||
discount_amount: allAmounts.globalDiscountAmount.toObjectString(),
|
global_discount_amount: invoice.globalDiscountAmount.toObjectString(),
|
||||||
|
|
||||||
taxable_amount: allAmounts.taxableAmount.toObjectString(),
|
total_discount_amount: invoice.totalDiscountAmount.toObjectString(),
|
||||||
|
|
||||||
iva_amount: totalIvaAmount.toObjectString(),
|
taxable_amount: invoice.taxableAmount.toObjectString(),
|
||||||
rec_amount: totalRecAmount.toObjectString(),
|
|
||||||
retention_amount: totalRetentionAmount.toObjectString(),
|
|
||||||
|
|
||||||
taxes_amount: allAmounts.taxesAmount.toObjectString(),
|
iva_amount: invoice.ivaAmount.toObjectString(),
|
||||||
total_amount: allAmounts.totalAmount.toObjectString(),
|
rec_amount: invoice.recAmount.toObjectString(),
|
||||||
|
retention_amount: invoice.retentionAmount.toObjectString(),
|
||||||
|
|
||||||
taxes: invoiceTaxes,
|
taxes_amount: invoice.taxesAmount.toObjectString(),
|
||||||
|
total_amount: invoice.totalAmount.toObjectString(),
|
||||||
|
|
||||||
|
taxes,
|
||||||
|
|
||||||
verifactu,
|
verifactu,
|
||||||
|
|
||||||
items,
|
items,
|
||||||
|
|
||||||
metadata: {
|
metadata: {
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
import type { IIssuedInvoiceItemFullSnapshot } from "./issued-invoice-item-full-snapshot.interface";
|
import type { IIssuedInvoiceItemFullSnapshot } from "./issued-invoice-item-full-snapshot.interface";
|
||||||
import type { IIssuedInvoiceRecipientFullSnapshot } from "./issued-invoice-recipient-full-snapshot.interfce";
|
import type { IIssuedInvoiceRecipientFullSnapshot } from "./issued-invoice-recipient-full-snapshot.interface";
|
||||||
|
import type { IIssuedInvoiceTaxFullSnapshot } from "./issued-invoice-tax-full-snapshot-interface";
|
||||||
import type { IIssuedInvoiceVerifactuFullSnapshot } from "./issued-invoice-verifactu-full-snapshot.interface";
|
import type { IIssuedInvoiceVerifactuFullSnapshot } from "./issued-invoice-verifactu-full-snapshot.interface";
|
||||||
|
|
||||||
export interface IIssuedInvoiceFullSnapshot {
|
export interface IIssuedInvoiceFullSnapshot {
|
||||||
@ -30,10 +31,11 @@ export interface IIssuedInvoiceFullSnapshot {
|
|||||||
};
|
};
|
||||||
|
|
||||||
subtotal_amount: { value: string; scale: string; currency_code: string };
|
subtotal_amount: { value: string; scale: string; currency_code: string };
|
||||||
items_discount_amount: { value: string; scale: string; currency_code: string };
|
|
||||||
|
|
||||||
discount_percentage: { value: string; scale: string };
|
items_discount_amount: { value: string; scale: string; currency_code: string };
|
||||||
discount_amount: { value: string; scale: string; currency_code: string };
|
global_discount_percentage: { value: string; scale: string };
|
||||||
|
global_discount_amount: { value: string; scale: string; currency_code: string };
|
||||||
|
total_discount_amount: { value: string; scale: string; currency_code: string };
|
||||||
|
|
||||||
taxable_amount: { value: string; scale: string; currency_code: string };
|
taxable_amount: { value: string; scale: string; currency_code: string };
|
||||||
|
|
||||||
@ -44,23 +46,7 @@ export interface IIssuedInvoiceFullSnapshot {
|
|||||||
taxes_amount: { value: string; scale: string; currency_code: string };
|
taxes_amount: { value: string; scale: string; currency_code: string };
|
||||||
total_amount: { value: string; scale: string; currency_code: string };
|
total_amount: { value: string; scale: string; currency_code: string };
|
||||||
|
|
||||||
taxes: Array<{
|
taxes: IIssuedInvoiceTaxFullSnapshot[];
|
||||||
taxable_amount: { value: string; scale: string; currency_code: string };
|
|
||||||
|
|
||||||
iva_code: string;
|
|
||||||
iva_percentage: { value: string; scale: string };
|
|
||||||
iva_amount: { value: string; scale: string; currency_code: string };
|
|
||||||
|
|
||||||
rec_code: string;
|
|
||||||
rec_percentage: { value: string; scale: string };
|
|
||||||
rec_amount: { value: string; scale: string; currency_code: string };
|
|
||||||
|
|
||||||
retention_code: string;
|
|
||||||
retention_percentage: { value: string; scale: string };
|
|
||||||
retention_amount: { value: string; scale: string; currency_code: string };
|
|
||||||
|
|
||||||
taxes_amount: { value: string; scale: string; currency_code: string };
|
|
||||||
}>;
|
|
||||||
|
|
||||||
verifactu: IIssuedInvoiceVerifactuFullSnapshot;
|
verifactu: IIssuedInvoiceVerifactuFullSnapshot;
|
||||||
items: IIssuedInvoiceItemFullSnapshot[];
|
items: IIssuedInvoiceItemFullSnapshot[];
|
||||||
|
|||||||
@ -1,5 +1,10 @@
|
|||||||
import type { ISnapshotBuilder } from "@erp/core/api";
|
import type { ISnapshotBuilder } from "@erp/core/api";
|
||||||
import { maybeToEmptyString } from "@repo/rdx-ddd";
|
import {
|
||||||
|
maybeToEmptyMoneyObjectString,
|
||||||
|
maybeToEmptyPercentageObjectString,
|
||||||
|
maybeToEmptyQuantityObjectString,
|
||||||
|
maybeToEmptyString,
|
||||||
|
} from "@repo/rdx-ddd";
|
||||||
|
|
||||||
import type { IssuedInvoiceItem, IssuedInvoiceItems } from "../../../../domain";
|
import type { IssuedInvoiceItem, IssuedInvoiceItems } from "../../../../domain";
|
||||||
|
|
||||||
@ -16,75 +21,38 @@ export class IssuedInvoiceItemsFullSnapshotBuilder
|
|||||||
id: invoiceItem.id.toPrimitive(),
|
id: invoiceItem.id.toPrimitive(),
|
||||||
is_valued: String(invoiceItem.isValued),
|
is_valued: String(invoiceItem.isValued),
|
||||||
position: String(index),
|
position: String(index),
|
||||||
description: maybeToEmptyString(invoiceItem.description, (value) => value.toPrimitive()),
|
|
||||||
|
|
||||||
quantity: invoiceItem.quantity.match(
|
description: maybeToEmptyString(invoiceItem.description, (value) => value.toString()),
|
||||||
(quantity) => quantity.toObjectString(),
|
|
||||||
() => ({ value: "", scale: "" })
|
quantity: maybeToEmptyQuantityObjectString(invoiceItem.quantity),
|
||||||
|
unit_amount: maybeToEmptyMoneyObjectString(invoiceItem.unitAmount),
|
||||||
|
|
||||||
|
subtotal_amount: maybeToEmptyMoneyObjectString(invoiceItem.subtotalAmount),
|
||||||
|
|
||||||
|
discount_percentage: maybeToEmptyPercentageObjectString(invoiceItem.itemDiscountPercentage),
|
||||||
|
discount_amount: maybeToEmptyMoneyObjectString(invoiceItem.itemDiscountAmount),
|
||||||
|
|
||||||
|
global_discount_percentage: maybeToEmptyPercentageObjectString(
|
||||||
|
invoiceItem.globalDiscountPercentage
|
||||||
),
|
),
|
||||||
|
global_discount_amount: maybeToEmptyMoneyObjectString(invoiceItem.globalDiscountAmount),
|
||||||
|
|
||||||
unit_amount: invoiceItem.unitAmount.match(
|
taxable_amount: maybeToEmptyMoneyObjectString(invoiceItem.taxableAmount),
|
||||||
(unitAmount) => unitAmount.toObjectString(),
|
|
||||||
() => ({ value: "", scale: "", currency_code: "" })
|
|
||||||
),
|
|
||||||
|
|
||||||
subtotal_amount: invoiceItem.subtotalAmount.toObjectString(),
|
iva_code: maybeToEmptyString(invoiceItem.ivaCode),
|
||||||
|
iva_percentage: maybeToEmptyPercentageObjectString(invoiceItem.ivaPercentage),
|
||||||
|
iva_amount: maybeToEmptyMoneyObjectString(invoiceItem.ivaAmount),
|
||||||
|
|
||||||
discount_percentage: invoiceItem.itemDiscountPercentage.match(
|
rec_code: maybeToEmptyString(invoiceItem.recCode),
|
||||||
(discountPercentage) => discountPercentage.toObjectString(),
|
rec_percentage: maybeToEmptyPercentageObjectString(invoiceItem.recPercentage),
|
||||||
() => ({ value: "", scale: "" })
|
rec_amount: maybeToEmptyMoneyObjectString(invoiceItem.recAmount),
|
||||||
),
|
|
||||||
|
|
||||||
discount_amount: invoiceItem.itemDiscountAmount.toObjectString(),
|
retention_code: maybeToEmptyString(invoiceItem.retentionCode),
|
||||||
|
retention_percentage: maybeToEmptyPercentageObjectString(invoiceItem.retentionPercentage),
|
||||||
|
retention_amount: maybeToEmptyMoneyObjectString(invoiceItem.retentionAmount),
|
||||||
|
|
||||||
global_discount_percentage: invoiceItem.globalDiscountPercentage.match(
|
taxes_amount: maybeToEmptyMoneyObjectString(invoiceItem.taxesAmount),
|
||||||
(discountPercentage) => discountPercentage.toObjectString(),
|
total_amount: maybeToEmptyMoneyObjectString(invoiceItem.totalAmount),
|
||||||
() => ({ value: "", scale: "" })
|
|
||||||
),
|
|
||||||
|
|
||||||
global_discount_amount: invoiceItem.globalDiscountAmount.toObjectString(),
|
|
||||||
|
|
||||||
taxable_amount: invoiceItem.taxableAmount.toObjectString(),
|
|
||||||
|
|
||||||
iva_code: invoiceItem.taxes.iva.match(
|
|
||||||
(iva) => iva.code,
|
|
||||||
() => ""
|
|
||||||
),
|
|
||||||
|
|
||||||
iva_percentage: invoiceItem.taxes.iva.match(
|
|
||||||
(iva) => iva.percentage.toObjectString(),
|
|
||||||
() => ({ value: "", scale: "" })
|
|
||||||
),
|
|
||||||
|
|
||||||
iva_amount: invoiceItem.ivaAmount.toObjectString(),
|
|
||||||
|
|
||||||
rec_code: invoiceItem.taxes.rec.match(
|
|
||||||
(rec) => rec.code,
|
|
||||||
() => ""
|
|
||||||
),
|
|
||||||
|
|
||||||
rec_percentage: invoiceItem.taxes.rec.match(
|
|
||||||
(rec) => rec.percentage.toObjectString(),
|
|
||||||
() => ({ value: "", scale: "" })
|
|
||||||
),
|
|
||||||
|
|
||||||
rec_amount: invoiceItem.recAmount.toObjectString(),
|
|
||||||
|
|
||||||
retention_code: invoiceItem.taxes.retention.match(
|
|
||||||
(retention) => retention.code,
|
|
||||||
() => ""
|
|
||||||
),
|
|
||||||
|
|
||||||
retention_percentage: invoiceItem.taxes.retention.match(
|
|
||||||
(retention) => retention.percentage.toObjectString(),
|
|
||||||
() => ({ value: "", scale: "" })
|
|
||||||
),
|
|
||||||
|
|
||||||
retention_amount: invoiceItem.retentionAmount.toObjectString(),
|
|
||||||
|
|
||||||
taxes_amount: invoiceItem.taxesAmount.toObjectString(),
|
|
||||||
|
|
||||||
total_amount: invoiceItem.totalAmount.toObjectString(),
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -3,7 +3,7 @@ import { DomainValidationError, maybeToEmptyString } from "@repo/rdx-ddd";
|
|||||||
|
|
||||||
import type { InvoiceRecipient, IssuedInvoice } from "../../../../domain";
|
import type { InvoiceRecipient, IssuedInvoice } from "../../../../domain";
|
||||||
|
|
||||||
import type { IIssuedInvoiceRecipientFullSnapshot } from "./issued-invoice-recipient-full-snapshot.interfce";
|
import type { IIssuedInvoiceRecipientFullSnapshot } from "./issued-invoice-recipient-full-snapshot.interface";
|
||||||
|
|
||||||
export interface IIssuedInvoiceRecipientFullSnapshotBuilder
|
export interface IIssuedInvoiceRecipientFullSnapshotBuilder
|
||||||
extends ISnapshotBuilder<IssuedInvoice, IIssuedInvoiceRecipientFullSnapshot> {}
|
extends ISnapshotBuilder<IssuedInvoice, IIssuedInvoiceRecipientFullSnapshot> {}
|
||||||
|
|||||||
@ -0,0 +1,17 @@
|
|||||||
|
export interface IIssuedInvoiceTaxFullSnapshot {
|
||||||
|
taxable_amount: { value: string; scale: string; currency_code: string };
|
||||||
|
|
||||||
|
iva_code: string;
|
||||||
|
iva_percentage: { value: string; scale: string };
|
||||||
|
iva_amount: { value: string; scale: string; currency_code: string };
|
||||||
|
|
||||||
|
rec_code: string;
|
||||||
|
rec_percentage: { value: string; scale: string };
|
||||||
|
rec_amount: { value: string; scale: string; currency_code: string };
|
||||||
|
|
||||||
|
retention_code: string;
|
||||||
|
retention_percentage: { value: string; scale: string };
|
||||||
|
retention_amount: { value: string; scale: string; currency_code: string };
|
||||||
|
|
||||||
|
taxes_amount: { value: string; scale: string; currency_code: string };
|
||||||
|
}
|
||||||
@ -0,0 +1,41 @@
|
|||||||
|
import type { ISnapshotBuilder } from "@erp/core/api";
|
||||||
|
import {
|
||||||
|
maybeToEmptyMoneyObjectString,
|
||||||
|
maybeToEmptyPercentageObjectString,
|
||||||
|
maybeToEmptyString,
|
||||||
|
} from "@repo/rdx-ddd";
|
||||||
|
|
||||||
|
import type { IssuedInvoiceTax, IssuedInvoiceTaxes } from "../../../../domain";
|
||||||
|
|
||||||
|
import type { IIssuedInvoiceTaxFullSnapshot } from "./issued-invoice-tax-full-snapshot-interface";
|
||||||
|
|
||||||
|
export interface IIssuedInvoiceTaxesFullSnapshotBuilder
|
||||||
|
extends ISnapshotBuilder<IssuedInvoiceTaxes, IIssuedInvoiceTaxFullSnapshot[]> {}
|
||||||
|
|
||||||
|
export class IssuedInvoiceTaxesFullSnapshotBuilder
|
||||||
|
implements IIssuedInvoiceTaxesFullSnapshotBuilder
|
||||||
|
{
|
||||||
|
private mapItem(invoiceTax: IssuedInvoiceTax, index: number): IIssuedInvoiceTaxFullSnapshot {
|
||||||
|
return {
|
||||||
|
taxable_amount: invoiceTax.taxableAmount.toObjectString(),
|
||||||
|
|
||||||
|
iva_code: invoiceTax.ivaCode.toString(),
|
||||||
|
iva_percentage: invoiceTax.ivaPercentage.toObjectString(),
|
||||||
|
iva_amount: invoiceTax.ivaAmount.toObjectString(),
|
||||||
|
|
||||||
|
rec_code: maybeToEmptyString(invoiceTax.recCode),
|
||||||
|
rec_percentage: maybeToEmptyPercentageObjectString(invoiceTax.recPercentage),
|
||||||
|
rec_amount: maybeToEmptyMoneyObjectString(invoiceTax.recAmount),
|
||||||
|
|
||||||
|
retention_code: maybeToEmptyString(invoiceTax.retentionCode),
|
||||||
|
retention_percentage: maybeToEmptyPercentageObjectString(invoiceTax.retentionPercentage),
|
||||||
|
retention_amount: maybeToEmptyMoneyObjectString(invoiceTax.retentionAmount),
|
||||||
|
|
||||||
|
taxes_amount: invoiceTax.taxesAmount.toObjectString(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
toOutput(invoiceTaxes: IssuedInvoiceTaxes): IIssuedInvoiceTaxFullSnapshot[] {
|
||||||
|
return invoiceTaxes.map((item, index) => this.mapItem(item, index));
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,7 +1,7 @@
|
|||||||
export * from "./application-models";
|
export * from "./application-models";
|
||||||
export * from "./di";
|
export * from "./di";
|
||||||
export * from "./dtos";
|
export * from "./dtos";
|
||||||
export * from "./mappers";
|
//export * from "./mappers";
|
||||||
export * from "./repositories";
|
export * from "./repositories";
|
||||||
export * from "./services";
|
export * from "./services";
|
||||||
export * from "./snapshot-builders";
|
export * from "./snapshot-builders";
|
||||||
|
|||||||
@ -17,8 +17,6 @@ import { Maybe, Result } from "@repo/rdx-utils";
|
|||||||
|
|
||||||
import type { CreateProformaItemRequestDTO, CreateProformaRequestDTO } from "../../../../common";
|
import type { CreateProformaItemRequestDTO, CreateProformaRequestDTO } from "../../../../common";
|
||||||
import {
|
import {
|
||||||
CustomerInvoiceItems,
|
|
||||||
type IProformaProps,
|
|
||||||
InvoiceNumber,
|
InvoiceNumber,
|
||||||
InvoicePaymentMethod,
|
InvoicePaymentMethod,
|
||||||
type InvoiceRecipient,
|
type InvoiceRecipient,
|
||||||
|
|||||||
@ -55,6 +55,11 @@ export type IssuedInvoiceProps = {
|
|||||||
totalDiscountAmount: InvoiceAmount;
|
totalDiscountAmount: InvoiceAmount;
|
||||||
|
|
||||||
taxableAmount: InvoiceAmount;
|
taxableAmount: InvoiceAmount;
|
||||||
|
|
||||||
|
ivaAmount: InvoiceAmount;
|
||||||
|
recAmount: InvoiceAmount;
|
||||||
|
retentionAmount: InvoiceAmount;
|
||||||
|
|
||||||
taxesAmount: InvoiceAmount;
|
taxesAmount: InvoiceAmount;
|
||||||
totalAmount: InvoiceAmount;
|
totalAmount: InvoiceAmount;
|
||||||
|
|
||||||
@ -188,6 +193,18 @@ export class IssuedInvoice extends AggregateRoot<IssuedInvoiceProps> {
|
|||||||
return this.props.taxableAmount;
|
return this.props.taxableAmount;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public get ivaAmount(): InvoiceAmount {
|
||||||
|
return this.props.ivaAmount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get recAmount(): InvoiceAmount {
|
||||||
|
return this.props.recAmount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get retentionAmount(): InvoiceAmount {
|
||||||
|
return this.props.retentionAmount;
|
||||||
|
}
|
||||||
|
|
||||||
public get taxesAmount(): InvoiceAmount {
|
public get taxesAmount(): InvoiceAmount {
|
||||||
return this.props.taxesAmount;
|
return this.props.taxesAmount;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,4 +1,3 @@
|
|||||||
export * from "./issued-invoice-items";
|
export * from "./issued-invoice-items";
|
||||||
export * from "./issued-invoice-tax.entity";
|
export * from "./issued-invoice-taxes";
|
||||||
export * from "./issued-invoice-taxes.collection";
|
|
||||||
export * from "./verifactu-record.entity";
|
export * from "./verifactu-record.entity";
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
import type { CurrencyCode, LanguageCode, Percentage } from "@repo/rdx-ddd";
|
import type { CurrencyCode, LanguageCode, Percentage } from "@repo/rdx-ddd";
|
||||||
import { Collection } from "@repo/rdx-utils";
|
import { Collection } from "@repo/rdx-utils";
|
||||||
|
|
||||||
import { InvoiceAmount, ItemDiscountPercentage } from "../../../common";
|
import { ItemDiscountPercentage } from "../../../common";
|
||||||
|
|
||||||
import type { IssuedInvoiceItem } from "./issued-invoice-item.entity";
|
import type { IssuedInvoiceItem } from "./issued-invoice-item.entity";
|
||||||
|
|
||||||
@ -57,10 +57,10 @@ export class IssuedInvoiceItems extends Collection<IssuedInvoiceItem> {
|
|||||||
return super.add(item);
|
return super.add(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
public getTotalAmount(): InvoiceAmount {
|
/*public getTotalAmount(): InvoiceAmount {
|
||||||
return this.getAll().reduce(
|
return this.getAll().reduce(
|
||||||
(acc, item) => acc.add(item.getProps().totalAmount),
|
(acc, item) => acc.add(item.getProps().totalAmount),
|
||||||
InvoiceAmount.zero(this.getAll()[0]?.getProps().totalAmount.currencyCode ?? "EUR")
|
InvoiceAmount.zero(this.getAll()[0]?.getProps().totalAmount.currencyCode ?? "EUR")
|
||||||
);
|
);
|
||||||
}
|
}*/
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,13 +0,0 @@
|
|||||||
import { Collection } from "@repo/rdx-utils";
|
|
||||||
|
|
||||||
import type { IssuedInvoiceTax } from "./issued-invoice-tax.entity";
|
|
||||||
|
|
||||||
export class IssuedInvoiceTaxes extends Collection<IssuedInvoiceTax> {
|
|
||||||
constructor(items: IssuedInvoiceTax[] = []) {
|
|
||||||
super(items);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static create(items: IssuedInvoiceTax[] = []): IssuedInvoiceTaxes {
|
|
||||||
return new IssuedInvoiceTaxes(items);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -0,0 +1,2 @@
|
|||||||
|
export * from "./issued-invoice-tax.entity";
|
||||||
|
export * from "./issued-invoice-taxes.collection";
|
||||||
@ -1,7 +1,7 @@
|
|||||||
import { DomainEntity, type Percentage, type UniqueID } from "@repo/rdx-ddd";
|
import { DomainEntity, type Percentage, type UniqueID } from "@repo/rdx-ddd";
|
||||||
import { type Maybe, Result } from "@repo/rdx-utils";
|
import { type Maybe, Result } from "@repo/rdx-utils";
|
||||||
|
|
||||||
import type { InvoiceAmount } from "../../common";
|
import type { InvoiceAmount } from "../../../common";
|
||||||
|
|
||||||
export type IssuedInvoiceTaxProps = {
|
export type IssuedInvoiceTaxProps = {
|
||||||
taxableAmount: InvoiceAmount;
|
taxableAmount: InvoiceAmount;
|
||||||
@ -0,0 +1,25 @@
|
|||||||
|
import type { CurrencyCode, LanguageCode } from "@repo/rdx-ddd";
|
||||||
|
import { Collection } from "@repo/rdx-utils";
|
||||||
|
|
||||||
|
import type { IssuedInvoiceTax } from "./issued-invoice-tax.entity";
|
||||||
|
|
||||||
|
export type IssuedInvoiceTaxesProps = {
|
||||||
|
taxes?: IssuedInvoiceTax[];
|
||||||
|
languageCode: LanguageCode;
|
||||||
|
currencyCode: CurrencyCode;
|
||||||
|
};
|
||||||
|
|
||||||
|
export class IssuedInvoiceTaxes extends Collection<IssuedInvoiceTax> {
|
||||||
|
private _languageCode!: LanguageCode;
|
||||||
|
private _currencyCode!: CurrencyCode;
|
||||||
|
|
||||||
|
constructor(props: IssuedInvoiceTaxesProps) {
|
||||||
|
super(props.taxes ?? []);
|
||||||
|
this._languageCode = props.languageCode;
|
||||||
|
this._currencyCode = props.currencyCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static create(props: IssuedInvoiceTaxesProps): IssuedInvoiceTaxes {
|
||||||
|
return new IssuedInvoiceTaxes(props);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -88,6 +88,18 @@ export class CustomerInvoiceModel extends Model<
|
|||||||
declare taxable_amount_value: number;
|
declare taxable_amount_value: number;
|
||||||
declare taxable_amount_scale: number;
|
declare taxable_amount_scale: number;
|
||||||
|
|
||||||
|
// IVA amount
|
||||||
|
declare iva_amount_value: number;
|
||||||
|
declare iva_amount_scale: number;
|
||||||
|
|
||||||
|
// Recargo de equivalencia amount
|
||||||
|
declare rec_amount_value: number;
|
||||||
|
declare rec_amount_scale: number;
|
||||||
|
|
||||||
|
// Retention amount
|
||||||
|
declare retention_amount_value: number;
|
||||||
|
declare retention_amount_scale: number;
|
||||||
|
|
||||||
// Total taxes amount / taxes total
|
// Total taxes amount / taxes total
|
||||||
declare taxes_amount_value: number;
|
declare taxes_amount_value: number;
|
||||||
declare taxes_amount_scale: number;
|
declare taxes_amount_scale: number;
|
||||||
@ -350,6 +362,40 @@ export default (database: Sequelize) => {
|
|||||||
defaultValue: 2,
|
defaultValue: 2,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
iva_amount_value: {
|
||||||
|
type: DataTypes.BIGINT,
|
||||||
|
allowNull: true,
|
||||||
|
defaultValue: null,
|
||||||
|
},
|
||||||
|
|
||||||
|
iva_amount_scale: {
|
||||||
|
type: DataTypes.SMALLINT,
|
||||||
|
allowNull: false,
|
||||||
|
defaultValue: 4,
|
||||||
|
},
|
||||||
|
|
||||||
|
rec_amount_value: {
|
||||||
|
type: DataTypes.BIGINT,
|
||||||
|
allowNull: true,
|
||||||
|
defaultValue: null,
|
||||||
|
},
|
||||||
|
rec_amount_scale: {
|
||||||
|
type: DataTypes.SMALLINT,
|
||||||
|
allowNull: false,
|
||||||
|
defaultValue: 4,
|
||||||
|
},
|
||||||
|
|
||||||
|
retention_amount_value: {
|
||||||
|
type: DataTypes.BIGINT,
|
||||||
|
allowNull: true,
|
||||||
|
defaultValue: null,
|
||||||
|
},
|
||||||
|
retention_amount_scale: {
|
||||||
|
type: DataTypes.SMALLINT,
|
||||||
|
allowNull: false,
|
||||||
|
defaultValue: 4,
|
||||||
|
},
|
||||||
|
|
||||||
taxes_amount_value: {
|
taxes_amount_value: {
|
||||||
type: new DataTypes.BIGINT(), // importante: evita problemas de precisión con valores grandes
|
type: new DataTypes.BIGINT(), // importante: evita problemas de precisión con valores grandes
|
||||||
allowNull: false,
|
allowNull: false,
|
||||||
|
|||||||
@ -216,6 +216,33 @@ export class SequelizeIssuedInvoiceDomainMapper
|
|||||||
errors
|
errors
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const ivaAmount = extractOrPushError(
|
||||||
|
InvoiceAmount.create({
|
||||||
|
value: raw.iva_amount_value,
|
||||||
|
currency_code: currencyCode?.code,
|
||||||
|
}),
|
||||||
|
"iva_amount_value",
|
||||||
|
errors
|
||||||
|
);
|
||||||
|
|
||||||
|
const recAmount = extractOrPushError(
|
||||||
|
InvoiceAmount.create({
|
||||||
|
value: raw.rec_amount_value,
|
||||||
|
currency_code: currencyCode?.code,
|
||||||
|
}),
|
||||||
|
"rec_amount_value",
|
||||||
|
errors
|
||||||
|
);
|
||||||
|
|
||||||
|
const retentionAmount = extractOrPushError(
|
||||||
|
InvoiceAmount.create({
|
||||||
|
value: raw.retention_amount_value,
|
||||||
|
currency_code: currencyCode?.code,
|
||||||
|
}),
|
||||||
|
"retention_amount_value",
|
||||||
|
errors
|
||||||
|
);
|
||||||
|
|
||||||
const taxesAmount = extractOrPushError(
|
const taxesAmount = extractOrPushError(
|
||||||
InvoiceAmount.create({
|
InvoiceAmount.create({
|
||||||
value: raw.taxes_amount_value,
|
value: raw.taxes_amount_value,
|
||||||
@ -258,6 +285,9 @@ export class SequelizeIssuedInvoiceDomainMapper
|
|||||||
globalDiscountAmount,
|
globalDiscountAmount,
|
||||||
totalDiscountAmount,
|
totalDiscountAmount,
|
||||||
taxableAmount,
|
taxableAmount,
|
||||||
|
ivaAmount,
|
||||||
|
recAmount,
|
||||||
|
retentionAmount,
|
||||||
taxesAmount,
|
taxesAmount,
|
||||||
totalAmount,
|
totalAmount,
|
||||||
};
|
};
|
||||||
@ -318,18 +348,19 @@ export class SequelizeIssuedInvoiceDomainMapper
|
|||||||
|
|
||||||
// 6) Construcción del agregado (Dominio)
|
// 6) Construcción del agregado (Dominio)
|
||||||
|
|
||||||
|
const verifactu = verifactuResult.data;
|
||||||
|
|
||||||
const items = IssuedInvoiceItems.create({
|
const items = IssuedInvoiceItems.create({
|
||||||
|
items: itemsResults.data.getAll(),
|
||||||
languageCode: attributes.languageCode!,
|
languageCode: attributes.languageCode!,
|
||||||
currencyCode: attributes.currencyCode!,
|
currencyCode: attributes.currencyCode!,
|
||||||
globalDiscountPercentage: attributes.globalDiscountPercentage!,
|
globalDiscountPercentage: attributes.globalDiscountPercentage!,
|
||||||
items: itemsResults.data.getAll(),
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const taxes = IssuedInvoiceTaxes.create({
|
const taxes = IssuedInvoiceTaxes.create({
|
||||||
|
taxes: taxesResults.data.getAll(),
|
||||||
languageCode: attributes.languageCode!,
|
languageCode: attributes.languageCode!,
|
||||||
currencyCode: attributes.currencyCode!,
|
currencyCode: attributes.currencyCode!,
|
||||||
globalDiscountPercentage: attributes.globalDiscountPercentage!,
|
|
||||||
taxes: taxesResults.data.getAll(),
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const invoiceProps: IssuedInvoiceProps = {
|
const invoiceProps: IssuedInvoiceProps = {
|
||||||
@ -360,14 +391,18 @@ export class SequelizeIssuedInvoiceDomainMapper
|
|||||||
totalDiscountAmount: attributes.totalDiscountAmount!,
|
totalDiscountAmount: attributes.totalDiscountAmount!,
|
||||||
|
|
||||||
taxableAmount: attributes.taxableAmount!,
|
taxableAmount: attributes.taxableAmount!,
|
||||||
|
ivaAmount: attributes.ivaAmount!,
|
||||||
|
recAmount: attributes.recAmount!,
|
||||||
|
retentionAmount: attributes.retentionAmount!,
|
||||||
|
|
||||||
taxesAmount: attributes.taxesAmount!,
|
taxesAmount: attributes.taxesAmount!,
|
||||||
totalAmount: attributes.totalAmount!,
|
totalAmount: attributes.totalAmount!,
|
||||||
|
|
||||||
paymentMethod: attributes.paymentMethod!,
|
paymentMethod: attributes.paymentMethod!,
|
||||||
|
|
||||||
items,
|
items,
|
||||||
taxes: taxesResults.data,
|
taxes,
|
||||||
verifactu: verifactuResult.data,
|
verifactu,
|
||||||
};
|
};
|
||||||
|
|
||||||
const createResult = IssuedInvoice.create(invoiceProps, attributes.invoiceId);
|
const createResult = IssuedInvoice.create(invoiceProps, attributes.invoiceId);
|
||||||
@ -479,11 +514,17 @@ export class SequelizeIssuedInvoiceDomainMapper
|
|||||||
subtotal_amount_value: source.subtotalAmount.value,
|
subtotal_amount_value: source.subtotalAmount.value,
|
||||||
subtotal_amount_scale: source.subtotalAmount.scale,
|
subtotal_amount_scale: source.subtotalAmount.scale,
|
||||||
|
|
||||||
discount_percentage_value: source.globalDiscountPercentage.toPrimitive().value,
|
items_discount_amount_value: source.itemsDiscountAmount.value,
|
||||||
discount_percentage_scale: source.globalDiscountPercentage.toPrimitive().scale,
|
items_discount_amount_scale: source.itemsDiscountAmount.scale,
|
||||||
|
|
||||||
discount_amount_value: source.globalDiscountAmount.value,
|
global_discount_percentage_value: source.globalDiscountPercentage.toPrimitive().value,
|
||||||
discount_amount_scale: source.globalDiscountAmount.scale,
|
global_discount_percentage_scale: source.globalDiscountPercentage.toPrimitive().scale,
|
||||||
|
|
||||||
|
global_discount_amount_value: source.globalDiscountAmount.value,
|
||||||
|
global_discount_amount_scale: source.globalDiscountAmount.scale,
|
||||||
|
|
||||||
|
total_discount_amount_value: source.totalDiscountAmount.value,
|
||||||
|
total_discount_amount_scale: source.totalDiscountAmount.scale,
|
||||||
|
|
||||||
taxable_amount_value: source.taxableAmount.value,
|
taxable_amount_value: source.taxableAmount.value,
|
||||||
taxable_amount_scale: source.taxableAmount.scale,
|
taxable_amount_scale: source.taxableAmount.scale,
|
||||||
|
|||||||
@ -339,10 +339,6 @@ export class SequelizeIssuedInvoiceItemDomainMapper extends SequelizeDomainMappe
|
|||||||
maybeToNullable(source.subtotalAmount, (v) => v.toPrimitive().scale) ??
|
maybeToNullable(source.subtotalAmount, (v) => v.toPrimitive().scale) ??
|
||||||
ItemAmount.DEFAULT_SCALE,
|
ItemAmount.DEFAULT_SCALE,
|
||||||
|
|
||||||
// Te has quedado aquí --- IGNORE ---
|
|
||||||
// !!!!!!!!!!!!!!!!!!!
|
|
||||||
|
|
||||||
//
|
|
||||||
discount_percentage_value: maybeToNullable(
|
discount_percentage_value: maybeToNullable(
|
||||||
source.itemDiscountPercentage,
|
source.itemDiscountPercentage,
|
||||||
(v) => v.toPrimitive().value
|
(v) => v.toPrimitive().value
|
||||||
@ -351,29 +347,46 @@ export class SequelizeIssuedInvoiceItemDomainMapper extends SequelizeDomainMappe
|
|||||||
maybeToNullable(source.itemDiscountPercentage, (v) => v.toPrimitive().scale) ??
|
maybeToNullable(source.itemDiscountPercentage, (v) => v.toPrimitive().scale) ??
|
||||||
ItemDiscountPercentage.DEFAULT_SCALE,
|
ItemDiscountPercentage.DEFAULT_SCALE,
|
||||||
|
|
||||||
discount_amount_value: source.itemDiscountAmount.value,
|
discount_amount_value: maybeToNullable(
|
||||||
discount_amount_scale: source.itemDiscountAmount.scale,
|
source.itemDiscountAmount,
|
||||||
|
(v) => v.toPrimitive().value
|
||||||
|
),
|
||||||
|
discount_amount_scale:
|
||||||
|
maybeToNullable(source.itemDiscountPercentage, (v) => v.toPrimitive().scale) ??
|
||||||
|
ItemDiscountPercentage.DEFAULT_SCALE,
|
||||||
|
|
||||||
//
|
|
||||||
global_discount_percentage_value: maybeToNullable(
|
global_discount_percentage_value: maybeToNullable(
|
||||||
source.globalDiscountPercentage,
|
source.globalDiscountPercentage,
|
||||||
(v) => v.toPrimitive().value
|
(v) => v.toPrimitive().value
|
||||||
),
|
),
|
||||||
|
|
||||||
global_discount_percentage_scale:
|
global_discount_percentage_scale:
|
||||||
maybeToNullable(source.globalDiscountPercentage, (v) => v.toPrimitive().scale) ??
|
maybeToNullable(source.globalDiscountPercentage, (v) => v.toPrimitive().scale) ??
|
||||||
ItemDiscountPercentage.DEFAULT_SCALE,
|
ItemDiscountPercentage.DEFAULT_SCALE,
|
||||||
|
|
||||||
global_discount_amount_value: source.globalDiscountAmount.value,
|
global_discount_amount_value: maybeToNullable(
|
||||||
global_discount_amount_scale: source.globalDiscountAmount.scale,
|
source.globalDiscountAmount,
|
||||||
|
(v) => v.toPrimitive().value
|
||||||
|
),
|
||||||
|
global_discount_amount_scale:
|
||||||
|
maybeToNullable(source.globalDiscountAmount, (v) => v.toPrimitive().scale) ??
|
||||||
|
ItemAmount.DEFAULT_SCALE,
|
||||||
|
|
||||||
|
total_discount_amount_value: maybeToNullable(
|
||||||
|
source.totalDiscountAmount,
|
||||||
|
(v) => v.toPrimitive().value
|
||||||
|
),
|
||||||
|
total_discount_amount_scale:
|
||||||
|
maybeToNullable(source.totalDiscountAmount, (v) => v.toPrimitive().scale) ??
|
||||||
|
ItemAmount.DEFAULT_SCALE,
|
||||||
|
|
||||||
|
// Te has quedado aquí --- IGNORE ---
|
||||||
|
// !!!!!!!!!!!!!!!!!!!
|
||||||
|
|
||||||
//
|
//
|
||||||
total_discount_amount_value: source.totalDiscountAmount.value,
|
taxable_amount_value: maybeToNullable(source.taxableAmount, (v) => v.toPrimitive().value),
|
||||||
total_discount_amount_scale: source.totalDiscountAmount.scale,
|
taxable_amount_scale:
|
||||||
|
maybeToNullable(source.taxableAmount, (v) => v.toPrimitive().scale) ??
|
||||||
//
|
ItemAmount.DEFAULT_SCALE,
|
||||||
taxable_amount_value: source.taxableAmount.value,
|
|
||||||
taxable_amount_scale: source.taxableAmount.scale,
|
|
||||||
|
|
||||||
// IVA
|
// IVA
|
||||||
iva_code: maybeToNullableString(source.ivaCode),
|
iva_code: maybeToNullableString(source.ivaCode),
|
||||||
@ -410,12 +423,16 @@ export class SequelizeIssuedInvoiceItemDomainMapper extends SequelizeDomainMappe
|
|||||||
maybeToNullable(source.retentionAmount, (v) => v.toPrimitive().scale) ?? 4,
|
maybeToNullable(source.retentionAmount, (v) => v.toPrimitive().scale) ?? 4,
|
||||||
|
|
||||||
//
|
//
|
||||||
taxes_amount_value: source.taxesAmount.value,
|
taxes_amount_value: maybeToNullable(source.taxesAmount, (v) => v.toPrimitive().value),
|
||||||
taxes_amount_scale: source.taxesAmount.scale,
|
taxes_amount_scale:
|
||||||
|
maybeToNullable(source.taxesAmount, (v) => v.toPrimitive().scale) ??
|
||||||
|
ItemAmount.DEFAULT_SCALE,
|
||||||
|
|
||||||
//
|
//
|
||||||
total_amount_value: source.totalAmount.value,
|
total_amount_value: maybeToNullable(source.totalAmount, (v) => v.toPrimitive().value),
|
||||||
total_amount_scale: source.totalAmount.scale,
|
total_amount_scale:
|
||||||
|
maybeToNullable(source.totalAmount, (v) => v.toPrimitive().scale) ??
|
||||||
|
ItemAmount.DEFAULT_SCALE,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -62,8 +62,9 @@ export const GetIssuedInvoiceByIdResponseSchema = z.object({
|
|||||||
|
|
||||||
subtotal_amount: MoneySchema,
|
subtotal_amount: MoneySchema,
|
||||||
items_discount_amount: MoneySchema,
|
items_discount_amount: MoneySchema,
|
||||||
discount_percentage: PercentageSchema,
|
global_discount_percentage: PercentageSchema,
|
||||||
discount_amount: MoneySchema,
|
global_discount_amount: MoneySchema,
|
||||||
|
total_discount_amount: MoneySchema,
|
||||||
taxable_amount: MoneySchema,
|
taxable_amount: MoneySchema,
|
||||||
iva_amount: MoneySchema,
|
iva_amount: MoneySchema,
|
||||||
rec_amount: MoneySchema,
|
rec_amount: MoneySchema,
|
||||||
|
|||||||
@ -1,8 +1,9 @@
|
|||||||
// application/shared/normalizers.ts
|
|
||||||
// Normalizadores y adaptadores DTO -> Maybe/VO
|
// Normalizadores y adaptadores DTO -> Maybe/VO
|
||||||
|
|
||||||
import { Maybe, Result, isNullishOrEmpty } from "@repo/rdx-utils";
|
import { Maybe, Result, isNullishOrEmpty } from "@repo/rdx-utils";
|
||||||
|
|
||||||
|
import { MoneyValue, Percentage, Quantity } from "../value-objects";
|
||||||
|
|
||||||
/** any | null | undefined -> Maybe<T> usando validación */
|
/** any | null | undefined -> Maybe<T> usando validación */
|
||||||
export function maybeFromNullableResult<T>(
|
export function maybeFromNullableResult<T>(
|
||||||
input: any,
|
input: any,
|
||||||
@ -13,6 +14,115 @@ export function maybeFromNullableResult<T>(
|
|||||||
return value.isSuccess ? Result.ok(Maybe.some(value.data)) : Result.fail(value.error);
|
return value.isSuccess ? Result.ok(Maybe.some(value.data)) : Result.fail(value.error);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Serializa un Maybe aplicando una política de objeto vacío.
|
||||||
|
*
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
function maybeToEmptyObjectString<T, R>(
|
||||||
|
maybe: Maybe<T>,
|
||||||
|
emptyObject: R,
|
||||||
|
defaultSerializer: (value: T) => R,
|
||||||
|
map?: (value: T) => R
|
||||||
|
): R {
|
||||||
|
if (!maybe || maybe.isNone()) {
|
||||||
|
return emptyObject;
|
||||||
|
}
|
||||||
|
|
||||||
|
const value = maybe.unwrap();
|
||||||
|
return map ? map(value) : defaultSerializer(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Serializa un `Maybe<MoneyValue>` a un objeto de transporte normalizado.
|
||||||
|
*
|
||||||
|
* - Si el `Maybe` es `None`, devuelve un objeto vacío:
|
||||||
|
* `{ value: "", scale: "", currency_code: "" }`
|
||||||
|
* - Si es `Some`, aplica la función `map` si está declarada o
|
||||||
|
* aplica el método `toObjectString()` del `MoneyValue`.
|
||||||
|
*
|
||||||
|
* Motivación:
|
||||||
|
* - Evita devolver `null` en la capa de transporte.
|
||||||
|
* - Garantiza una estructura estable para consumidores (API / frontend).
|
||||||
|
* - Centraliza la política de normalización de importes opcionales.
|
||||||
|
*
|
||||||
|
* @typeParam T - Tipo interno del MoneyValue/Amount en dominio.
|
||||||
|
* @param maybe - Instancia `Maybe` que envuelve el Amount de dominio.
|
||||||
|
* @param map - Función que transforma el Amount de dominio al objeto de transporte.
|
||||||
|
* @returns Objeto normalizado de importe listo para transporte.
|
||||||
|
*/
|
||||||
|
export function maybeToEmptyMoneyObjectString(
|
||||||
|
maybe: Maybe<MoneyValue>,
|
||||||
|
map?: (value: MoneyValue) => { value: string; scale: string; currency_code: string }
|
||||||
|
): { value: string; scale: string; currency_code: string } {
|
||||||
|
return maybeToEmptyObjectString(
|
||||||
|
maybe,
|
||||||
|
MoneyValue.EMPTY_MONEY_OBJECT,
|
||||||
|
(value) => value.toObjectString(),
|
||||||
|
map
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Serializa un `Maybe<Percentage>` a un objeto de transporte normalizado.
|
||||||
|
*
|
||||||
|
* - Si el `Maybe` es `None`, devuelve un objeto vacío:
|
||||||
|
* `{ value: "", scale: "" }`
|
||||||
|
* - Si es `Some`, aplica la función `map` si está declarada o
|
||||||
|
* aplica el método `toObjectString()` del `Percentage`.
|
||||||
|
*
|
||||||
|
* Motivación:
|
||||||
|
* - Evita devolver `null` en la capa de transporte.
|
||||||
|
* - Garantiza una estructura estable para consumidores (API / frontend).
|
||||||
|
* - Centraliza la política de normalización de porcentajes opcionales.
|
||||||
|
*
|
||||||
|
* @typeParam T - Tipo interno del Percentage en dominio.
|
||||||
|
* @param maybe - Instancia `Maybe` que envuelve el Percentage de dominio.
|
||||||
|
* @param map - Función que transforma el Percentage de dominio al objeto de transporte.
|
||||||
|
* @returns Objeto normalizado de porcentaje listo para transporte.
|
||||||
|
*/
|
||||||
|
export function maybeToEmptyPercentageObjectString(
|
||||||
|
maybe: Maybe<Percentage>,
|
||||||
|
map?: (value: Percentage) => { value: string; scale: string }
|
||||||
|
): { value: string; scale: string } {
|
||||||
|
return maybeToEmptyObjectString(
|
||||||
|
maybe,
|
||||||
|
Percentage.EMPTY_PERCENTAGE_OBJECT,
|
||||||
|
(value) => value.toObjectString(),
|
||||||
|
map
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Serializa un `Maybe<Quantity>` a un objeto de transporte normalizado.
|
||||||
|
*
|
||||||
|
* - Si el `Maybe` es `None`, devuelve un objeto vacío:
|
||||||
|
* `{ value: "", scale: "" }`
|
||||||
|
* - Si es `Some`, aplica la función `map` si está declarada o
|
||||||
|
* aplica el método `toObjectString()` del `Quantity`.
|
||||||
|
*
|
||||||
|
* Motivación:
|
||||||
|
* - Evita devolver `null` en la capa de transporte.
|
||||||
|
* - Garantiza una estructura estable para consumidores (API / frontend).
|
||||||
|
* - Centraliza la política de normalización de cantidades opcionales.
|
||||||
|
*
|
||||||
|
* @typeParam T - Tipo interno del Quantity en dominio.
|
||||||
|
* @param maybe - Instancia `Maybe` que envuelve el Quantity de dominio.
|
||||||
|
* @param map - Función que transforma el Quantity de dominio al objeto de transporte.
|
||||||
|
* @returns Objeto normalizado de cantidad listo para transporte.
|
||||||
|
*/
|
||||||
|
export function maybeToEmptyQuantityObjectString(
|
||||||
|
maybe: Maybe<Quantity>,
|
||||||
|
map?: (value: Quantity) => { value: string; scale: string }
|
||||||
|
): { value: string; scale: string } {
|
||||||
|
return maybeToEmptyObjectString(
|
||||||
|
maybe,
|
||||||
|
Quantity.EMPTY_QUANTITY_OBJECT,
|
||||||
|
(value) => value.toObjectString(),
|
||||||
|
map
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
/** string | null | undefined -> Maybe<string> (trim, vacío => None) */
|
/** string | null | undefined -> Maybe<string> (trim, vacío => None) */
|
||||||
export function maybeFromNullableOrEmptyString(input?: string | null): Maybe<string> {
|
export function maybeFromNullableOrEmptyString(input?: string | null): Maybe<string> {
|
||||||
if (isNullishOrEmpty(input)) return Maybe.none<string>();
|
if (isNullishOrEmpty(input)) return Maybe.none<string>();
|
||||||
|
|||||||
@ -1,7 +1,8 @@
|
|||||||
import { Result } from "@repo/rdx-utils";
|
import { Result } from "@repo/rdx-utils";
|
||||||
import DineroFactory, { Currency, Dinero } from "dinero.js";
|
import DineroFactory, { type Currency, type Dinero } from "dinero.js";
|
||||||
import { Percentage } from "./percentage";
|
|
||||||
import { Quantity } from "./quantity";
|
import type { Percentage } from "./percentage";
|
||||||
|
import type { Quantity } from "./quantity";
|
||||||
import { ValueObject } from "./value-object";
|
import { ValueObject } from "./value-object";
|
||||||
|
|
||||||
const DEFAULT_SCALE = 2;
|
const DEFAULT_SCALE = 2;
|
||||||
@ -45,6 +46,8 @@ export interface IMoneyValue {
|
|||||||
hasSameCurrency(comparator: MoneyValue): boolean;
|
hasSameCurrency(comparator: MoneyValue): boolean;
|
||||||
hasSameAmount(comparator: MoneyValue): boolean;
|
hasSameAmount(comparator: MoneyValue): boolean;
|
||||||
format(locale: string): string;
|
format(locale: string): string;
|
||||||
|
|
||||||
|
toObjectString(): { value: string; scale: string; currency_code: string };
|
||||||
}
|
}
|
||||||
|
|
||||||
export class MoneyValue extends ValueObject<MoneyValueProps> implements IMoneyValue {
|
export class MoneyValue extends ValueObject<MoneyValueProps> implements IMoneyValue {
|
||||||
@ -52,6 +55,7 @@ export class MoneyValue extends ValueObject<MoneyValueProps> implements IMoneyVa
|
|||||||
|
|
||||||
static DEFAULT_SCALE = DEFAULT_SCALE;
|
static DEFAULT_SCALE = DEFAULT_SCALE;
|
||||||
static DEFAULT_CURRENCY_CODE = DEFAULT_CURRENCY_CODE;
|
static DEFAULT_CURRENCY_CODE = DEFAULT_CURRENCY_CODE;
|
||||||
|
static EMPTY_MONEY_OBJECT = { value: "", scale: "", currency_code: "" };
|
||||||
|
|
||||||
static create({ value, currency_code, scale }: MoneyValueProps) {
|
static create({ value, currency_code, scale }: MoneyValueProps) {
|
||||||
const props = {
|
const props = {
|
||||||
@ -95,13 +99,13 @@ export class MoneyValue extends ValueObject<MoneyValueProps> implements IMoneyVa
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Reconstruye el VO desde la cadena persistida */
|
/** Reconstruye el VO desde la cadena persistida */
|
||||||
static fromPersistence(value: string): MoneyValue {
|
/*static fromPersistence(value: string): MoneyValue {
|
||||||
const [currencyCode, amountStr, scaleStr] = value.split(":");
|
const [currencyCode, amountStr, scaleStr] = value.split(":");
|
||||||
const amount = Number.parseInt(amountStr, 10);
|
const amount = Number.parseInt(amountStr, 10);
|
||||||
const scale = Number.parseInt(scaleStr, 10);
|
const scale = Number.parseInt(scaleStr, 10);
|
||||||
const currency = currencyCode;
|
const currency = currencyCode;
|
||||||
return new MoneyValue({ value: amount, scale, currency_code: currency });
|
return new MoneyValue({ value: amount, scale, currency_code: currency });
|
||||||
}
|
}*/
|
||||||
|
|
||||||
toPrimitive() {
|
toPrimitive() {
|
||||||
return {
|
return {
|
||||||
@ -111,6 +115,14 @@ export class MoneyValue extends ValueObject<MoneyValueProps> implements IMoneyVa
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
toObjectString() {
|
||||||
|
return {
|
||||||
|
value: String(this.value),
|
||||||
|
scale: String(this.scale),
|
||||||
|
currency_code: this.currencyCode,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
convertScale(newScale: number, roundingMode: RoundingMode = "HALF_UP"): MoneyValue {
|
convertScale(newScale: number, roundingMode: RoundingMode = "HALF_UP"): MoneyValue {
|
||||||
const _newDinero = this.dinero.convertPrecision(newScale, roundingMode);
|
const _newDinero = this.dinero.convertPrecision(newScale, roundingMode);
|
||||||
return new MoneyValue({
|
return new MoneyValue({
|
||||||
|
|||||||
@ -26,6 +26,8 @@ export class Percentage extends ValueObject<PercentageProps> {
|
|||||||
static MIN_SCALE = DEFAULT_MIN_SCALE;
|
static MIN_SCALE = DEFAULT_MIN_SCALE;
|
||||||
static MAX_SCALE = DEFAULT_MAX_SCALE;
|
static MAX_SCALE = DEFAULT_MAX_SCALE;
|
||||||
|
|
||||||
|
static EMPTY_PERCENTAGE_OBJECT = { value: "", scale: "" };
|
||||||
|
|
||||||
protected static validate(values: PercentageProps) {
|
protected static validate(values: PercentageProps) {
|
||||||
const schema = z.object({
|
const schema = z.object({
|
||||||
value: z.number().int().min(Percentage.MIN_VALUE, "La cantidad no puede ser negativa."),
|
value: z.number().int().min(Percentage.MIN_VALUE, "La cantidad no puede ser negativa."),
|
||||||
|
|||||||
@ -1,6 +1,8 @@
|
|||||||
import { Result } from "@repo/rdx-utils";
|
import { Result } from "@repo/rdx-utils";
|
||||||
import { z } from "zod/v4";
|
import { z } from "zod/v4";
|
||||||
|
|
||||||
import { translateZodValidationError } from "../helpers";
|
import { translateZodValidationError } from "../helpers";
|
||||||
|
|
||||||
import { ValueObject } from "./value-object";
|
import { ValueObject } from "./value-object";
|
||||||
|
|
||||||
const DEFAULT_SCALE = 2;
|
const DEFAULT_SCALE = 2;
|
||||||
@ -13,6 +15,8 @@ export interface QuantityProps {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export class Quantity extends ValueObject<QuantityProps> {
|
export class Quantity extends ValueObject<QuantityProps> {
|
||||||
|
static EMPTY_QUANTITY_OBJECT = { value: "", scale: "" };
|
||||||
|
|
||||||
protected static validate(values: QuantityProps) {
|
protected static validate(values: QuantityProps) {
|
||||||
const schema = z.object({
|
const schema = z.object({
|
||||||
value: z.number().int(),
|
value: z.number().int(),
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user