This commit is contained in:
David Arranz 2026-02-17 19:13:59 +01:00
parent 7f77b18d52
commit 302f3293c6
67 changed files with 1288 additions and 844 deletions

View File

@ -2,7 +2,7 @@ import {
ValidationErrorCollection, ValidationErrorCollection,
type ValidationErrorDetail, type ValidationErrorDetail,
extractOrPushError, extractOrPushError,
maybeFromNullableVO, maybeFromNullableResult,
} from "@repo/rdx-ddd"; } from "@repo/rdx-ddd";
import { Result } from "@repo/rdx-utils"; import { Result } from "@repo/rdx-utils";
@ -12,7 +12,7 @@ import {
type IssuedInvoiceItemProps, type IssuedInvoiceItemProps,
ItemAmount, ItemAmount,
ItemDescription, ItemDescription,
ItemDiscount, ItemDiscountPercentage,
ItemQuantity, ItemQuantity,
} from "../../domain"; } from "../../domain";
@ -28,25 +28,27 @@ export function mapDTOToCustomerInvoiceItemsProps(
const path = (field: string) => `items[${index}].${field}`; const path = (field: string) => `items[${index}].${field}`;
const description = extractOrPushError( const description = extractOrPushError(
maybeFromNullableVO(item.description, (value) => ItemDescription.create(value)), maybeFromNullableResult(item.description, (value) => ItemDescription.create(value)),
path("description"), path("description"),
errors errors
); );
const quantity = extractOrPushError( const quantity = extractOrPushError(
maybeFromNullableVO(item.quantity, (value) => ItemQuantity.create({ value })), maybeFromNullableResult(item.quantity, (value) => ItemQuantity.create({ value })),
path("quantity"), path("quantity"),
errors errors
); );
const unitAmount = extractOrPushError( const unitAmount = extractOrPushError(
maybeFromNullableVO(item.unit_amount, (value) => ItemAmount.create({ value })), maybeFromNullableResult(item.unit_amount, (value) => ItemAmount.create({ value })),
path("unit_amount"), path("unit_amount"),
errors errors
); );
const discountPercentage = extractOrPushError( const discountPercentage = extractOrPushError(
maybeFromNullableVO(item.discount_percentage, (value) => ItemDiscount.create({ value })), maybeFromNullableResult(item.discount_percentage, (value) =>
ItemDiscountPercentage.create({ value })
),
path("discount_percentage"), path("discount_percentage"),
errors errors
); );

View File

@ -5,7 +5,7 @@ import {
ValidationErrorCollection, ValidationErrorCollection,
type ValidationErrorDetail, type ValidationErrorDetail,
extractOrPushError, extractOrPushError,
maybeFromNullableVO, maybeFromNullableResult,
} from "@repo/rdx-ddd"; } from "@repo/rdx-ddd";
import { Result } from "@repo/rdx-utils"; import { Result } from "@repo/rdx-utils";
@ -30,12 +30,12 @@ export function mapDTOToCustomerInvoiceProps(dto: CreateCustomerInvoiceRequestDT
const invoiceId = extractOrPushError(UniqueID.create(dto.id), "id", errors); const invoiceId = extractOrPushError(UniqueID.create(dto.id), "id", errors);
const invoiceNumber = extractOrPushError( const invoiceNumber = extractOrPushError(
maybeFromNullableVO(dto.invoice_number, (value) => InvoiceNumber.create(value)), maybeFromNullableResult(dto.invoice_number, (value) => InvoiceNumber.create(value)),
"invoice_number", "invoice_number",
errors errors
); );
const invoiceSeries = extractOrPushError( const invoiceSeries = extractOrPushError(
maybeFromNullableVO(dto.series, (value) => InvoiceSerie.create(value)), maybeFromNullableResult(dto.series, (value) => InvoiceSerie.create(value)),
"invoice_series", "invoice_series",
errors errors
); );
@ -45,7 +45,7 @@ export function mapDTOToCustomerInvoiceProps(dto: CreateCustomerInvoiceRequestDT
errors errors
); );
const operationDate = extractOrPushError( const operationDate = extractOrPushError(
maybeFromNullableVO(dto.operation_date, (value) => UtcDate.createFromISO(value)), maybeFromNullableResult(dto.operation_date, (value) => UtcDate.createFromISO(value)),
"operation_date", "operation_date",
errors errors
); );

View File

@ -1,5 +1,5 @@
import type { ISnapshotBuilder } from "@erp/core/api"; import type { ISnapshotBuilder } from "@erp/core/api";
import { toEmptyString } from "@repo/rdx-ddd"; import { maybeToEmptyString } from "@repo/rdx-ddd";
import { InvoiceAmount, type IssuedInvoice } from "../../../../domain"; import { InvoiceAmount, type IssuedInvoice } from "../../../../domain";
@ -87,14 +87,14 @@ export class IssuedInvoiceFullSnapshotBuilder implements IIssuedInvoiceFullSnaps
is_proforma: invoice.isProforma ? "true" : "false", is_proforma: invoice.isProforma ? "true" : "false",
invoice_number: invoice.invoiceNumber.toString(), invoice_number: invoice.invoiceNumber.toString(),
status: invoice.status.toPrimitive(), status: invoice.status.toPrimitive(),
series: toEmptyString(invoice.series, (value) => value.toString()), series: maybeToEmptyString(invoice.series, (value) => value.toString()),
invoice_date: invoice.invoiceDate.toDateString(), invoice_date: invoice.invoiceDate.toDateString(),
operation_date: toEmptyString(invoice.operationDate, (value) => value.toDateString()), operation_date: maybeToEmptyString(invoice.operationDate, (value) => value.toDateString()),
reference: toEmptyString(invoice.reference, (value) => value.toString()), reference: maybeToEmptyString(invoice.reference, (value) => value.toString()),
description: toEmptyString(invoice.description, (value) => value.toString()), description: maybeToEmptyString(invoice.description, (value) => value.toString()),
notes: toEmptyString(invoice.notes, (value) => value.toString()), notes: maybeToEmptyString(invoice.notes, (value) => value.toString()),
language_code: invoice.languageCode.toString(), language_code: invoice.languageCode.toString(),
currency_code: invoice.currencyCode.toString(), currency_code: invoice.currencyCode.toString(),

View File

@ -1,5 +1,5 @@
import type { ISnapshotBuilder } from "@erp/core/api"; import type { ISnapshotBuilder } from "@erp/core/api";
import { toEmptyString } from "@repo/rdx-ddd"; import { maybeToEmptyString } from "@repo/rdx-ddd";
import type { IssuedInvoiceItem, IssuedInvoiceItems } from "../../../../domain"; import type { IssuedInvoiceItem, IssuedInvoiceItems } from "../../../../domain";
@ -16,7 +16,7 @@ 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: toEmptyString(invoiceItem.description, (value) => value.toPrimitive()), description: maybeToEmptyString(invoiceItem.description, (value) => value.toPrimitive()),
quantity: invoiceItem.quantity.match( quantity: invoiceItem.quantity.match(
(quantity) => quantity.toObjectString(), (quantity) => quantity.toObjectString(),

View File

@ -1,5 +1,5 @@
import type { ISnapshotBuilder } from "@erp/core/api"; import type { ISnapshotBuilder } from "@erp/core/api";
import { DomainValidationError, toEmptyString } from "@repo/rdx-ddd"; import { DomainValidationError, maybeToEmptyString } from "@repo/rdx-ddd";
import type { InvoiceRecipient, IssuedInvoice } from "../../../../domain"; import type { InvoiceRecipient, IssuedInvoice } from "../../../../domain";
@ -23,12 +23,12 @@ export class IssuedInvoiceRecipientFullSnapshotBuilder
id: invoice.customerId.toString(), id: invoice.customerId.toString(),
name: recipient.name.toString(), name: recipient.name.toString(),
tin: recipient.tin.toString(), tin: recipient.tin.toString(),
street: toEmptyString(recipient.street, (v) => v.toString()), street: maybeToEmptyString(recipient.street, (v) => v.toString()),
street2: toEmptyString(recipient.street2, (v) => v.toString()), street2: maybeToEmptyString(recipient.street2, (v) => v.toString()),
city: toEmptyString(recipient.city, (v) => v.toString()), city: maybeToEmptyString(recipient.city, (v) => v.toString()),
province: toEmptyString(recipient.province, (v) => v.toString()), province: maybeToEmptyString(recipient.province, (v) => v.toString()),
postal_code: toEmptyString(recipient.postalCode, (v) => v.toString()), postal_code: maybeToEmptyString(recipient.postalCode, (v) => v.toString()),
country: toEmptyString(recipient.country, (v) => v.toString()), country: maybeToEmptyString(recipient.country, (v) => v.toString()),
}), }),
() => ({ () => ({
id: "", id: "",

View File

@ -1,5 +1,5 @@
import type { ISnapshotBuilder } from "@erp/core/api"; import type { ISnapshotBuilder } from "@erp/core/api";
import { toEmptyString } from "@repo/rdx-ddd"; import { maybeToEmptyString } from "@repo/rdx-ddd";
import type { IssuedInvoiceListDTO } from "../../dtos"; import type { IssuedInvoiceListDTO } from "../../dtos";
@ -30,12 +30,12 @@ export class IssuedInvoiceListItemSnapshotBuilder implements IIssuedInvoiceListI
invoice_number: invoice.invoiceNumber.toString(), invoice_number: invoice.invoiceNumber.toString(),
status: invoice.status.toPrimitive(), status: invoice.status.toPrimitive(),
series: toEmptyString(invoice.series, (v) => v.toString()), series: maybeToEmptyString(invoice.series, (v) => v.toString()),
invoice_date: invoice.invoiceDate.toDateString(), invoice_date: invoice.invoiceDate.toDateString(),
operation_date: toEmptyString(invoice.operationDate, (v) => v.toDateString()), operation_date: maybeToEmptyString(invoice.operationDate, (v) => v.toDateString()),
reference: toEmptyString(invoice.reference, (v) => v.toString()), reference: maybeToEmptyString(invoice.reference, (v) => v.toString()),
description: toEmptyString(invoice.description, (v) => v.toString()), description: maybeToEmptyString(invoice.description, (v) => v.toString()),
recipient, recipient,

View File

@ -11,7 +11,7 @@ import {
ValidationErrorCollection, ValidationErrorCollection,
type ValidationErrorDetail, type ValidationErrorDetail,
extractOrPushError, extractOrPushError,
maybeFromNullableVO, maybeFromNullableResult,
} from "@repo/rdx-ddd"; } from "@repo/rdx-ddd";
import { Maybe, Result } from "@repo/rdx-utils"; import { Maybe, Result } from "@repo/rdx-utils";
@ -28,7 +28,7 @@ import {
type IssuedInvoiceItemProps, type IssuedInvoiceItemProps,
ItemAmount, ItemAmount,
ItemDescription, ItemDescription,
ItemDiscount, ItemDiscountPercentage,
ItemQuantity, ItemQuantity,
} from "../../../domain"; } from "../../../domain";
@ -79,7 +79,7 @@ export class CreateProformaPropsMapper {
); );
const series = extractOrPushError( const series = extractOrPushError(
maybeFromNullableVO(dto.series, (value) => InvoiceSerie.create(value)), maybeFromNullableResult(dto.series, (value) => InvoiceSerie.create(value)),
"series", "series",
this.errors this.errors
); );
@ -91,25 +91,25 @@ export class CreateProformaPropsMapper {
); );
const operationDate = extractOrPushError( const operationDate = extractOrPushError(
maybeFromNullableVO(dto.operation_date, (value) => UtcDate.createFromISO(value)), maybeFromNullableResult(dto.operation_date, (value) => UtcDate.createFromISO(value)),
"operation_date", "operation_date",
this.errors this.errors
); );
const reference = extractOrPushError( const reference = extractOrPushError(
maybeFromNullableVO(dto.reference, (value) => Result.ok(String(value))), maybeFromNullableResult(dto.reference, (value) => Result.ok(String(value))),
"reference", "reference",
this.errors this.errors
); );
const description = extractOrPushError( const description = extractOrPushError(
maybeFromNullableVO(dto.reference, (value) => Result.ok(String(value))), maybeFromNullableResult(dto.reference, (value) => Result.ok(String(value))),
"description", "description",
this.errors this.errors
); );
const notes = extractOrPushError( const notes = extractOrPushError(
maybeFromNullableVO(dto.notes, (value) => TextValue.create(value)), maybeFromNullableResult(dto.notes, (value) => TextValue.create(value)),
"notes", "notes",
this.errors this.errors
); );
@ -127,7 +127,7 @@ export class CreateProformaPropsMapper {
); );
const paymentMethod = extractOrPushError( const paymentMethod = extractOrPushError(
maybeFromNullableVO(dto.payment_method, (value) => maybeFromNullableResult(dto.payment_method, (value) =>
InvoicePaymentMethod.create({ paymentDescription: value }) InvoicePaymentMethod.create({ paymentDescription: value })
), ),
"payment_method", "payment_method",
@ -195,25 +195,27 @@ export class CreateProformaPropsMapper {
items.forEach((item, index) => { items.forEach((item, index) => {
const description = extractOrPushError( const description = extractOrPushError(
maybeFromNullableVO(item.description, (value) => ItemDescription.create(value)), maybeFromNullableResult(item.description, (value) => ItemDescription.create(value)),
"description", "description",
this.errors this.errors
); );
const quantity = extractOrPushError( const quantity = extractOrPushError(
maybeFromNullableVO(item.quantity, (value) => ItemQuantity.create(value)), maybeFromNullableResult(item.quantity, (value) => ItemQuantity.create(value)),
"quantity", "quantity",
this.errors this.errors
); );
const unitAmount = extractOrPushError( const unitAmount = extractOrPushError(
maybeFromNullableVO(item.unit_amount, (value) => ItemAmount.create(value)), maybeFromNullableResult(item.unit_amount, (value) => ItemAmount.create(value)),
"unit_amount", "unit_amount",
this.errors this.errors
); );
const discountPercentage = extractOrPushError( const discountPercentage = extractOrPushError(
maybeFromNullableVO(item.discount_percentage, (value) => ItemDiscount.create(value)), maybeFromNullableResult(item.discount_percentage, (value) =>
ItemDiscountPercentage.create(value)
),
"discount_percentage", "discount_percentage",
this.errors this.errors
); );

View File

@ -8,7 +8,7 @@ import {
ValidationErrorCollection, ValidationErrorCollection,
type ValidationErrorDetail, type ValidationErrorDetail,
extractOrPushError, extractOrPushError,
maybeFromNullableVO, maybeFromNullableResult,
} from "@repo/rdx-ddd"; } from "@repo/rdx-ddd";
import { Result, isNullishOrEmpty, toPatchField } from "@repo/rdx-utils"; import { Result, isNullishOrEmpty, toPatchField } from "@repo/rdx-utils";
@ -36,7 +36,7 @@ export function UpdateProformaPropsMapper(dto: UpdateProformaByIdRequestDTO) {
toPatchField(dto.series).ifSet((series) => { toPatchField(dto.series).ifSet((series) => {
props.series = extractOrPushError( props.series = extractOrPushError(
maybeFromNullableVO(series, (value) => CustomerInvoiceSerie.create(value)), maybeFromNullableResult(series, (value) => CustomerInvoiceSerie.create(value)),
"reference", "reference",
errors errors
); );
@ -56,7 +56,7 @@ export function UpdateProformaPropsMapper(dto: UpdateProformaByIdRequestDTO) {
toPatchField(dto.operation_date).ifSet((operation_date) => { toPatchField(dto.operation_date).ifSet((operation_date) => {
props.operationDate = extractOrPushError( props.operationDate = extractOrPushError(
maybeFromNullableVO(operation_date, (value) => UtcDate.createFromISO(value)), maybeFromNullableResult(operation_date, (value) => UtcDate.createFromISO(value)),
"operation_date", "operation_date",
errors errors
); );
@ -72,7 +72,7 @@ export function UpdateProformaPropsMapper(dto: UpdateProformaByIdRequestDTO) {
toPatchField(dto.reference).ifSet((reference) => { toPatchField(dto.reference).ifSet((reference) => {
props.reference = extractOrPushError( props.reference = extractOrPushError(
maybeFromNullableVO(reference, (value) => Result.ok(String(value))), maybeFromNullableResult(reference, (value) => Result.ok(String(value))),
"reference", "reference",
errors errors
); );
@ -80,7 +80,7 @@ export function UpdateProformaPropsMapper(dto: UpdateProformaByIdRequestDTO) {
toPatchField(dto.description).ifSet((description) => { toPatchField(dto.description).ifSet((description) => {
props.description = extractOrPushError( props.description = extractOrPushError(
maybeFromNullableVO(description, (value) => Result.ok(String(value))), maybeFromNullableResult(description, (value) => Result.ok(String(value))),
"description", "description",
errors errors
); );
@ -88,7 +88,7 @@ export function UpdateProformaPropsMapper(dto: UpdateProformaByIdRequestDTO) {
toPatchField(dto.notes).ifSet((notes) => { toPatchField(dto.notes).ifSet((notes) => {
props.notes = extractOrPushError( props.notes = extractOrPushError(
maybeFromNullableVO(notes, (value) => TextValue.create(value)), maybeFromNullableResult(notes, (value) => TextValue.create(value)),
"notes", "notes",
errors errors
); );

View File

@ -1,5 +1,5 @@
import type { ISnapshotBuilder } from "@erp/core/api"; import type { ISnapshotBuilder } from "@erp/core/api";
import { toEmptyString } from "@repo/rdx-ddd"; import { maybeToEmptyString } from "@repo/rdx-ddd";
import { InvoiceAmount, type Proforma } from "../../../../domain"; import { InvoiceAmount, type Proforma } from "../../../../domain";
@ -86,14 +86,14 @@ export class ProformaFullSnapshotBuilder implements IProformaFullSnapshotBuilder
is_proforma: invoice.isProforma ? "true" : "false", is_proforma: invoice.isProforma ? "true" : "false",
invoice_number: invoice.invoiceNumber.toString(), invoice_number: invoice.invoiceNumber.toString(),
status: invoice.status.toPrimitive(), status: invoice.status.toPrimitive(),
series: toEmptyString(invoice.series, (value) => value.toString()), series: maybeToEmptyString(invoice.series, (value) => value.toString()),
invoice_date: invoice.invoiceDate.toDateString(), invoice_date: invoice.invoiceDate.toDateString(),
operation_date: toEmptyString(invoice.operationDate, (value) => value.toDateString()), operation_date: maybeToEmptyString(invoice.operationDate, (value) => value.toDateString()),
reference: toEmptyString(invoice.reference, (value) => value.toString()), reference: maybeToEmptyString(invoice.reference, (value) => value.toString()),
description: toEmptyString(invoice.description, (value) => value.toString()), description: maybeToEmptyString(invoice.description, (value) => value.toString()),
notes: toEmptyString(invoice.notes, (value) => value.toString()), notes: maybeToEmptyString(invoice.notes, (value) => value.toString()),
language_code: invoice.languageCode.toString(), language_code: invoice.languageCode.toString(),
currency_code: invoice.currencyCode.toString(), currency_code: invoice.currencyCode.toString(),

View File

@ -1,5 +1,5 @@
import type { ISnapshotBuilder } from "@erp/core/api"; import type { ISnapshotBuilder } from "@erp/core/api";
import { toEmptyString } from "@repo/rdx-ddd"; import { maybeToEmptyString } from "@repo/rdx-ddd";
import type { CustomerInvoiceItems, IssuedInvoiceItem } from "../../../../domain"; import type { CustomerInvoiceItems, IssuedInvoiceItem } from "../../../../domain";
@ -16,7 +16,7 @@ export class ProformaItemsFullSnapshotBuilder implements IProformaItemsFullSnaps
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: toEmptyString(invoiceItem.description, (value) => value.toPrimitive()), description: maybeToEmptyString(invoiceItem.description, (value) => value.toPrimitive()),
quantity: invoiceItem.quantity.match( quantity: invoiceItem.quantity.match(
(quantity) => quantity.toObjectString(), (quantity) => quantity.toObjectString(),

View File

@ -1,5 +1,5 @@
import type { ISnapshotBuilder } from "@erp/core/api"; import type { ISnapshotBuilder } from "@erp/core/api";
import { DomainValidationError, toEmptyString } from "@repo/rdx-ddd"; import { DomainValidationError, maybeToEmptyString } from "@repo/rdx-ddd";
import type { InvoiceRecipient, Proforma } from "../../../../domain"; import type { InvoiceRecipient, Proforma } from "../../../../domain";
import type { ProformaRecipientFullSnapshot } from "../../application-models"; import type { ProformaRecipientFullSnapshot } from "../../application-models";
@ -20,12 +20,12 @@ export class ProformaRecipientFullSnapshotBuilder implements IProformaRecipientF
id: invoice.customerId.toString(), id: invoice.customerId.toString(),
name: recipient.name.toString(), name: recipient.name.toString(),
tin: recipient.tin.toString(), tin: recipient.tin.toString(),
street: toEmptyString(recipient.street, (v) => v.toString()), street: maybeToEmptyString(recipient.street, (v) => v.toString()),
street2: toEmptyString(recipient.street2, (v) => v.toString()), street2: maybeToEmptyString(recipient.street2, (v) => v.toString()),
city: toEmptyString(recipient.city, (v) => v.toString()), city: maybeToEmptyString(recipient.city, (v) => v.toString()),
province: toEmptyString(recipient.province, (v) => v.toString()), province: maybeToEmptyString(recipient.province, (v) => v.toString()),
postal_code: toEmptyString(recipient.postalCode, (v) => v.toString()), postal_code: maybeToEmptyString(recipient.postalCode, (v) => v.toString()),
country: toEmptyString(recipient.country, (v) => v.toString()), country: maybeToEmptyString(recipient.country, (v) => v.toString()),
}), }),
() => ({ () => ({
id: "", id: "",

View File

@ -1,5 +1,5 @@
import type { ISnapshotBuilder } from "@erp/core/api"; import type { ISnapshotBuilder } from "@erp/core/api";
import { toEmptyString } from "@repo/rdx-ddd"; import { maybeToEmptyString } from "@repo/rdx-ddd";
import type { CustomerInvoiceListDTO } from "../../../../infrastructure"; import type { CustomerInvoiceListDTO } from "../../../../infrastructure";
import type { ProformaListItemSnapshot } from "../../application-models"; import type { ProformaListItemSnapshot } from "../../application-models";
@ -19,12 +19,12 @@ export class ProformaListItemSnapshotBuilder implements IProformaListItemSnapsho
invoice_number: proforma.invoiceNumber.toString(), invoice_number: proforma.invoiceNumber.toString(),
status: proforma.status.toPrimitive(), status: proforma.status.toPrimitive(),
series: toEmptyString(proforma.series, (value) => value.toString()), series: maybeToEmptyString(proforma.series, (value) => value.toString()),
invoice_date: proforma.invoiceDate.toDateString(), invoice_date: proforma.invoiceDate.toDateString(),
operation_date: toEmptyString(proforma.operationDate, (value) => value.toDateString()), operation_date: maybeToEmptyString(proforma.operationDate, (value) => value.toDateString()),
reference: toEmptyString(proforma.reference, (value) => value.toString()), reference: maybeToEmptyString(proforma.reference, (value) => value.toString()),
description: toEmptyString(proforma.description, (value) => value.toString()), description: maybeToEmptyString(proforma.description, (value) => value.toString()),
recipient, recipient,

View File

@ -1,6 +1,6 @@
import { SnapshotBuilder } from "@erp/core/api"; import { SnapshotBuilder } from "@erp/core/api";
import type { GetProformaByIdResponseDTO } from "@erp/customer-invoices/common"; import type { GetProformaByIdResponseDTO } from "@erp/customer-invoices/common";
import { toEmptyString } from "@repo/rdx-ddd"; import { maybeToEmptyString } from "@repo/rdx-ddd";
import type { ArrayElement } from "@repo/rdx-utils"; import type { ArrayElement } from "@repo/rdx-utils";
import type { CustomerInvoiceItems, IssuedInvoiceItem } from "../../../../domain"; import type { CustomerInvoiceItems, IssuedInvoiceItem } from "../../../../domain";
@ -15,7 +15,7 @@ export class ProformaItemsFullPresenter extends SnapshotBuilder {
id: proformaItem.id.toPrimitive(), id: proformaItem.id.toPrimitive(),
is_valued: String(proformaItem.isValued), is_valued: String(proformaItem.isValued),
position: String(index), position: String(index),
description: toEmptyString(proformaItem.description, (value) => value.toPrimitive()), description: maybeToEmptyString(proformaItem.description, (value) => value.toPrimitive()),
quantity: proformaItem.quantity.match( quantity: proformaItem.quantity.match(
(quantity) => quantity.toObjectString(), (quantity) => quantity.toObjectString(),

View File

@ -1,5 +1,5 @@
import { SnapshotBuilder } from "@erp/core/api"; import { SnapshotBuilder } from "@erp/core/api";
import { DomainValidationError, toEmptyString } from "@repo/rdx-ddd"; import { DomainValidationError, maybeToEmptyString } from "@repo/rdx-ddd";
import type { GetIssuedInvoiceByIdResponseDTO as GetProformaByIdResponseDTO } from "../../../../../common/dto"; import type { GetIssuedInvoiceByIdResponseDTO as GetProformaByIdResponseDTO } from "../../../../../common/dto";
import type { InvoiceRecipient, Proforma } from "../../../../domain"; import type { InvoiceRecipient, Proforma } from "../../../../domain";
@ -20,12 +20,12 @@ export class ProformaRecipientFullPresenter extends SnapshotBuilder {
id: proforma.customerId.toString(), id: proforma.customerId.toString(),
name: recipient.name.toString(), name: recipient.name.toString(),
tin: recipient.tin.toString(), tin: recipient.tin.toString(),
street: toEmptyString(recipient.street, (value) => value.toString()), street: maybeToEmptyString(recipient.street, (value) => value.toString()),
street2: toEmptyString(recipient.street2, (value) => value.toString()), street2: maybeToEmptyString(recipient.street2, (value) => value.toString()),
city: toEmptyString(recipient.city, (value) => value.toString()), city: maybeToEmptyString(recipient.city, (value) => value.toString()),
province: toEmptyString(recipient.province, (value) => value.toString()), province: maybeToEmptyString(recipient.province, (value) => value.toString()),
postal_code: toEmptyString(recipient.postalCode, (value) => value.toString()), postal_code: maybeToEmptyString(recipient.postalCode, (value) => value.toString()),
country: toEmptyString(recipient.country, (value) => value.toString()), country: maybeToEmptyString(recipient.country, (value) => value.toString()),
}; };
}, },
() => { () => {

View File

@ -1,5 +1,5 @@
import { Presenter } from "@erp/core/api"; import { Presenter } from "@erp/core/api";
import { toEmptyString } from "@repo/rdx-ddd"; import { maybeToEmptyString } from "@repo/rdx-ddd";
import type { GetProformaByIdResponseDTO } from "../../../../../common/dto"; import type { GetProformaByIdResponseDTO } from "../../../../../common/dto";
import { InvoiceAmount, type Proforma } from "../../../../domain"; import { InvoiceAmount, type Proforma } from "../../../../domain";
@ -87,14 +87,14 @@ export class ProformaFullPresenter extends Presenter<Proforma, GetProformaByIdRe
is_proforma: proforma.isProforma ? "true" : "false", is_proforma: proforma.isProforma ? "true" : "false",
invoice_number: proforma.invoiceNumber.toString(), invoice_number: proforma.invoiceNumber.toString(),
status: proforma.status.toPrimitive(), status: proforma.status.toPrimitive(),
series: toEmptyString(proforma.series, (value) => value.toString()), series: maybeToEmptyString(proforma.series, (value) => value.toString()),
invoice_date: proforma.invoiceDate.toDateString(), invoice_date: proforma.invoiceDate.toDateString(),
operation_date: toEmptyString(proforma.operationDate, (value) => value.toDateString()), operation_date: maybeToEmptyString(proforma.operationDate, (value) => value.toDateString()),
reference: toEmptyString(proforma.reference, (value) => value.toString()), reference: maybeToEmptyString(proforma.reference, (value) => value.toString()),
description: toEmptyString(proforma.description, (value) => value.toString()), description: maybeToEmptyString(proforma.description, (value) => value.toString()),
notes: toEmptyString(proforma.notes, (value) => value.toString()), notes: maybeToEmptyString(proforma.notes, (value) => value.toString()),
language_code: proforma.languageCode.toString(), language_code: proforma.languageCode.toString(),
currency_code: proforma.currencyCode.toString(), currency_code: proforma.currencyCode.toString(),

View File

@ -1,5 +1,5 @@
import type { Criteria } from "@repo/rdx-criteria/server"; import type { Criteria } from "@repo/rdx-criteria/server";
import { toEmptyString } from "@repo/rdx-ddd"; import { maybeToEmptyString } from "@repo/rdx-ddd";
import type { ArrayElement, Collection } from "@repo/rdx-utils"; import type { ArrayElement, Collection } from "@repo/rdx-utils";
import type { ListIssuedInvoicesResponseDTO } from "../../../../../common/dto"; import type { ListIssuedInvoicesResponseDTO } from "../../../../../common/dto";
@ -26,12 +26,12 @@ export class IssuedInvoiceListPresenter extends Presenter {
invoice_number: invoice.invoiceNumber.toString(), invoice_number: invoice.invoiceNumber.toString(),
status: invoice.status.toPrimitive(), status: invoice.status.toPrimitive(),
series: toEmptyString(invoice.series, (value) => value.toString()), series: maybeToEmptyString(invoice.series, (value) => value.toString()),
invoice_date: invoice.invoiceDate.toDateString(), invoice_date: invoice.invoiceDate.toDateString(),
operation_date: toEmptyString(invoice.operationDate, (value) => value.toDateString()), operation_date: maybeToEmptyString(invoice.operationDate, (value) => value.toDateString()),
reference: toEmptyString(invoice.reference, (value) => value.toString()), reference: maybeToEmptyString(invoice.reference, (value) => value.toString()),
description: toEmptyString(invoice.description, (value) => value.toString()), description: maybeToEmptyString(invoice.description, (value) => value.toString()),
recipient: recipientDTO, recipient: recipientDTO,

View File

@ -1,6 +1,6 @@
import { Presenter } from "@erp/core/api"; import { Presenter } from "@erp/core/api";
import type { Criteria } from "@repo/rdx-criteria/server"; import type { Criteria } from "@repo/rdx-criteria/server";
import { toEmptyString } from "@repo/rdx-ddd"; import { maybeToEmptyString } from "@repo/rdx-ddd";
import type { ArrayElement, Collection } from "@repo/rdx-utils"; import type { ArrayElement, Collection } from "@repo/rdx-utils";
import type { ListProformasResponseDTO } from "../../../../../common/dto"; import type { ListProformasResponseDTO } from "../../../../../common/dto";
@ -18,12 +18,12 @@ export class ProformaListPresenter extends Presenter {
invoice_number: proforma.invoiceNumber.toString(), invoice_number: proforma.invoiceNumber.toString(),
status: proforma.status.toPrimitive(), status: proforma.status.toPrimitive(),
series: toEmptyString(proforma.series, (value) => value.toString()), series: maybeToEmptyString(proforma.series, (value) => value.toString()),
invoice_date: proforma.invoiceDate.toDateString(), invoice_date: proforma.invoiceDate.toDateString(),
operation_date: toEmptyString(proforma.operationDate, (value) => value.toDateString()), operation_date: maybeToEmptyString(proforma.operationDate, (value) => value.toDateString()),
reference: toEmptyString(proforma.reference, (value) => value.toString()), reference: maybeToEmptyString(proforma.reference, (value) => value.toString()),
description: toEmptyString(proforma.description, (value) => value.toString()), description: maybeToEmptyString(proforma.description, (value) => value.toString()),
recipient: recipientDTO, recipient: recipientDTO,

View File

@ -1,12 +1,15 @@
export * from "./invoice-address-type.vo"; export * from "./invoice-address-type.vo";
export * from "./invoice-amount.vo"; export * from "./invoice-amount.vo";
export * from "./invoice-discount-percentage.vo";
export * from "./invoice-number.vo"; export * from "./invoice-number.vo";
export * from "./invoice-recipient"; export * from "./invoice-recipient";
export * from "./invoice-serie.vo"; export * from "./invoice-serie.vo";
export * from "./invoice-status.vo"; export * from "./invoice-status.vo";
export * from "./invoice-tax-group.vo"; export * from "./invoice-tax-group.vo";
export * from "./invoice-tax-percentage.vo";
export * from "./item-amount.vo"; export * from "./item-amount.vo";
export * from "./item-description.vo"; export * from "./item-description.vo";
export * from "./item-discount.vo"; export * from "./item-discount-percentage.vo";
export * from "./item-quantity.vo"; export * from "./item-quantity.vo";
export * from "./item-tax-group.vo"; export * from "./item-tax-group.vo";
export * from "./item-tax-percentage.vo";

View File

@ -0,0 +1,19 @@
import { Percentage, type PercentageProps } from "@repo/rdx-ddd";
import type { Result } from "@repo/rdx-utils";
type InvoiceDiscountPercentageProps = Pick<PercentageProps, "value">;
export class InvoiceDiscountPercentage extends Percentage {
static DEFAULT_SCALE = 2;
static create({ value }: InvoiceDiscountPercentageProps): Result<Percentage> {
return Percentage.create({
value,
scale: InvoiceDiscountPercentage.DEFAULT_SCALE,
});
}
static zero() {
return InvoiceDiscountPercentage.create({ value: 0 }).data;
}
}

View File

@ -7,7 +7,7 @@ import {
type Street, type Street,
type TINNumber, type TINNumber,
ValueObject, ValueObject,
toEmptyString, maybeToEmptyString,
} from "@repo/rdx-ddd"; } from "@repo/rdx-ddd";
import { type Maybe, Result } from "@repo/rdx-utils"; import { type Maybe, Result } from "@repo/rdx-utils";
@ -90,12 +90,12 @@ export class InvoiceRecipient extends ValueObject<InvoiceRecipientProps> {
return { return {
tin: this.tin.toString(), tin: this.tin.toString(),
name: this.name.toString(), name: this.name.toString(),
street: toEmptyString(this.street, (value) => value.toString()), street: maybeToEmptyString(this.street, (value) => value.toString()),
street2: toEmptyString(this.street2, (value) => value.toString()), street2: maybeToEmptyString(this.street2, (value) => value.toString()),
city: toEmptyString(this.city, (value) => value.toString()), city: maybeToEmptyString(this.city, (value) => value.toString()),
postal_code: toEmptyString(this.postalCode, (value) => value.toString()), postal_code: maybeToEmptyString(this.postalCode, (value) => value.toString()),
province: toEmptyString(this.province, (value) => value.toString()), province: maybeToEmptyString(this.province, (value) => value.toString()),
country: toEmptyString(this.country, (value) => value.toString()), country: maybeToEmptyString(this.country, (value) => value.toString()),
}; };
} }
} }

View File

@ -0,0 +1,19 @@
import { Percentage, type PercentageProps } from "@repo/rdx-ddd";
import type { Result } from "@repo/rdx-utils";
type InvoiceTaxPercentageProps = Pick<PercentageProps, "value">;
export class InvoiceTaxPercentage extends Percentage {
static DEFAULT_SCALE = 2;
static create({ value }: InvoiceTaxPercentageProps): Result<Percentage> {
return Percentage.create({
value,
scale: InvoiceTaxPercentage.DEFAULT_SCALE,
});
}
static zero() {
return InvoiceTaxPercentage.create({ value: 0 }).data;
}
}

View File

@ -0,0 +1,19 @@
import { Percentage, type PercentageProps } from "@repo/rdx-ddd";
import type { Result } from "@repo/rdx-utils";
type ItemDiscountPercentageProps = Pick<PercentageProps, "value">;
export class ItemDiscountPercentage extends Percentage {
static DEFAULT_SCALE = 2;
static create({ value }: ItemDiscountPercentageProps): Result<Percentage> {
return Percentage.create({
value,
scale: ItemDiscountPercentage.DEFAULT_SCALE,
});
}
static zero() {
return ItemDiscountPercentage.create({ value: 0 }).data;
}
}

View File

@ -1,19 +0,0 @@
import { Percentage, type PercentageProps } from "@repo/rdx-ddd";
import type { Result } from "@repo/rdx-utils";
type ItemDiscountProps = Pick<PercentageProps, "value">;
export class ItemDiscount extends Percentage {
static DEFAULT_SCALE = 2;
static create({ value }: ItemDiscountProps): Result<Percentage> {
return Percentage.create({
value,
scale: ItemDiscount.DEFAULT_SCALE,
});
}
static zero() {
return ItemDiscount.create({ value: 0 }).data;
}
}

View File

@ -0,0 +1,19 @@
import { Percentage, type PercentageProps } from "@repo/rdx-ddd";
import type { Result } from "@repo/rdx-utils";
type ItemTaxPercentageProps = Pick<PercentageProps, "value">;
export class ItemTaxPercentage extends Percentage {
static DEFAULT_SCALE = 2;
static create({ value }: ItemTaxPercentageProps): Result<Percentage> {
return Percentage.create({
value,
scale: ItemTaxPercentage.DEFAULT_SCALE,
});
}
static zero() {
return ItemTaxPercentage.create({ value: 0 }).data;
}
}

View File

@ -49,17 +49,12 @@ export type IssuedInvoiceProps = {
subtotalAmount: InvoiceAmount; subtotalAmount: InvoiceAmount;
itemDiscountAmount: InvoiceAmount; itemsDiscountAmount: InvoiceAmount;
globalDiscountPercentage: Percentage; globalDiscountPercentage: Percentage;
globalDiscountAmount: InvoiceAmount; globalDiscountAmount: InvoiceAmount;
totalDiscountAmount: InvoiceAmount; totalDiscountAmount: InvoiceAmount;
taxableAmount: InvoiceAmount; taxableAmount: InvoiceAmount;
ivaAmount: InvoiceAmount;
recAmount: InvoiceAmount;
retentionAmount: InvoiceAmount;
taxesAmount: InvoiceAmount; taxesAmount: InvoiceAmount;
totalAmount: InvoiceAmount; totalAmount: InvoiceAmount;
@ -173,8 +168,8 @@ export class IssuedInvoice extends AggregateRoot<IssuedInvoiceProps> {
return this.props.subtotalAmount; return this.props.subtotalAmount;
} }
public get itemDiscountAmount(): InvoiceAmount { public get itemsDiscountAmount(): InvoiceAmount {
return this.props.itemDiscountAmount; return this.props.itemsDiscountAmount;
} }
public get globalDiscountPercentage(): Percentage { public get globalDiscountPercentage(): Percentage {

View File

@ -1,13 +1,18 @@
import { type CurrencyCode, DomainEntity, type LanguageCode, type UniqueID } from "@repo/rdx-ddd"; import {
type CurrencyCode,
DomainEntity,
type LanguageCode,
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 { import type {
InvoiceAmount, InvoiceAmount,
ItemAmount, ItemAmount,
ItemDescription, ItemDescription,
ItemDiscount, ItemDiscountPercentage,
ItemQuantity, ItemQuantity,
ItemTaxGroup,
} from "../../../common"; } from "../../../common";
/** /**
@ -26,26 +31,32 @@ export type IssuedInvoiceItemProps = {
quantity: Maybe<ItemQuantity>; quantity: Maybe<ItemQuantity>;
unitAmount: Maybe<ItemAmount>; unitAmount: Maybe<ItemAmount>;
subtotalAmount: InvoiceAmount; subtotalAmount: Maybe<InvoiceAmount>;
itemDiscountPercentage: Maybe<ItemDiscount>; itemDiscountPercentage: Maybe<ItemDiscountPercentage>;
itemDiscountAmount: InvoiceAmount; itemDiscountAmount: Maybe<InvoiceAmount>;
globalDiscountPercentage: Maybe<ItemDiscount>; globalDiscountPercentage: Maybe<ItemDiscountPercentage>;
globalDiscountAmount: InvoiceAmount; globalDiscountAmount: Maybe<InvoiceAmount>;
totalDiscountAmount: InvoiceAmount; totalDiscountAmount: Maybe<InvoiceAmount>;
taxableAmount: InvoiceAmount; taxableAmount: Maybe<InvoiceAmount>;
ivaAmount: InvoiceAmount; ivaCode: Maybe<string>;
recAmount: InvoiceAmount; ivaPercentage: Maybe<ItemDiscountPercentage>;
retentionAmount: InvoiceAmount; ivaAmount: Maybe<InvoiceAmount>;
taxesAmount: InvoiceAmount; recCode: Maybe<string>;
totalAmount: InvoiceAmount; recPercentage: Maybe<ItemDiscountPercentage>;
recAmount: Maybe<InvoiceAmount>;
taxes: ItemTaxGroup; retentionCode: Maybe<string>;
retentionPercentage: Maybe<ItemDiscountPercentage>;
retentionAmount: Maybe<InvoiceAmount>;
taxesAmount: Maybe<InvoiceAmount>;
totalAmount: Maybe<InvoiceAmount>;
languageCode: LanguageCode; languageCode: LanguageCode;
currencyCode: CurrencyCode; currencyCode: CurrencyCode;
@ -107,10 +118,6 @@ export class IssuedInvoiceItem extends DomainEntity<IssuedInvoiceItemProps> {
return this.props.globalDiscountAmount; return this.props.globalDiscountAmount;
} }
get taxes() {
return this.props.taxes;
}
get languageCode() { get languageCode() {
return this.props.languageCode; return this.props.languageCode;
} }
@ -119,35 +126,53 @@ export class IssuedInvoiceItem extends DomainEntity<IssuedInvoiceItemProps> {
return this.props.currencyCode; return this.props.currencyCode;
} }
public get subtotalAmount(): ItemAmount { public get subtotalAmount() {
return this.props.subtotalAmount; return this.props.subtotalAmount;
} }
public get totalDiscountAmount(): ItemAmount { public get totalDiscountAmount() {
return this.props.totalDiscountAmount; return this.props.totalDiscountAmount;
} }
public get taxableAmount(): ItemAmount { public get taxableAmount() {
return this.props.taxableAmount; return this.props.taxableAmount;
} }
public get ivaAmount(): InvoiceAmount { public get ivaCode(): Maybe<string> {
return this.props.ivaCode;
}
public get ivaPercentage(): Maybe<Percentage> {
return this.props.ivaPercentage;
}
public get ivaAmount(): Maybe<InvoiceAmount> {
return this.props.ivaAmount; return this.props.ivaAmount;
} }
public get recAmount(): InvoiceAmount { public get recCode(): Maybe<string> {
return this.props.recCode;
}
public get recPercentage(): Maybe<Percentage> {
return this.props.recPercentage;
}
public get recAmount(): Maybe<InvoiceAmount> {
return this.props.recAmount; return this.props.recAmount;
} }
public get retentionAmount(): InvoiceAmount { public get retentionCode(): Maybe<string> {
return this.props.retentionCode;
}
public get retentionPercentage(): Maybe<Percentage> {
return this.props.retentionPercentage;
}
public get retentionAmount(): Maybe<InvoiceAmount> {
return this.props.retentionAmount; return this.props.retentionAmount;
} }
public get taxesAmount(): ItemAmount { public get taxesAmount() {
return this.props.taxesAmount; return this.props.taxesAmount;
} }
public get totalAmount(): ItemAmount { public get totalAmount() {
return this.props.totalAmount; return this.props.totalAmount;
} }

View File

@ -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, ItemDiscount } from "../../../common"; import { InvoiceAmount, ItemDiscountPercentage } from "../../../common";
import type { IssuedInvoiceItem } from "./issued-invoice-item.entity"; import type { IssuedInvoiceItem } from "./issued-invoice-item.entity";
@ -47,7 +47,7 @@ export class IssuedInvoiceItems extends Collection<IssuedInvoiceItem> {
this._globalDiscountPercentage.equals( this._globalDiscountPercentage.equals(
item.globalDiscountPercentage.match( item.globalDiscountPercentage.match(
(v) => v, (v) => v,
() => ItemDiscount.zero() () => ItemDiscountPercentage.zero()
) )
) )
) )

View File

@ -12,11 +12,11 @@ export type IssuedInvoiceTaxProps = {
recCode: Maybe<string>; recCode: Maybe<string>;
recPercentage: Maybe<Percentage>; recPercentage: Maybe<Percentage>;
recAmount: InvoiceAmount; recAmount: Maybe<InvoiceAmount>;
retentionCode: Maybe<string>; retentionCode: Maybe<string>;
retentionPercentage: Maybe<Percentage>; retentionPercentage: Maybe<Percentage>;
retentionAmount: InvoiceAmount; retentionAmount: Maybe<InvoiceAmount>;
taxesAmount: InvoiceAmount; taxesAmount: InvoiceAmount;
}; };
@ -49,7 +49,7 @@ export class IssuedInvoiceTax extends DomainEntity<IssuedInvoiceTaxProps> {
public get recPercentage(): Maybe<Percentage> { public get recPercentage(): Maybe<Percentage> {
return this.props.recPercentage; return this.props.recPercentage;
} }
public get recAmount(): InvoiceAmount { public get recAmount(): Maybe<InvoiceAmount> {
return this.props.recAmount; return this.props.recAmount;
} }
@ -59,7 +59,7 @@ export class IssuedInvoiceTax extends DomainEntity<IssuedInvoiceTaxProps> {
public get retentionPercentage(): Maybe<Percentage> { public get retentionPercentage(): Maybe<Percentage> {
return this.props.retentionPercentage; return this.props.retentionPercentage;
} }
public get retentionAmount(): InvoiceAmount { public get retentionAmount(): Maybe<InvoiceAmount> {
return this.props.retentionAmount; return this.props.retentionAmount;
} }

View File

@ -1,4 +1,4 @@
import { DomainEntity, type URLAddress, type UniqueID, toEmptyString } from "@repo/rdx-ddd"; import { DomainEntity, type URLAddress, type UniqueID, maybeToEmptyString } from "@repo/rdx-ddd";
import { type Maybe, Result } from "@repo/rdx-utils"; import { type Maybe, Result } from "@repo/rdx-utils";
import type { VerifactuRecordEstado } from "../value-objects/verifactu-status.vo"; import type { VerifactuRecordEstado } from "../value-objects/verifactu-status.vo";
@ -53,10 +53,10 @@ export class VerifactuRecord extends DomainEntity<VerifactuRecordProps> {
toObjectString() { toObjectString() {
return { return {
status: this.estado.toString(), status: this.estado.toString(),
url: toEmptyString(this.url, (value) => value.toString()), url: maybeToEmptyString(this.url, (value) => value.toString()),
qr_code: toEmptyString(this.qrCode, (value) => value.toString()), qr_code: maybeToEmptyString(this.qrCode, (value) => value.toString()),
uuid: toEmptyString(this.uuid, (value) => value.toString()), uuid: maybeToEmptyString(this.uuid, (value) => value.toString()),
operacion: toEmptyString(this.operacion, (value) => value.toString()), operacion: maybeToEmptyString(this.operacion, (value) => value.toString()),
}; };
} }
} }

View File

@ -1,4 +1,3 @@
export * from "./aggregates"; export * from "./aggregates";
export * from "./entities"; export * from "./entities";
export * from "./errors";
export * from "./value-objects"; export * from "./value-objects";

View File

@ -1 +1,2 @@
export * from "./issued-invoice-tax-group.vo";
export * from "./verifactu-status.vo"; export * from "./verifactu-status.vo";

View File

@ -1,117 +0,0 @@
import { type Percentage, ValueObject } from "@repo/rdx-ddd";
import { type Maybe, Result } from "@repo/rdx-utils";
import type { InvoiceAmount } from "../../common";
export type IssuedInvoiceTaxGroupProps = {
ivaCode: string;
ivaPercentage: Percentage;
ivaAmount: InvoiceAmount;
recCode: Maybe<string>;
recPercentage: Maybe<Percentage>;
recAmount: InvoiceAmount;
retentionCode: Maybe<string>;
retentionPercentage: Maybe<Percentage>;
retentionAmount: InvoiceAmount;
taxableAmount: InvoiceAmount;
totalAmount: InvoiceAmount;
};
export class IssuedInvoiceTaxGroup extends ValueObject<IssuedInvoiceTaxGroupProps> {
static create(props: IssuedInvoiceTaxGroupProps) {
return Result.ok(new IssuedInvoiceTaxGroup(props));
}
// IVA
get ivaCode(): string {
return this.props.ivaCode;
}
get ivaPercentage(): Percentage {
return this.props.ivaPercentage;
}
get ivaAmount(): InvoiceAmount {
return this.props.ivaAmount;
}
// Recargo de equivalencia (rec)
get recCode(): Maybe<string> {
return this.props.recCode;
}
get recPercentage(): Maybe<Percentage> {
return this.props.recPercentage;
}
get recAmount(): Maybe<InvoiceAmount> {
return this.props.recAmount;
}
// Retención (ret)
get retentionCode(): Maybe<string> {
return this.props.retentionCode;
}
get retentionPercentage(): Maybe<Percentage> {
return this.props.retentionPercentage;
}
get retentionAmount(): Maybe<InvoiceAmount> {
return this.props.retentionAmount;
}
//
get taxableAmount(): InvoiceAmount {
return this.props.taxableAmount;
}
get totalAmount(): InvoiceAmount {
return this.props.totalAmount;
}
/**
* Devuelve únicamente los códigos existentes: ["iva_21", "rec_5_2"]
*/
public getCodesArray(): string[] {
const codes: string[] = [];
// IVA
codes.push(this.props.ivaCode);
this.props.rec.match(
(t) => codes.push(t.code),
() => {
//
}
);
this.props.retention.match(
(t) => codes.push(t.code),
() => {
//
}
);
return codes;
}
/**
* Devuelve una cadena tipo: "iva_21, rec_5_2"
*/
public getCodesToString(): string {
return this.getCodesArray().join(", ");
}
getProps() {
return this.props;
}
toPrimitive() {
return this.getProps();
}
}

View File

@ -0,0 +1,66 @@
import type { Tax } from "@erp/core/api";
import { ValueObject } from "@repo/rdx-ddd";
import { type Maybe, Result } from "@repo/rdx-utils";
import type { InvoiceAmount } from "../../common";
export type IssuedInvoiceTaxGroupProps = {
taxableAmount: InvoiceAmount;
iva: Tax;
ivaAmount: InvoiceAmount;
rec: Maybe<Tax>; // si existe
recAmount: Maybe<InvoiceAmount>;
retention: Maybe<Tax>; // si existe
retentionAmount: Maybe<InvoiceAmount>;
taxesAmount: InvoiceAmount;
};
export class IssuedInvoiceTaxGroup extends ValueObject<IssuedInvoiceTaxGroupProps> {
static create(props: IssuedInvoiceTaxGroupProps) {
return Result.ok(new IssuedInvoiceTaxGroup(props));
}
get taxableAmount(): InvoiceAmount {
return this.props.taxableAmount;
}
get iva(): Tax {
return this.props.iva;
}
get ivaAmount(): InvoiceAmount {
return this.props.ivaAmount;
}
get rec(): Maybe<Tax> {
return this.props.rec;
}
get recAmount(): Maybe<InvoiceAmount> {
return this.props.recAmount;
}
get retention(): Maybe<Tax> {
return this.props.retention;
}
get retentionAmount(): Maybe<InvoiceAmount> {
return this.props.retentionAmount;
}
get taxesAmount(): InvoiceAmount {
return this.props.taxesAmount;
}
getProps() {
return this.props;
}
toPrimitive() {
return this.getProps();
}
}

View File

@ -4,7 +4,7 @@ import { type Maybe, Result } from "@repo/rdx-utils";
import { import {
ItemAmount, ItemAmount,
type ItemDescription, type ItemDescription,
ItemDiscount, ItemDiscountPercentage,
ItemQuantity, ItemQuantity,
type ItemTaxGroup, type ItemTaxGroup,
} from "../../../common"; } from "../../../common";
@ -31,8 +31,8 @@ export type ProformaItemProps = {
quantity: Maybe<ItemQuantity>; // Cantidad de unidades quantity: Maybe<ItemQuantity>; // Cantidad de unidades
unitAmount: Maybe<ItemAmount>; // Precio unitario en la moneda de la factura unitAmount: Maybe<ItemAmount>; // Precio unitario en la moneda de la factura
itemDiscountPercentage: Maybe<ItemDiscount>; // % descuento itemDiscountPercentage: Maybe<ItemDiscountPercentage>; // % descuento
globalDiscountPercentage: Maybe<ItemDiscount>; // % descuento de la cabecera globalDiscountPercentage: Maybe<ItemDiscountPercentage>; // % descuento de la cabecera
taxes: ItemTaxGroup; taxes: ItemTaxGroup;
@ -128,7 +128,7 @@ export class ProformaItem extends DomainEntity<ProformaItemProps> {
private _calculateItemDiscountAmount(subtotal: ItemAmount): ItemAmount { private _calculateItemDiscountAmount(subtotal: ItemAmount): ItemAmount {
const discountPercentage = this.props.itemDiscountPercentage.match( const discountPercentage = this.props.itemDiscountPercentage.match(
(discount) => discount, (discount) => discount,
() => ItemDiscount.zero() () => ItemDiscountPercentage.zero()
); );
return subtotal.percentage(discountPercentage); return subtotal.percentage(discountPercentage);
@ -145,7 +145,7 @@ export class ProformaItem extends DomainEntity<ProformaItemProps> {
const globalDiscount = this.props.globalDiscountPercentage.match( const globalDiscount = this.props.globalDiscountPercentage.match(
(discount) => discount, (discount) => discount,
() => ItemDiscount.zero() () => ItemDiscountPercentage.zero()
); );
return amountAfterLineDiscount.percentage(globalDiscount); return amountAfterLineDiscount.percentage(globalDiscount);

View File

@ -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 { ItemAmount, ItemDiscount, type ItemTaxGroup } from "../../../common"; import { ItemAmount, ItemDiscountPercentage, type ItemTaxGroup } from "../../../common";
import type { ProformaItem } from "./proforma-item.entity"; import type { ProformaItem } from "./proforma-item.entity";
@ -76,7 +76,7 @@ export class ProformaItems extends Collection<ProformaItem> {
this.globalDiscountPercentage.equals( this.globalDiscountPercentage.equals(
item.globalDiscountPercentage.match( item.globalDiscountPercentage.match(
(v) => v, (v) => v,
() => ItemDiscount.zero() () => ItemDiscountPercentage.zero()
) )
); );

View File

@ -10,8 +10,8 @@ import {
ValidationErrorCollection, ValidationErrorCollection,
type ValidationErrorDetail, type ValidationErrorDetail,
extractOrPushError, extractOrPushError,
maybeFromNullableVO, maybeFromNullableResult,
toNullable, maybeToNullable,
} from "@repo/rdx-ddd"; } from "@repo/rdx-ddd";
import { Result } from "@repo/rdx-utils"; import { Result } from "@repo/rdx-utils";
@ -21,7 +21,7 @@ import {
type IssuedInvoiceItemProps, type IssuedInvoiceItemProps,
ItemAmount, ItemAmount,
ItemDescription, ItemDescription,
ItemDiscount, ItemDiscountPercentage,
ItemQuantity, ItemQuantity,
ItemTaxGroup, ItemTaxGroup,
type Proforma, type Proforma,
@ -78,19 +78,19 @@ export class CustomerInvoiceItemDomainMapper
); );
const description = extractOrPushError( const description = extractOrPushError(
maybeFromNullableVO(source.description, (v) => ItemDescription.create(v)), maybeFromNullableResult(source.description, (v) => ItemDescription.create(v)),
`items[${index}].description`, `items[${index}].description`,
errors errors
); );
const quantity = extractOrPushError( const quantity = extractOrPushError(
maybeFromNullableVO(source.quantity_value, (v) => ItemQuantity.create({ value: v })), maybeFromNullableResult(source.quantity_value, (v) => ItemQuantity.create({ value: v })),
`items[${index}].quantity`, `items[${index}].quantity`,
errors errors
); );
const unitAmount = extractOrPushError( const unitAmount = extractOrPushError(
maybeFromNullableVO(source.unit_amount_value, (value) => maybeFromNullableResult(source.unit_amount_value, (value) =>
ItemAmount.create({ value, currency_code: attributes.currencyCode?.code }) ItemAmount.create({ value, currency_code: attributes.currencyCode?.code })
), ),
`items[${index}].unit_amount`, `items[${index}].unit_amount`,
@ -98,35 +98,39 @@ export class CustomerInvoiceItemDomainMapper
); );
const discountPercentage = extractOrPushError( const discountPercentage = extractOrPushError(
maybeFromNullableVO(source.discount_percentage_value, (v) => maybeFromNullableResult(source.discount_percentage_value, (v) =>
ItemDiscount.create({ value: v }) ItemDiscountPercentage.create({ value: v })
), ),
`items[${index}].discount_percentage`, `items[${index}].discount_percentage`,
errors errors
); );
const globalDiscountPercentage = extractOrPushError( const globalDiscountPercentage = extractOrPushError(
maybeFromNullableVO(source.global_discount_percentage_value, (v) => maybeFromNullableResult(source.global_discount_percentage_value, (v) =>
ItemDiscount.create({ value: v }) ItemDiscountPercentage.create({ value: v })
), ),
`items[${index}].discount_percentage`, `items[${index}].discount_percentage`,
errors errors
); );
const iva = extractOrPushError( const iva = extractOrPushError(
maybeFromNullableVO(source.iva_code, (code) => Tax.createFromCode(code, this._taxCatalog)), maybeFromNullableResult(source.iva_code, (code) =>
Tax.createFromCode(code, this._taxCatalog)
),
`items[${index}].iva_code`, `items[${index}].iva_code`,
errors errors
); );
const rec = extractOrPushError( const rec = extractOrPushError(
maybeFromNullableVO(source.rec_code, (code) => Tax.createFromCode(code, this._taxCatalog)), maybeFromNullableResult(source.rec_code, (code) =>
Tax.createFromCode(code, this._taxCatalog)
),
`items[${index}].rec_code`, `items[${index}].rec_code`,
errors errors
); );
const retention = extractOrPushError( const retention = extractOrPushError(
maybeFromNullableVO(source.retention_code, (code) => maybeFromNullableResult(source.retention_code, (code) =>
Tax.createFromCode(code, this._taxCatalog) Tax.createFromCode(code, this._taxCatalog)
), ),
`items[${index}].retention_code`, `items[${index}].retention_code`,
@ -216,40 +220,42 @@ export class CustomerInvoiceItemDomainMapper
invoice_id: parent.id.toPrimitive(), invoice_id: parent.id.toPrimitive(),
position: index, position: index,
description: toNullable(source.description, (v) => v.toPrimitive()), description: maybeToNullable(source.description, (v) => v.toPrimitive()),
quantity_value: toNullable(source.quantity, (v) => v.toPrimitive().value), quantity_value: maybeToNullable(source.quantity, (v) => v.toPrimitive().value),
quantity_scale: quantity_scale:
toNullable(source.quantity, (v) => v.toPrimitive().scale) ?? ItemQuantity.DEFAULT_SCALE, maybeToNullable(source.quantity, (v) => v.toPrimitive().scale) ??
ItemQuantity.DEFAULT_SCALE,
unit_amount_value: toNullable(source.unitAmount, (v) => v.toPrimitive().value), unit_amount_value: maybeToNullable(source.unitAmount, (v) => v.toPrimitive().value),
unit_amount_scale: unit_amount_scale:
toNullable(source.unitAmount, (v) => v.toPrimitive().scale) ?? ItemAmount.DEFAULT_SCALE, maybeToNullable(source.unitAmount, (v) => v.toPrimitive().scale) ??
ItemAmount.DEFAULT_SCALE,
subtotal_amount_value: allAmounts.subtotalAmount.value, subtotal_amount_value: allAmounts.subtotalAmount.value,
subtotal_amount_scale: allAmounts.subtotalAmount.scale, subtotal_amount_scale: allAmounts.subtotalAmount.scale,
// //
discount_percentage_value: toNullable( discount_percentage_value: maybeToNullable(
source.itemDiscountPercentage, source.itemDiscountPercentage,
(v) => v.toPrimitive().value (v) => v.toPrimitive().value
), ),
discount_percentage_scale: discount_percentage_scale:
toNullable(source.itemDiscountPercentage, (v) => v.toPrimitive().scale) ?? maybeToNullable(source.itemDiscountPercentage, (v) => v.toPrimitive().scale) ??
ItemDiscount.DEFAULT_SCALE, ItemDiscountPercentage.DEFAULT_SCALE,
discount_amount_value: allAmounts.itemDiscountAmount.value, discount_amount_value: allAmounts.itemDiscountAmount.value,
discount_amount_scale: allAmounts.itemDiscountAmount.scale, discount_amount_scale: allAmounts.itemDiscountAmount.scale,
// //
global_discount_percentage_value: toNullable( 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:
toNullable(source.globalDiscountPercentage, (v) => v.toPrimitive().scale) ?? maybeToNullable(source.globalDiscountPercentage, (v) => v.toPrimitive().scale) ??
ItemDiscount.DEFAULT_SCALE, ItemDiscountPercentage.DEFAULT_SCALE,
global_discount_amount_value: allAmounts.globalDiscountAmount.value, global_discount_amount_value: allAmounts.globalDiscountAmount.value,
global_discount_amount_scale: allAmounts.globalDiscountAmount.scale, global_discount_amount_scale: allAmounts.globalDiscountAmount.scale,
@ -263,29 +269,32 @@ export class CustomerInvoiceItemDomainMapper
taxable_amount_scale: allAmounts.taxableAmount.scale, taxable_amount_scale: allAmounts.taxableAmount.scale,
// IVA // IVA
iva_code: toNullable(source.taxes.iva, (v) => v.code), iva_code: maybeToNullable(source.taxes.iva, (v) => v.code),
iva_percentage_value: toNullable(source.taxes.iva, (v) => v.percentage.value), iva_percentage_value: maybeToNullable(source.taxes.iva, (v) => v.percentage.value),
iva_percentage_scale: toNullable(source.taxes.iva, (v) => v.percentage.scale) ?? 2, iva_percentage_scale: maybeToNullable(source.taxes.iva, (v) => v.percentage.scale) ?? 2,
iva_amount_value: taxesAmounts.ivaAmount.value, iva_amount_value: taxesAmounts.ivaAmount.value,
iva_amount_scale: taxesAmounts.ivaAmount.scale, iva_amount_scale: taxesAmounts.ivaAmount.scale,
// REC // REC
rec_code: toNullable(source.taxes.rec, (v) => v.code), rec_code: maybeToNullable(source.taxes.rec, (v) => v.code),
rec_percentage_value: toNullable(source.taxes.rec, (v) => v.percentage.value), rec_percentage_value: maybeToNullable(source.taxes.rec, (v) => v.percentage.value),
rec_percentage_scale: toNullable(source.taxes.rec, (v) => v.percentage.scale) ?? 2, rec_percentage_scale: maybeToNullable(source.taxes.rec, (v) => v.percentage.scale) ?? 2,
rec_amount_value: taxesAmounts.recAmount.value, rec_amount_value: taxesAmounts.recAmount.value,
rec_amount_scale: taxesAmounts.recAmount.scale, rec_amount_scale: taxesAmounts.recAmount.scale,
// RET // RET
retention_code: toNullable(source.taxes.retention, (v) => v.code), retention_code: maybeToNullable(source.taxes.retention, (v) => v.code),
retention_percentage_value: toNullable(source.taxes.retention, (v) => v.percentage.value), retention_percentage_value: maybeToNullable(
source.taxes.retention,
(v) => v.percentage.value
),
retention_percentage_scale: retention_percentage_scale:
toNullable(source.taxes.retention, (v) => v.percentage.scale) ?? 2, maybeToNullable(source.taxes.retention, (v) => v.percentage.scale) ?? 2,
retention_amount_value: taxesAmounts.retentionAmount.value, retention_amount_value: taxesAmounts.retentionAmount.value,
retention_amount_scale: taxesAmounts.retentionAmount.scale, retention_amount_scale: taxesAmounts.retentionAmount.scale,

View File

@ -1,6 +1,6 @@
import type { JsonTaxCatalogProvider } from "@erp/core"; import type { JsonTaxCatalogProvider } from "@erp/core";
import { type MapperParamsType, SequelizeDomainMapper } from "@erp/core/api"; import { type MapperParamsType, SequelizeDomainMapper } from "@erp/core/api";
import { UniqueID, type ValidationErrorDetail, toNullable } from "@repo/rdx-ddd"; import { UniqueID, type ValidationErrorDetail, maybeToNullable } from "@repo/rdx-ddd";
import { Result } from "@repo/rdx-utils"; import { Result } from "@repo/rdx-utils";
import type { InvoiceTaxGroup, Proforma } from "../../../../../../domain"; import type { InvoiceTaxGroup, Proforma } from "../../../../../../domain";
@ -120,19 +120,20 @@ export class CustomerInvoiceTaxesDomainMapper extends SequelizeDomainMapper<
iva_amount_scale: ivaAmount.scale, iva_amount_scale: ivaAmount.scale,
// REC // REC
rec_code: toNullable(source.rec, (v) => v.code), rec_code: maybeToNullable(source.rec, (v) => v.code),
rec_percentage_value: toNullable(source.rec, (v) => v.percentage.value), rec_percentage_value: maybeToNullable(source.rec, (v) => v.percentage.value),
rec_percentage_scale: toNullable(source.rec, (v) => v.percentage.scale) ?? 2, rec_percentage_scale: maybeToNullable(source.rec, (v) => v.percentage.scale) ?? 2,
rec_amount_value: recAmount.value, rec_amount_value: recAmount.value,
rec_amount_scale: recAmount.scale, rec_amount_scale: recAmount.scale,
// RET // RET
retention_code: toNullable(source.retention, (v) => v.code), retention_code: maybeToNullable(source.retention, (v) => v.code),
retention_percentage_value: toNullable(source.retention, (v) => v.percentage.value), retention_percentage_value: maybeToNullable(source.retention, (v) => v.percentage.value),
retention_percentage_scale: toNullable(source.retention, (v) => v.percentage.scale) ?? 2, retention_percentage_scale:
maybeToNullable(source.retention, (v) => v.percentage.scale) ?? 2,
retention_amount_value: retentionAmount.value, retention_amount_value: retentionAmount.value,
retention_amount_scale: retentionAmount.scale, retention_amount_scale: retentionAmount.scale,

View File

@ -13,8 +13,8 @@ import {
ValidationErrorCollection, ValidationErrorCollection,
type ValidationErrorDetail, type ValidationErrorDetail,
extractOrPushError, extractOrPushError,
maybeFromNullableVO, maybeFromNullableResult,
toNullable, maybeToNullable,
} from "@repo/rdx-ddd"; } from "@repo/rdx-ddd";
import { Maybe, Result, isNullishOrEmpty } from "@repo/rdx-utils"; import { Maybe, Result, isNullishOrEmpty } from "@repo/rdx-utils";
@ -79,7 +79,7 @@ export class CustomerInvoiceDomainMapper
const isProforma = Boolean(source.is_proforma); const isProforma = Boolean(source.is_proforma);
const proformaId = extractOrPushError( const proformaId = extractOrPushError(
maybeFromNullableVO(source.proforma_id, (v) => UniqueID.create(v)), maybeFromNullableResult(source.proforma_id, (v) => UniqueID.create(v)),
"proforma_id", "proforma_id",
errors errors
); );
@ -87,7 +87,7 @@ export class CustomerInvoiceDomainMapper
const status = extractOrPushError(InvoiceStatus.create(source.status), "status", errors); const status = extractOrPushError(InvoiceStatus.create(source.status), "status", errors);
const series = extractOrPushError( const series = extractOrPushError(
maybeFromNullableVO(source.series, (v) => InvoiceSerie.create(v)), maybeFromNullableResult(source.series, (v) => InvoiceSerie.create(v)),
"series", "series",
errors errors
); );
@ -106,7 +106,7 @@ export class CustomerInvoiceDomainMapper
); );
const operationDate = extractOrPushError( const operationDate = extractOrPushError(
maybeFromNullableVO(source.operation_date, (v) => UtcDate.createFromISO(v)), maybeFromNullableResult(source.operation_date, (v) => UtcDate.createFromISO(v)),
"operation_date", "operation_date",
errors errors
); );
@ -126,19 +126,19 @@ export class CustomerInvoiceDomainMapper
// Textos opcionales // Textos opcionales
const reference = extractOrPushError( const reference = extractOrPushError(
maybeFromNullableVO(source.reference, (value) => Result.ok(String(value))), maybeFromNullableResult(source.reference, (value) => Result.ok(String(value))),
"reference", "reference",
errors errors
); );
const description = extractOrPushError( const description = extractOrPushError(
maybeFromNullableVO(source.description, (value) => Result.ok(String(value))), maybeFromNullableResult(source.description, (value) => Result.ok(String(value))),
"description", "description",
errors errors
); );
const notes = extractOrPushError( const notes = extractOrPushError(
maybeFromNullableVO(source.notes, (value) => TextValue.create(value)), maybeFromNullableResult(source.notes, (value) => TextValue.create(value)),
"notes", "notes",
errors errors
); );
@ -362,19 +362,19 @@ export class CustomerInvoiceDomainMapper
// Flags / estado / serie / número // Flags / estado / serie / número
is_proforma: source.isProforma, is_proforma: source.isProforma,
proforma_id: toNullable(source.proformaId, (v) => v.toPrimitive()), proforma_id: maybeToNullable(source.proformaId, (v) => v.toPrimitive()),
status: source.status.toPrimitive(), status: source.status.toPrimitive(),
series: toNullable(source.series, (v) => v.toPrimitive()), series: maybeToNullable(source.series, (v) => v.toPrimitive()),
invoice_number: source.invoiceNumber.toPrimitive(), invoice_number: source.invoiceNumber.toPrimitive(),
invoice_date: source.invoiceDate.toPrimitive(), invoice_date: source.invoiceDate.toPrimitive(),
operation_date: toNullable(source.operationDate, (v) => v.toPrimitive()), operation_date: maybeToNullable(source.operationDate, (v) => v.toPrimitive()),
language_code: source.languageCode.toPrimitive(), language_code: source.languageCode.toPrimitive(),
currency_code: source.currencyCode.toPrimitive(), currency_code: source.currencyCode.toPrimitive(),
reference: toNullable(source.reference, (reference) => reference), reference: maybeToNullable(source.reference, (reference) => reference),
description: toNullable(source.description, (description) => description), description: maybeToNullable(source.description, (description) => description),
notes: toNullable(source.notes, (v) => v.toPrimitive()), notes: maybeToNullable(source.notes, (v) => v.toPrimitive()),
subtotal_amount_value: allAmounts.subtotalAmount.value, subtotal_amount_value: allAmounts.subtotalAmount.value,
subtotal_amount_scale: allAmounts.subtotalAmount.scale, subtotal_amount_scale: allAmounts.subtotalAmount.scale,
@ -394,8 +394,11 @@ export class CustomerInvoiceDomainMapper
total_amount_value: allAmounts.totalAmount.value, total_amount_value: allAmounts.totalAmount.value,
total_amount_scale: allAmounts.totalAmount.scale, total_amount_scale: allAmounts.totalAmount.scale,
payment_method_id: toNullable(source.paymentMethod, (payment) => payment.toObjectString().id), payment_method_id: maybeToNullable(
payment_method_description: toNullable( source.paymentMethod,
(payment) => payment.toObjectString().id
),
payment_method_description: maybeToNullable(
source.paymentMethod, source.paymentMethod,
(payment) => payment.toObjectString().payment_description (payment) => payment.toObjectString().payment_description
), ),

View File

@ -10,8 +10,8 @@ import {
ValidationErrorCollection, ValidationErrorCollection,
type ValidationErrorDetail, type ValidationErrorDetail,
extractOrPushError, extractOrPushError,
maybeFromNullableVO, maybeFromNullableResult,
toNullable, maybeToNullable,
} from "@repo/rdx-ddd"; } from "@repo/rdx-ddd";
import { Maybe, Result } from "@repo/rdx-utils"; import { Maybe, Result } from "@repo/rdx-utils";
@ -59,37 +59,37 @@ export class InvoiceRecipientDomainMapper {
const customerTin = extractOrPushError(TINNumber.create(_tin!), "customer_tin", errors); const customerTin = extractOrPushError(TINNumber.create(_tin!), "customer_tin", errors);
const customerStreet = extractOrPushError( const customerStreet = extractOrPushError(
maybeFromNullableVO(_street, (value) => Street.create(value)), maybeFromNullableResult(_street, (value) => Street.create(value)),
"customer_street", "customer_street",
errors errors
); );
const customerStreet2 = extractOrPushError( const customerStreet2 = extractOrPushError(
maybeFromNullableVO(_street2, (value) => Street.create(value)), maybeFromNullableResult(_street2, (value) => Street.create(value)),
"customer_street2", "customer_street2",
errors errors
); );
const customerCity = extractOrPushError( const customerCity = extractOrPushError(
maybeFromNullableVO(_city, (value) => City.create(value)), maybeFromNullableResult(_city, (value) => City.create(value)),
"customer_city", "customer_city",
errors errors
); );
const customerProvince = extractOrPushError( const customerProvince = extractOrPushError(
maybeFromNullableVO(_province, (value) => Province.create(value)), maybeFromNullableResult(_province, (value) => Province.create(value)),
"customer_province", "customer_province",
errors errors
); );
const customerPostalCode = extractOrPushError( const customerPostalCode = extractOrPushError(
maybeFromNullableVO(_postal_code, (value) => PostalCode.create(value)), maybeFromNullableResult(_postal_code, (value) => PostalCode.create(value)),
"customer_postal_code", "customer_postal_code",
errors errors
); );
const customerCountry = extractOrPushError( const customerCountry = extractOrPushError(
maybeFromNullableVO(_country, (value) => Country.create(value)), maybeFromNullableResult(_country, (value) => Country.create(value)),
"customer_country", "customer_country",
errors errors
); );
@ -167,12 +167,12 @@ export class InvoiceRecipientDomainMapper {
return { return {
customer_tin: recipient.tin.toPrimitive(), customer_tin: recipient.tin.toPrimitive(),
customer_name: recipient.name.toPrimitive(), customer_name: recipient.name.toPrimitive(),
customer_street: toNullable(recipient.street, (v) => v.toPrimitive()), customer_street: maybeToNullable(recipient.street, (v) => v.toPrimitive()),
customer_street2: toNullable(recipient.street2, (v) => v.toPrimitive()), customer_street2: maybeToNullable(recipient.street2, (v) => v.toPrimitive()),
customer_city: toNullable(recipient.city, (v) => v.toPrimitive()), customer_city: maybeToNullable(recipient.city, (v) => v.toPrimitive()),
customer_province: toNullable(recipient.province, (v) => v.toPrimitive()), customer_province: maybeToNullable(recipient.province, (v) => v.toPrimitive()),
customer_postal_code: toNullable(recipient.postalCode, (v) => v.toPrimitive()), customer_postal_code: maybeToNullable(recipient.postalCode, (v) => v.toPrimitive()),
customer_country: toNullable(recipient.country, (v) => v.toPrimitive()), customer_country: maybeToNullable(recipient.country, (v) => v.toPrimitive()),
}; };
} }
} }

View File

@ -6,8 +6,8 @@ import {
ValidationErrorCollection, ValidationErrorCollection,
type ValidationErrorDetail, type ValidationErrorDetail,
extractOrPushError, extractOrPushError,
maybeFromNullableVO, maybeFromNullableResult,
toEmptyString, maybeToEmptyString,
} from "@repo/rdx-ddd"; } from "@repo/rdx-ddd";
import { Maybe, Result } from "@repo/rdx-utils"; import { Maybe, Result } from "@repo/rdx-utils";
@ -58,25 +58,25 @@ export class CustomerInvoiceVerifactuDomainMapper
); );
const qr = extractOrPushError( const qr = extractOrPushError(
maybeFromNullableVO(source.qr, (value) => Result.ok(String(value))), maybeFromNullableResult(source.qr, (value) => Result.ok(String(value))),
"qr", "qr",
errors errors
); );
const url = extractOrPushError( const url = extractOrPushError(
maybeFromNullableVO(source.url, (value) => URLAddress.create(value)), maybeFromNullableResult(source.url, (value) => URLAddress.create(value)),
"url", "url",
errors errors
); );
const uuid = extractOrPushError( const uuid = extractOrPushError(
maybeFromNullableVO(source.uuid, (value) => Result.ok(String(value))), maybeFromNullableResult(source.uuid, (value) => Result.ok(String(value))),
"uuid", "uuid",
errors errors
); );
const operacion = extractOrPushError( const operacion = extractOrPushError(
maybeFromNullableVO(source.operacion, (value) => Result.ok(String(value))), maybeFromNullableResult(source.operacion, (value) => Result.ok(String(value))),
"operacion", "operacion",
errors errors
); );
@ -136,10 +136,10 @@ export class CustomerInvoiceVerifactuDomainMapper
id: verifactu.id.toPrimitive(), id: verifactu.id.toPrimitive(),
invoice_id: parent.id.toPrimitive(), invoice_id: parent.id.toPrimitive(),
estado: verifactu.estado.toPrimitive(), estado: verifactu.estado.toPrimitive(),
qr: toEmptyString(verifactu.qrCode, (v) => v), qr: maybeToEmptyString(verifactu.qrCode, (v) => v),
url: toEmptyString(verifactu.url, (v) => v.toPrimitive()), url: maybeToEmptyString(verifactu.url, (v) => v.toPrimitive()),
uuid: toEmptyString(verifactu.uuid, (v) => v), uuid: maybeToEmptyString(verifactu.uuid, (v) => v),
operacion: toEmptyString(verifactu.operacion, (v) => v), operacion: maybeToEmptyString(verifactu.operacion, (v) => v),
}); });
} }
} }

View File

@ -12,7 +12,7 @@ import {
ValidationErrorCollection, ValidationErrorCollection,
type ValidationErrorDetail, type ValidationErrorDetail,
extractOrPushError, extractOrPushError,
maybeFromNullableVO, maybeFromNullableResult,
} from "@repo/rdx-ddd"; } from "@repo/rdx-ddd";
import { Maybe, Result } from "@repo/rdx-utils"; import { Maybe, Result } from "@repo/rdx-utils";
@ -167,7 +167,7 @@ export class CustomerInvoiceListMapper
const status = extractOrPushError(InvoiceStatus.create(raw.status), "status", errors); const status = extractOrPushError(InvoiceStatus.create(raw.status), "status", errors);
const series = extractOrPushError( const series = extractOrPushError(
maybeFromNullableVO(raw.series, (value) => InvoiceSerie.create(value)), maybeFromNullableResult(raw.series, (value) => InvoiceSerie.create(value)),
"serie", "serie",
errors errors
); );
@ -185,19 +185,19 @@ export class CustomerInvoiceListMapper
); );
const operationDate = extractOrPushError( const operationDate = extractOrPushError(
maybeFromNullableVO(raw.operation_date, (value) => UtcDate.createFromISO(value)), maybeFromNullableResult(raw.operation_date, (value) => UtcDate.createFromISO(value)),
"operation_date", "operation_date",
errors errors
); );
const reference = extractOrPushError( const reference = extractOrPushError(
maybeFromNullableVO(raw.reference, (value) => Result.ok(String(value))), maybeFromNullableResult(raw.reference, (value) => Result.ok(String(value))),
"description", "description",
errors errors
); );
const description = extractOrPushError( const description = extractOrPushError(
maybeFromNullableVO(raw.description, (value) => Result.ok(String(value))), maybeFromNullableResult(raw.description, (value) => Result.ok(String(value))),
"description", "description",
errors errors
); );

View File

@ -13,7 +13,7 @@ import {
TINNumber, TINNumber,
type ValidationErrorDetail, type ValidationErrorDetail,
extractOrPushError, extractOrPushError,
maybeFromNullableVO, maybeFromNullableResult,
} from "@repo/rdx-ddd"; } from "@repo/rdx-ddd";
import type { Result } from "@repo/rdx-utils"; import type { Result } from "@repo/rdx-utils";
@ -67,37 +67,37 @@ export class InvoiceRecipientListMapper
const customerTin = extractOrPushError(TINNumber.create(_tin), "customer_tin", errors); const customerTin = extractOrPushError(TINNumber.create(_tin), "customer_tin", errors);
const customerStreet = extractOrPushError( const customerStreet = extractOrPushError(
maybeFromNullableVO(_street, (value) => Street.create(value)), maybeFromNullableResult(_street, (value) => Street.create(value)),
"customer_street", "customer_street",
errors errors
); );
const customerStreet2 = extractOrPushError( const customerStreet2 = extractOrPushError(
maybeFromNullableVO(_street2, (value) => Street.create(value)), maybeFromNullableResult(_street2, (value) => Street.create(value)),
"customer_street2", "customer_street2",
errors errors
); );
const customerCity = extractOrPushError( const customerCity = extractOrPushError(
maybeFromNullableVO(_city, (value) => City.create(value)), maybeFromNullableResult(_city, (value) => City.create(value)),
"customer_city", "customer_city",
errors errors
); );
const customerProvince = extractOrPushError( const customerProvince = extractOrPushError(
maybeFromNullableVO(_province, (value) => Province.create(value)), maybeFromNullableResult(_province, (value) => Province.create(value)),
"customer_province", "customer_province",
errors errors
); );
const customerPostalCode = extractOrPushError( const customerPostalCode = extractOrPushError(
maybeFromNullableVO(_postal_code, (value) => PostalCode.create(value)), maybeFromNullableResult(_postal_code, (value) => PostalCode.create(value)),
"customer_postal_code", "customer_postal_code",
errors errors
); );
const customerCountry = extractOrPushError( const customerCountry = extractOrPushError(
maybeFromNullableVO(_country, (value) => Country.create(value)), maybeFromNullableResult(_country, (value) => Country.create(value)),
"customer_country", "customer_country",
errors errors
); );

View File

@ -9,7 +9,7 @@ import {
ValidationErrorCollection, ValidationErrorCollection,
type ValidationErrorDetail, type ValidationErrorDetail,
extractOrPushError, extractOrPushError,
maybeFromNullableVO, maybeFromNullableResult,
} from "@repo/rdx-ddd"; } from "@repo/rdx-ddd";
import { Result } from "@repo/rdx-utils"; import { Result } from "@repo/rdx-utils";
@ -35,25 +35,25 @@ export class VerifactuRecordListMapper
const estado = extractOrPushError(VerifactuRecordEstado.create(raw.estado), "estado", errors); const estado = extractOrPushError(VerifactuRecordEstado.create(raw.estado), "estado", errors);
const qr = extractOrPushError( const qr = extractOrPushError(
maybeFromNullableVO(raw.qr, (value) => Result.ok(String(value))), maybeFromNullableResult(raw.qr, (value) => Result.ok(String(value))),
"qr", "qr",
errors errors
); );
const url = extractOrPushError( const url = extractOrPushError(
maybeFromNullableVO(raw.url, (value) => URLAddress.create(value)), maybeFromNullableResult(raw.url, (value) => URLAddress.create(value)),
"url", "url",
errors errors
); );
const uuid = extractOrPushError( const uuid = extractOrPushError(
maybeFromNullableVO(raw.uuid, (value) => Result.ok(String(value))), maybeFromNullableResult(raw.uuid, (value) => Result.ok(String(value))),
"uuid", "uuid",
errors errors
); );
const operacion = extractOrPushError( const operacion = extractOrPushError(
maybeFromNullableVO(raw.operacion, (value) => Result.ok(String(value))), maybeFromNullableResult(raw.operacion, (value) => Result.ok(String(value))),
"operacion", "operacion",
errors errors
); );

View File

@ -23,20 +23,20 @@ export class CustomerInvoiceTaxModel extends Model<
declare invoice_id: string; declare invoice_id: string;
// Taxable amount (base imponible) // Taxable amount (base imponible)
declare taxable_amount_value: CreationOptional<number | null>; declare taxable_amount_value: number;
declare taxable_amount_scale: number; declare taxable_amount_scale: number;
// Código de impuestos // Código de impuestos
// IVA percentage // IVA percentage
declare iva_code: CreationOptional<string | null>; declare iva_code: string;
declare iva_percentage_value: CreationOptional<number | null>; declare iva_percentage_value: number;
declare iva_percentage_scale: number; declare iva_percentage_scale: number;
// IVA amount // IVA amount
declare iva_amount_value: CreationOptional<number | null>; declare iva_amount_value: number;
declare iva_amount_scale: number; declare iva_amount_scale: number;
// Recargo de equivalencia percentage // Recargo de equivalencia percentage
@ -60,7 +60,7 @@ export class CustomerInvoiceTaxModel extends Model<
declare retention_amount_scale: number; declare retention_amount_scale: number;
// Total taxes amount / taxes total // Total taxes amount / taxes total
declare taxes_amount_value: CreationOptional<number | null>; declare taxes_amount_value: number;
declare taxes_amount_scale: number; declare taxes_amount_scale: number;
// Relaciones // Relaciones
@ -108,8 +108,8 @@ export default (database: Sequelize) => {
taxable_amount_value: { taxable_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: true, allowNull: false,
defaultValue: null, defaultValue: 0,
}, },
taxable_amount_scale: { taxable_amount_scale: {
@ -207,8 +207,8 @@ export default (database: Sequelize) => {
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: true, allowNull: false,
defaultValue: null, defaultValue: 0,
}, },
taxes_amount_scale: { taxes_amount_scale: {

View File

@ -9,13 +9,14 @@ import {
ValidationErrorCollection, ValidationErrorCollection,
type ValidationErrorDetail, type ValidationErrorDetail,
extractOrPushError, extractOrPushError,
maybeFromNullableVO, maybeFromNullableResult,
toNullable, maybeToNullable,
} from "@repo/rdx-ddd"; } from "@repo/rdx-ddd";
import { Maybe, Result, isNullishOrEmpty } from "@repo/rdx-utils"; import { Maybe, Result, isNullishOrEmpty } from "@repo/rdx-utils";
import type { IIssuedInvoiceDomainMapper } from "../../../../../../application"; import type { IIssuedInvoiceDomainMapper } from "../../../../../../application";
import { import {
InvoiceAmount,
InvoiceNumber, InvoiceNumber,
InvoicePaymentMethod, InvoicePaymentMethod,
InvoiceSerie, InvoiceSerie,
@ -23,6 +24,7 @@ import {
IssuedInvoice, IssuedInvoice,
IssuedInvoiceItems, IssuedInvoiceItems,
type IssuedInvoiceProps, type IssuedInvoiceProps,
IssuedInvoiceTaxes,
} from "../../../../../../domain"; } from "../../../../../../domain";
import type { import type {
CustomerInvoiceCreationAttributes, CustomerInvoiceCreationAttributes,
@ -52,87 +54,83 @@ export class SequelizeIssuedInvoiceDomainMapper
this._itemsMapper = new SequelizeIssuedInvoiceItemDomainMapper(params); // Instanciar el mapper de items this._itemsMapper = new SequelizeIssuedInvoiceItemDomainMapper(params); // Instanciar el mapper de items
this._recipientMapper = new SequelizeIssuedInvoiceRecipientDomainMapper(); this._recipientMapper = new SequelizeIssuedInvoiceRecipientDomainMapper();
this._taxesMapper = new SequelizeIssuedInvoiceTaxesDomainMapper(); this._taxesMapper = new SequelizeIssuedInvoiceTaxesDomainMapper(params);
this._verifactuMapper = new SequelizeIssuedInvoiceVerifactuDomainMapper(); this._verifactuMapper = new SequelizeIssuedInvoiceVerifactuDomainMapper();
} }
private _mapAttributesToDomain(source: CustomerInvoiceModel, params?: MapperParamsType) { private _mapAttributesToDomain(raw: CustomerInvoiceModel, params?: MapperParamsType) {
const { errors } = params as { const { errors } = params as {
errors: ValidationErrorDetail[]; errors: ValidationErrorDetail[];
}; };
const invoiceId = extractOrPushError(UniqueID.create(source.id), "id", errors); const invoiceId = extractOrPushError(UniqueID.create(raw.id), "id", errors);
const companyId = extractOrPushError(UniqueID.create(source.company_id), "company_id", errors); const companyId = extractOrPushError(UniqueID.create(raw.company_id), "company_id", errors);
const customerId = extractOrPushError( const customerId = extractOrPushError(UniqueID.create(raw.customer_id), "customer_id", errors);
UniqueID.create(source.customer_id),
"customer_id",
errors
);
const isIssuedInvoice = Boolean(source.is_proforma); const isIssuedInvoice = Boolean(raw.is_proforma);
const proformaId = extractOrPushError( const proformaId = extractOrPushError(
maybeFromNullableVO(source.proforma_id, (v) => UniqueID.create(v)), maybeFromNullableResult(raw.proforma_id, (v) => UniqueID.create(v)),
"proforma_id", "proforma_id",
errors errors
); );
const status = extractOrPushError(InvoiceStatus.create(source.status), "status", errors); const status = extractOrPushError(InvoiceStatus.create(raw.status), "status", errors);
const series = extractOrPushError( const series = extractOrPushError(
maybeFromNullableVO(source.series, (v) => InvoiceSerie.create(v)), maybeFromNullableResult(raw.series, (v) => InvoiceSerie.create(v)),
"series", "series",
errors errors
); );
const invoiceNumber = extractOrPushError( const invoiceNumber = extractOrPushError(
InvoiceNumber.create(source.invoice_number), InvoiceNumber.create(raw.invoice_number),
"invoice_number", "invoice_number",
errors errors
); );
// Fechas // Fechas
const invoiceDate = extractOrPushError( const invoiceDate = extractOrPushError(
UtcDate.createFromISO(source.invoice_date), UtcDate.createFromISO(raw.invoice_date),
"invoice_date", "invoice_date",
errors errors
); );
const operationDate = extractOrPushError( const operationDate = extractOrPushError(
maybeFromNullableVO(source.operation_date, (v) => UtcDate.createFromISO(v)), maybeFromNullableResult(raw.operation_date, (v) => UtcDate.createFromISO(v)),
"operation_date", "operation_date",
errors errors
); );
// Idioma / divisa // Idioma / divisa
const languageCode = extractOrPushError( const languageCode = extractOrPushError(
LanguageCode.create(source.language_code), LanguageCode.create(raw.language_code),
"language_code", "language_code",
errors errors
); );
const currencyCode = extractOrPushError( const currencyCode = extractOrPushError(
CurrencyCode.create(source.currency_code), CurrencyCode.create(raw.currency_code),
"currency_code", "currency_code",
errors errors
); );
// Textos opcionales // Textos opcionales
const reference = extractOrPushError( const reference = extractOrPushError(
maybeFromNullableVO(source.reference, (value) => Result.ok(String(value))), maybeFromNullableResult(raw.reference, (value) => Result.ok(String(value))),
"reference", "reference",
errors errors
); );
const description = extractOrPushError( const description = extractOrPushError(
maybeFromNullableVO(source.description, (value) => Result.ok(String(value))), maybeFromNullableResult(raw.description, (value) => Result.ok(String(value))),
"description", "description",
errors errors
); );
const notes = extractOrPushError( const notes = extractOrPushError(
maybeFromNullableVO(source.notes, (value) => TextValue.create(value)), maybeFromNullableResult(raw.notes, (value) => TextValue.create(value)),
"notes", "notes",
errors errors
); );
@ -140,16 +138,16 @@ export class SequelizeIssuedInvoiceDomainMapper
// Método de pago (VO opcional con id + descripción) // Método de pago (VO opcional con id + descripción)
let paymentMethod = Maybe.none<InvoicePaymentMethod>(); let paymentMethod = Maybe.none<InvoicePaymentMethod>();
if (!isNullishOrEmpty(source.payment_method_id)) { if (!isNullishOrEmpty(raw.payment_method_id)) {
const paymentId = extractOrPushError( const paymentId = extractOrPushError(
UniqueID.create(String(source.payment_method_id)), UniqueID.create(String(raw.payment_method_id)),
"paymentMethod.id", "paymentMethod.id",
errors errors
); );
const paymentVO = extractOrPushError( const paymentVO = extractOrPushError(
InvoicePaymentMethod.create( InvoicePaymentMethod.create(
{ paymentDescription: String(source.payment_method_description ?? "") }, { paymentDescription: String(raw.payment_method_description ?? "") },
paymentId ?? undefined paymentId ?? undefined
), ),
"payment_method_description", "payment_method_description",
@ -161,13 +159,78 @@ export class SequelizeIssuedInvoiceDomainMapper
} }
} }
// % descuento (VO) const subtotalAmount = extractOrPushError(
const discountPercentage = extractOrPushError( InvoiceAmount.create({
Percentage.create({ value: raw.subtotal_amount_value,
value: Number(source.discount_percentage_value ?? 0), currency_code: currencyCode?.code,
scale: Number(source.discount_percentage_scale ?? 2),
}), }),
"discount_percentage_value", "subtotal_amount_value",
errors
);
// Total descuento de líneas
const itemsDiscountAmount = extractOrPushError(
InvoiceAmount.create({
value: Number(raw.items_discount_amount_value ?? 0),
currency_code: currencyCode?.code,
}),
"items_discount_amount_value",
errors
);
// % descuento global (VO)
const globalDiscountPercentage = extractOrPushError(
Percentage.create({
value: Number(raw.global_discount_percentage_value ?? 0),
scale: Number(raw.global_discount_percentage_scale ?? 2),
}),
"global_discount_percentage_value",
errors
);
const globalDiscountAmount = extractOrPushError(
InvoiceAmount.create({
value: Number(raw.global_discount_amount_value ?? 0),
currency_code: currencyCode?.code,
}),
"global_discount_amount_value",
errors
);
const totalDiscountAmount = extractOrPushError(
InvoiceAmount.create({
value: raw.total_discount_amount_value,
currency_code: currencyCode?.code,
}),
"total_discount_amount_value",
errors
);
const taxableAmount = extractOrPushError(
InvoiceAmount.create({
value: raw.taxable_amount_value,
currency_code: currencyCode?.code,
}),
"taxable_amount_value",
errors
);
const taxesAmount = extractOrPushError(
InvoiceAmount.create({
value: raw.taxes_amount_value,
currency_code: currencyCode?.code,
}),
"taxes_amount_value",
errors
);
const totalAmount = extractOrPushError(
InvoiceAmount.create({
value: raw.total_amount_value,
currency_code: currencyCode?.code,
}),
"total_amount_value",
errors errors
); );
@ -187,8 +250,16 @@ export class SequelizeIssuedInvoiceDomainMapper
notes, notes,
languageCode, languageCode,
currencyCode, currencyCode,
discountPercentage,
paymentMethod, paymentMethod,
subtotalAmount,
itemsDiscountAmount,
globalDiscountPercentage,
globalDiscountAmount,
totalDiscountAmount,
taxableAmount,
taxesAmount,
totalAmount,
}; };
} }
@ -227,7 +298,18 @@ export class SequelizeIssuedInvoiceDomainMapper
} }
); );
// 5) Si hubo errores de mapeo, devolvemos colección de validación // 5) Taxes (colección)
const taxesResults = this._taxesMapper.mapToDomainCollection(
source.taxes,
source.taxes.length,
{
errors,
attributes,
...params,
}
);
// 6) 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 invoice mapping failed [mapToDomain]", errors) new ValidationErrorCollection("Customer invoice mapping failed [mapToDomain]", errors)
@ -239,10 +321,17 @@ export class SequelizeIssuedInvoiceDomainMapper
const items = IssuedInvoiceItems.create({ const items = IssuedInvoiceItems.create({
languageCode: attributes.languageCode!, languageCode: attributes.languageCode!,
currencyCode: attributes.currencyCode!, currencyCode: attributes.currencyCode!,
globalDiscountPercentage: attributes.discountPercentage!, globalDiscountPercentage: attributes.globalDiscountPercentage!,
items: itemsResults.data.getAll(), items: itemsResults.data.getAll(),
}); });
const taxes = IssuedInvoiceTaxes.create({
languageCode: attributes.languageCode!,
currencyCode: attributes.currencyCode!,
globalDiscountPercentage: attributes.globalDiscountPercentage!,
taxes: taxesResults.data.getAll(),
});
const invoiceProps: IssuedInvoiceProps = { const invoiceProps: IssuedInvoiceProps = {
companyId: attributes.companyId!, companyId: attributes.companyId!,
@ -263,11 +352,21 @@ export class SequelizeIssuedInvoiceDomainMapper
languageCode: attributes.languageCode!, languageCode: attributes.languageCode!,
currencyCode: attributes.currencyCode!, currencyCode: attributes.currencyCode!,
globalDiscountPercentage: attributes.discountPercentage!, subtotalAmount: attributes.subtotalAmount!,
itemsDiscountAmount: attributes.itemsDiscountAmount!,
globalDiscountPercentage: attributes.globalDiscountPercentage!,
globalDiscountAmount: attributes.globalDiscountAmount!,
totalDiscountAmount: attributes.totalDiscountAmount!,
taxableAmount: attributes.taxableAmount!,
taxesAmount: attributes.taxesAmount!,
totalAmount: attributes.totalAmount!,
paymentMethod: attributes.paymentMethod!, paymentMethod: attributes.paymentMethod!,
items, items,
taxes: taxesResults.data,
verifactu: verifactuResult.data, verifactu: verifactuResult.data,
}; };
@ -354,22 +453,25 @@ export class SequelizeIssuedInvoiceDomainMapper
// Flags / estado / serie / número // Flags / estado / serie / número
is_proforma: false, is_proforma: false,
status: source.status.toPrimitive(), status: source.status.toPrimitive(),
proforma_id: toNullable(source.proformaId, (v) => v.toPrimitive()), proforma_id: maybeToNullable(source.proformaId, (v) => v.toPrimitive()),
series: toNullable(source.series, (v) => v.toPrimitive()), series: maybeToNullable(source.series, (v) => v.toPrimitive()),
invoice_number: source.invoiceNumber.toPrimitive(), invoice_number: source.invoiceNumber.toPrimitive(),
invoice_date: source.invoiceDate.toPrimitive(), invoice_date: source.invoiceDate.toPrimitive(),
operation_date: toNullable(source.operationDate, (v) => v.toPrimitive()), operation_date: maybeToNullable(source.operationDate, (v) => v.toPrimitive()),
language_code: source.languageCode.toPrimitive(), language_code: source.languageCode.toPrimitive(),
currency_code: source.currencyCode.toPrimitive(), currency_code: source.currencyCode.toPrimitive(),
reference: toNullable(source.reference, (reference) => reference), reference: maybeToNullable(source.reference, (reference) => reference),
description: toNullable(source.description, (description) => description), description: maybeToNullable(source.description, (description) => description),
notes: toNullable(source.notes, (v) => v.toPrimitive()), notes: maybeToNullable(source.notes, (v) => v.toPrimitive()),
payment_method_id: toNullable(source.paymentMethod, (payment) => payment.toObjectString().id), payment_method_id: maybeToNullable(
payment_method_description: toNullable( source.paymentMethod,
(payment) => payment.toObjectString().id
),
payment_method_description: maybeToNullable(
source.paymentMethod, source.paymentMethod,
(payment) => payment.toObjectString().payment_description (payment) => payment.toObjectString().payment_description
), ),

View File

@ -1,12 +1,14 @@
import type { JsonTaxCatalogProvider } from "@erp/core"; import type { JsonTaxCatalogProvider } from "@erp/core";
import { type MapperParamsType, SequelizeDomainMapper, Tax } from "@erp/core/api"; import { type MapperParamsType, SequelizeDomainMapper } from "@erp/core/api";
import { import {
UniqueID, UniqueID,
ValidationErrorCollection, ValidationErrorCollection,
type ValidationErrorDetail, type ValidationErrorDetail,
extractOrPushError, extractOrPushError,
maybeFromNullableVO, maybeFromNullableOrEmptyString,
toNullable, maybeFromNullableResult,
maybeToNullable,
maybeToNullableString,
} from "@repo/rdx-ddd"; } from "@repo/rdx-ddd";
import { Result } from "@repo/rdx-utils"; import { Result } from "@repo/rdx-utils";
@ -17,9 +19,9 @@ import {
type IssuedInvoiceProps, type IssuedInvoiceProps,
ItemAmount, ItemAmount,
ItemDescription, ItemDescription,
ItemDiscount, ItemDiscountPercentage,
ItemQuantity, ItemQuantity,
ItemTaxGroup, ItemTaxPercentage,
} from "../../../../../../domain"; } from "../../../../../../domain";
import type { import type {
CustomerInvoiceItemCreationAttributes, CustomerInvoiceItemCreationAttributes,
@ -31,7 +33,7 @@ export class SequelizeIssuedInvoiceItemDomainMapper extends SequelizeDomainMappe
CustomerInvoiceItemCreationAttributes, CustomerInvoiceItemCreationAttributes,
IssuedInvoiceItem IssuedInvoiceItem
> { > {
private _taxCatalog!: JsonTaxCatalogProvider; private taxCatalog!: JsonTaxCatalogProvider;
constructor(params: MapperParamsType) { constructor(params: MapperParamsType) {
super(); super();
@ -40,14 +42,14 @@ export class SequelizeIssuedInvoiceItemDomainMapper extends SequelizeDomainMappe
}; };
if (!taxCatalog) { if (!taxCatalog) {
throw new Error('taxCatalog not defined ("CustomerInvoiceItemDomainMapper")'); throw new Error('taxCatalog not defined ("SequelizeIssuedInvoiceItemDomainMapper")');
} }
this._taxCatalog = taxCatalog; this.taxCatalog = taxCatalog;
} }
private mapAttributesToDomain( private mapAttributesToDomain(
source: CustomerInvoiceItemModel, raw: CustomerInvoiceItemModel,
params?: MapperParamsType params?: MapperParamsType
): Partial<IssuedInvoiceItemProps> & { itemId?: UniqueID } { ): Partial<IssuedInvoiceItemProps> & { itemId?: UniqueID } {
const { errors, index, attributes } = params as { const { errors, index, attributes } = params as {
@ -57,83 +59,179 @@ export class SequelizeIssuedInvoiceItemDomainMapper extends SequelizeDomainMappe
}; };
const itemId = extractOrPushError( const itemId = extractOrPushError(
UniqueID.create(source.item_id), UniqueID.create(raw.item_id),
`items[${index}].item_id`, `items[${index}].item_id`,
errors errors
); );
const description = extractOrPushError( const description = extractOrPushError(
maybeFromNullableVO(source.description, (v) => ItemDescription.create(v)), maybeFromNullableResult(raw.description, (v) => ItemDescription.create(v)),
`items[${index}].description`, `items[${index}].description`,
errors errors
); );
const quantity = extractOrPushError( const quantity = extractOrPushError(
maybeFromNullableVO(source.quantity_value, (v) => ItemQuantity.create({ value: v })), maybeFromNullableResult(raw.quantity_value, (v) => ItemQuantity.create({ value: v })),
`items[${index}].quantity`, `items[${index}].quantity_value`,
errors errors
); );
const unitAmount = extractOrPushError( const unitAmount = extractOrPushError(
maybeFromNullableVO(source.unit_amount_value, (value) => maybeFromNullableResult(raw.unit_amount_value, (value) =>
ItemAmount.create({ value, currency_code: attributes.currencyCode?.code }) ItemAmount.create({ value, currency_code: attributes.currencyCode?.code })
), ),
`items[${index}].unit_amount`, `items[${index}].unit_amount_value`,
errors errors
); );
const discountPercentage = extractOrPushError( const subtotalAmount = extractOrPushError(
maybeFromNullableVO(source.discount_percentage_value, (v) => maybeFromNullableResult(raw.subtotal_amount_value, (value) =>
ItemDiscount.create({ value: v }) ItemAmount.create({ value, currency_code: attributes.currencyCode?.code })
), ),
`items[${index}].discount_percentage`, `items[${index}].subtotal_amount_value`,
errors
);
const itemDiscountPercentage = extractOrPushError(
maybeFromNullableResult(raw.discount_percentage_value, (v) =>
ItemDiscountPercentage.create({ value: v })
),
`items[${index}].discount_percentage_value`,
errors
);
const itemDiscountAmount = extractOrPushError(
maybeFromNullableResult(raw.discount_amount_value, (value) =>
ItemAmount.create({ value, currency_code: attributes.currencyCode?.code })
),
`items[${index}].discount_amount_value`,
errors errors
); );
const globalDiscountPercentage = extractOrPushError( const globalDiscountPercentage = extractOrPushError(
maybeFromNullableVO(source.global_discount_percentage_value, (v) => maybeFromNullableResult(raw.global_discount_percentage_value, (v) =>
ItemDiscount.create({ value: v }) ItemDiscountPercentage.create({ value: v })
), ),
`items[${index}].discount_percentage`, `items[${index}].global_discount_percentage_value`,
errors errors
); );
const iva = extractOrPushError( const globalDiscountAmount = extractOrPushError(
maybeFromNullableVO(source.iva_code, (code) => Tax.createFromCode(code, this._taxCatalog)), maybeFromNullableResult(raw.global_discount_amount_value, (value) =>
`items[${index}].iva_code`, ItemAmount.create({ value, currency_code: attributes.currencyCode?.code })
errors
);
const rec = extractOrPushError(
maybeFromNullableVO(source.rec_code, (code) => Tax.createFromCode(code, this._taxCatalog)),
`items[${index}].rec_code`,
errors
);
const retention = extractOrPushError(
maybeFromNullableVO(source.retention_code, (code) =>
Tax.createFromCode(code, this._taxCatalog)
), ),
`items[${index}].retention_code`, `items[${index}].global_discount_amount_value`,
errors
);
const totalDiscountAmount = extractOrPushError(
maybeFromNullableResult(raw.total_discount_amount_value, (value) =>
ItemAmount.create({ value, currency_code: attributes.currencyCode?.code })
),
`items[${index}].total_discount_amount_value`,
errors
);
const ivaCode = maybeFromNullableOrEmptyString(raw.iva_code);
const ivaPercentage = extractOrPushError(
maybeFromNullableResult(raw.iva_percentage_value, (value) =>
ItemTaxPercentage.create({ value })
),
`items[${index}].iva_percentage_value`,
errors
);
const ivaAmount = extractOrPushError(
maybeFromNullableResult(raw.iva_amount_value, (value) =>
ItemAmount.create({ value, currency_code: attributes.currencyCode?.code })
),
`items[${index}].iva_amount_value`,
errors
);
const recCode = maybeFromNullableOrEmptyString(raw.rec_code);
const recPercentage = extractOrPushError(
maybeFromNullableResult(raw.rec_percentage_value, (value) =>
ItemTaxPercentage.create({ value })
),
`items[${index}].rec_percentage_value`,
errors
);
const recAmount = extractOrPushError(
maybeFromNullableResult(raw.rec_amount_value, (value) =>
ItemAmount.create({ value, currency_code: attributes.currencyCode?.code })
),
`items[${index}].rec_amount_value`,
errors
);
const retentionCode = maybeFromNullableOrEmptyString(raw.retention_code);
const retentionPercentage = extractOrPushError(
maybeFromNullableResult(raw.retention_percentage_value, (value) =>
ItemTaxPercentage.create({ value })
),
`items[${index}].retention_percentage_value`,
errors
);
const retentionAmount = extractOrPushError(
maybeFromNullableResult(raw.retention_amount_value, (value) =>
ItemAmount.create({ value, currency_code: attributes.currencyCode?.code })
),
`items[${index}].retention_amount_value`,
errors
);
const taxesAmount = extractOrPushError(
maybeFromNullableResult(raw.taxes_amount_value, (value) =>
ItemAmount.create({ value, currency_code: attributes.currencyCode?.code })
),
`items[${index}].taxes_amount_value`,
errors
);
const totalAmount = extractOrPushError(
maybeFromNullableResult(raw.total_amount_value, (value) =>
ItemAmount.create({ value, currency_code: attributes.currencyCode?.code })
),
`items[${index}].total_amount_value`,
errors errors
); );
return { return {
itemId, itemId,
languageCode: attributes.languageCode, languageCode: attributes.languageCode,
currencyCode: attributes.currencyCode, currencyCode: attributes.currencyCode,
description, description,
quantity, quantity,
unitAmount, unitAmount,
itemDiscountPercentage: discountPercentage, subtotalAmount,
globalDiscountPercentage,
taxes: ItemTaxGroup.create({ itemDiscountPercentage,
iva: iva!, itemDiscountAmount,
rec: rec!, globalDiscountPercentage,
retention: retention!, globalDiscountAmount,
}).data, totalDiscountAmount,
ivaCode,
ivaPercentage,
ivaAmount,
recCode,
recPercentage,
recAmount,
retentionCode,
retentionPercentage,
retentionAmount,
taxesAmount,
totalAmount,
}; };
} }
@ -177,15 +275,21 @@ export class SequelizeIssuedInvoiceItemDomainMapper extends SequelizeDomainMappe
taxableAmount: attributes.taxableAmount!, taxableAmount: attributes.taxableAmount!,
ivaCode: attributes.ivaCode!,
ivaPercentage: attributes.ivaPercentage!,
ivaAmount: attributes.ivaAmount!, ivaAmount: attributes.ivaAmount!,
recCode: attributes.recCode!,
recPercentage: attributes.recPercentage!,
recAmount: attributes.recAmount!, recAmount: attributes.recAmount!,
retentionCode: attributes.retentionCode!,
retentionPercentage: attributes.retentionPercentage!,
retentionAmount: attributes.retentionAmount!, retentionAmount: attributes.retentionAmount!,
taxesAmount: attributes.taxesAmount!, taxesAmount: attributes.taxesAmount!,
totalAmount: attributes.totalAmount!, totalAmount: attributes.totalAmount!,
taxes: attributes.taxes!,
languageCode: attributes.languageCode!, languageCode: attributes.languageCode!,
currencyCode: attributes.currencyCode!, currencyCode: attributes.currencyCode!,
}, },
@ -213,47 +317,52 @@ export class SequelizeIssuedInvoiceItemDomainMapper extends SequelizeDomainMappe
errors: ValidationErrorDetail[]; errors: ValidationErrorDetail[];
}; };
const taxesAmounts = source.taxes;
return Result.ok({ return Result.ok({
item_id: source.id.toPrimitive(), item_id: source.id.toPrimitive(),
invoice_id: parent.id.toPrimitive(), invoice_id: parent.id.toPrimitive(),
position: index, position: index,
description: toNullable(source.description, (v) => v.toPrimitive()), description: maybeToNullable(source.description, (v) => v.toPrimitive()),
quantity_value: toNullable(source.quantity, (v) => v.toPrimitive().value), quantity_value: maybeToNullable(source.quantity, (v) => v.toPrimitive().value),
quantity_scale: quantity_scale:
toNullable(source.quantity, (v) => v.toPrimitive().scale) ?? ItemQuantity.DEFAULT_SCALE, maybeToNullable(source.quantity, (v) => v.toPrimitive().scale) ??
ItemQuantity.DEFAULT_SCALE,
unit_amount_value: toNullable(source.unitAmount, (v) => v.toPrimitive().value), unit_amount_value: maybeToNullable(source.unitAmount, (v) => v.toPrimitive().value),
unit_amount_scale: unit_amount_scale:
toNullable(source.unitAmount, (v) => v.toPrimitive().scale) ?? ItemAmount.DEFAULT_SCALE, maybeToNullable(source.unitAmount, (v) => v.toPrimitive().scale) ??
ItemAmount.DEFAULT_SCALE,
subtotal_amount_value: source.subtotalAmount.value, subtotal_amount_value: maybeToNullable(source.subtotalAmount, (v) => v.toPrimitive().value),
subtotal_amount_scale: source.subtotalAmount.scale, subtotal_amount_scale:
maybeToNullable(source.subtotalAmount, (v) => v.toPrimitive().scale) ??
ItemAmount.DEFAULT_SCALE,
// Te has quedado aquí --- IGNORE ---
// !!!!!!!!!!!!!!!!!!!
// //
discount_percentage_value: toNullable( discount_percentage_value: maybeToNullable(
source.itemDiscountPercentage, source.itemDiscountPercentage,
(v) => v.toPrimitive().value (v) => v.toPrimitive().value
), ),
discount_percentage_scale: discount_percentage_scale:
toNullable(source.itemDiscountPercentage, (v) => v.toPrimitive().scale) ?? maybeToNullable(source.itemDiscountPercentage, (v) => v.toPrimitive().scale) ??
ItemDiscount.DEFAULT_SCALE, ItemDiscountPercentage.DEFAULT_SCALE,
discount_amount_value: source.itemDiscountAmount.value, discount_amount_value: source.itemDiscountAmount.value,
discount_amount_scale: source.itemDiscountAmount.scale, discount_amount_scale: source.itemDiscountAmount.scale,
// //
global_discount_percentage_value: toNullable( 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:
toNullable(source.globalDiscountPercentage, (v) => v.toPrimitive().scale) ?? maybeToNullable(source.globalDiscountPercentage, (v) => v.toPrimitive().scale) ??
ItemDiscount.DEFAULT_SCALE, ItemDiscountPercentage.DEFAULT_SCALE,
global_discount_amount_value: source.globalDiscountAmount.value, global_discount_amount_value: source.globalDiscountAmount.value,
global_discount_amount_scale: source.globalDiscountAmount.scale, global_discount_amount_scale: source.globalDiscountAmount.scale,
@ -267,32 +376,38 @@ export class SequelizeIssuedInvoiceItemDomainMapper extends SequelizeDomainMappe
taxable_amount_scale: source.taxableAmount.scale, taxable_amount_scale: source.taxableAmount.scale,
// IVA // IVA
iva_code: toNullable(source.taxes.iva, (v) => v.code), iva_code: maybeToNullableString(source.ivaCode),
iva_percentage_value: toNullable(source.taxes.iva, (v) => v.percentage.value), iva_percentage_value: maybeToNullable(source.ivaPercentage, (v) => v.toPrimitive().value),
iva_percentage_scale: toNullable(source.taxes.iva, (v) => v.percentage.scale) ?? 2, iva_percentage_scale:
maybeToNullable(source.ivaPercentage, (v) => v.toPrimitive().scale) ?? 2,
iva_amount_value: taxesAmounts.ivaAmount.value, iva_amount_value: maybeToNullable(source.ivaAmount, (v) => v.toPrimitive().value),
iva_amount_scale: taxesAmounts.ivaAmount.scale, iva_amount_scale: maybeToNullable(source.ivaAmount, (v) => v.toPrimitive().scale) ?? 4,
// REC // REC
rec_code: toNullable(source.taxes.rec, (v) => v.code), rec_code: maybeToNullableString(source.recCode),
rec_percentage_value: toNullable(source.taxes.rec, (v) => v.percentage.value), rec_percentage_value: maybeToNullable(source.recPercentage, (v) => v.toPrimitive().value),
rec_percentage_scale: toNullable(source.taxes.rec, (v) => v.percentage.scale) ?? 2, rec_percentage_scale:
maybeToNullable(source.recPercentage, (v) => v.toPrimitive().scale) ?? 2,
rec_amount_value: taxesAmounts.recAmount.value, rec_amount_value: maybeToNullable(source.recAmount, (v) => v.toPrimitive().value),
rec_amount_scale: taxesAmounts.recAmount.scale, rec_amount_scale: maybeToNullable(source.recAmount, (v) => v.toPrimitive().scale) ?? 4,
// RET // RET
retention_code: toNullable(source.taxes.retention, (v) => v.code), retention_code: maybeToNullableString(source.retentionCode),
retention_percentage_value: toNullable(source.taxes.retention, (v) => v.percentage.value), retention_percentage_value: maybeToNullable(
source.retentionPercentage,
(v) => v.toPrimitive().value
),
retention_percentage_scale: retention_percentage_scale:
toNullable(source.taxes.retention, (v) => v.percentage.scale) ?? 2, maybeToNullable(source.retentionPercentage, (v) => v.toPrimitive().scale) ?? 2,
retention_amount_value: taxesAmounts.retentionAmount.value, retention_amount_value: maybeToNullable(source.retentionAmount, (v) => v.toPrimitive().value),
retention_amount_scale: taxesAmounts.retentionAmount.scale, retention_amount_scale:
maybeToNullable(source.retentionAmount, (v) => v.toPrimitive().scale) ?? 4,
// //
taxes_amount_value: source.taxesAmount.value, taxes_amount_value: source.taxesAmount.value,

View File

@ -10,8 +10,8 @@ import {
ValidationErrorCollection, ValidationErrorCollection,
type ValidationErrorDetail, type ValidationErrorDetail,
extractOrPushError, extractOrPushError,
maybeFromNullableVO, maybeFromNullableResult,
toNullable, maybeToNullable,
} from "@repo/rdx-ddd"; } from "@repo/rdx-ddd";
import { Maybe, Result } from "@repo/rdx-utils"; import { Maybe, Result } from "@repo/rdx-utils";
@ -51,37 +51,37 @@ export class SequelizeIssuedInvoiceRecipientDomainMapper {
const customerTin = extractOrPushError(TINNumber.create(_tin!), "customer_tin", errors); const customerTin = extractOrPushError(TINNumber.create(_tin!), "customer_tin", errors);
const customerStreet = extractOrPushError( const customerStreet = extractOrPushError(
maybeFromNullableVO(_street, (value) => Street.create(value)), maybeFromNullableResult(_street, (value) => Street.create(value)),
"customer_street", "customer_street",
errors errors
); );
const customerStreet2 = extractOrPushError( const customerStreet2 = extractOrPushError(
maybeFromNullableVO(_street2, (value) => Street.create(value)), maybeFromNullableResult(_street2, (value) => Street.create(value)),
"customer_street2", "customer_street2",
errors errors
); );
const customerCity = extractOrPushError( const customerCity = extractOrPushError(
maybeFromNullableVO(_city, (value) => City.create(value)), maybeFromNullableResult(_city, (value) => City.create(value)),
"customer_city", "customer_city",
errors errors
); );
const customerProvince = extractOrPushError( const customerProvince = extractOrPushError(
maybeFromNullableVO(_province, (value) => Province.create(value)), maybeFromNullableResult(_province, (value) => Province.create(value)),
"customer_province", "customer_province",
errors errors
); );
const customerPostalCode = extractOrPushError( const customerPostalCode = extractOrPushError(
maybeFromNullableVO(_postal_code, (value) => PostalCode.create(value)), maybeFromNullableResult(_postal_code, (value) => PostalCode.create(value)),
"customer_postal_code", "customer_postal_code",
errors errors
); );
const customerCountry = extractOrPushError( const customerCountry = extractOrPushError(
maybeFromNullableVO(_country, (value) => Country.create(value)), maybeFromNullableResult(_country, (value) => Country.create(value)),
"customer_country", "customer_country",
errors errors
); );
@ -145,12 +145,12 @@ export class SequelizeIssuedInvoiceRecipientDomainMapper {
return { return {
customer_tin: recipient.tin.toPrimitive(), customer_tin: recipient.tin.toPrimitive(),
customer_name: recipient.name.toPrimitive(), customer_name: recipient.name.toPrimitive(),
customer_street: toNullable(recipient.street, (v) => v.toPrimitive()), customer_street: maybeToNullable(recipient.street, (v) => v.toPrimitive()),
customer_street2: toNullable(recipient.street2, (v) => v.toPrimitive()), customer_street2: maybeToNullable(recipient.street2, (v) => v.toPrimitive()),
customer_city: toNullable(recipient.city, (v) => v.toPrimitive()), customer_city: maybeToNullable(recipient.city, (v) => v.toPrimitive()),
customer_province: toNullable(recipient.province, (v) => v.toPrimitive()), customer_province: maybeToNullable(recipient.province, (v) => v.toPrimitive()),
customer_postal_code: toNullable(recipient.postalCode, (v) => v.toPrimitive()), customer_postal_code: maybeToNullable(recipient.postalCode, (v) => v.toPrimitive()),
customer_country: toNullable(recipient.country, (v) => v.toPrimitive()), customer_country: maybeToNullable(recipient.country, (v) => v.toPrimitive()),
}; };
} }
} }

View File

@ -1,8 +1,24 @@
import type { JsonTaxCatalogProvider } from "@erp/core";
import { type MapperParamsType, SequelizeDomainMapper } from "@erp/core/api"; import { type MapperParamsType, SequelizeDomainMapper } from "@erp/core/api";
import { UniqueID, type ValidationErrorDetail, toNullable } from "@repo/rdx-ddd"; import {
UniqueID,
ValidationErrorCollection,
type ValidationErrorDetail,
extractOrPushError,
maybeFromNullableOrEmptyString,
maybeFromNullableResult,
maybeToNullable,
maybeToNullableString,
} from "@repo/rdx-ddd";
import { Result } from "@repo/rdx-utils"; import { Result } from "@repo/rdx-utils";
import type { InvoiceTaxGroup, IssuedInvoice } from "../../../../../../domain"; import {
InvoiceAmount,
InvoiceTaxPercentage,
type IssuedInvoice,
type IssuedInvoiceProps,
IssuedInvoiceTax,
} from "../../../../../../domain";
import type { import type {
CustomerInvoiceTaxCreationAttributes, CustomerInvoiceTaxCreationAttributes,
CustomerInvoiceTaxModel, CustomerInvoiceTaxModel,
@ -23,17 +39,145 @@ import type {
export class SequelizeIssuedInvoiceTaxesDomainMapper extends SequelizeDomainMapper< export class SequelizeIssuedInvoiceTaxesDomainMapper extends SequelizeDomainMapper<
CustomerInvoiceTaxModel, CustomerInvoiceTaxModel,
CustomerInvoiceTaxCreationAttributes, CustomerInvoiceTaxCreationAttributes,
InvoiceTaxGroup IssuedInvoiceTax
> { > {
private taxCatalog!: JsonTaxCatalogProvider;
constructor(params: MapperParamsType) {
super();
const { taxCatalog } = params as {
taxCatalog: JsonTaxCatalogProvider;
};
if (!taxCatalog) {
throw new Error('taxCatalog not defined ("SequelizeIssuedInvoiceTaxesDomainMapper")');
}
this.taxCatalog = taxCatalog;
}
public mapToDomain( public mapToDomain(
source: CustomerInvoiceTaxModel, source: CustomerInvoiceTaxModel,
params?: MapperParamsType params?: MapperParamsType
): Result<InvoiceTaxGroup, Error> { ): Result<IssuedInvoiceTax, Error> {
throw new Error("Se calcula a partir de las líneas de detalle"); const { errors, index, attributes } = params as {
index: number;
errors: ValidationErrorDetail[];
attributes: Partial<IssuedInvoiceProps>;
};
const taxableAmount = extractOrPushError(
InvoiceAmount.create({
value: source.taxable_amount_value,
currency_code: attributes.currencyCode?.code,
}),
`taxes[${index}].taxable_amount_value`,
errors
);
const ivaCode = source.iva_code;
const ivaPercentage = extractOrPushError(
InvoiceTaxPercentage.create({
value: source.iva_percentage_value,
}),
`taxes[${index}].iva_percentage_value`,
errors
);
const ivaAmount = extractOrPushError(
InvoiceAmount.create({
value: source.iva_amount_value,
currency_code: attributes.currencyCode?.code,
}),
`taxes[${index}].iva_amount_value`,
errors
);
const recCode = maybeFromNullableOrEmptyString(source.rec_code);
const recPercentage = extractOrPushError(
maybeFromNullableResult(source.rec_percentage_value, (value) =>
InvoiceTaxPercentage.create({ value })
),
`taxes[${index}].rec_percentage_value`,
errors
);
const recAmount = extractOrPushError(
maybeFromNullableResult(source.rec_amount_value, (value) =>
InvoiceAmount.create({ value, currency_code: attributes.currencyCode?.code })
),
`taxes[${index}].rec_amount_value`,
errors
);
const retentionCode = maybeFromNullableOrEmptyString(source.retention_code);
const retentionPercentage = extractOrPushError(
maybeFromNullableResult(source.retention_percentage_value, (value) =>
InvoiceTaxPercentage.create({ value })
),
`taxes[${index}].retention_percentage_value`,
errors
);
const retentionAmount = extractOrPushError(
maybeFromNullableResult(source.retention_amount_value, (value) =>
InvoiceAmount.create({ value, currency_code: attributes.currencyCode?.code })
),
`taxes[${index}].retention_amount_value`,
errors
);
const taxesAmount = extractOrPushError(
InvoiceAmount.create({
value: source.taxes_amount_value,
currency_code: attributes.currencyCode?.code,
}),
`taxes[${index}].taxes_amount_value`,
errors
);
// Si hubo errores de mapeo, devolvemos colección de validación
if (errors.length > 0) {
return Result.fail(
new ValidationErrorCollection("Customer invoice tax mapping failed [mapToDomain]", errors)
);
}
// 2) Construcción del elemento de dominio
const createResult = IssuedInvoiceTax.create({
taxableAmount: taxableAmount!,
ivaCode: ivaCode!,
ivaPercentage: ivaPercentage!,
ivaAmount: ivaAmount!,
recCode: recCode,
recPercentage: recPercentage!,
recAmount: recAmount!,
retentionCode: retentionCode,
retentionPercentage: retentionPercentage!,
retentionAmount: retentionAmount!,
taxesAmount: taxesAmount!,
});
if (createResult.isFailure) {
return Result.fail(
new ValidationErrorCollection("Invoice tax group entity creation failed", [
{ path: `taxes[${index}]`, message: "Invoice tax group entity creation failed" },
])
);
}
return createResult;
} }
public mapToPersistence( public mapToPersistence(
source: InvoiceTaxGroup, source: IssuedInvoiceTax,
params?: MapperParamsType params?: MapperParamsType
): Result<CustomerInvoiceTaxCreationAttributes, Error> { ): Result<CustomerInvoiceTaxCreationAttributes, Error> {
const { errors, parent } = params as { const { errors, parent } = params as {
@ -42,10 +186,6 @@ export class SequelizeIssuedInvoiceTaxesDomainMapper extends SequelizeDomainMapp
}; };
try { try {
const { ivaAmount, recAmount, retentionAmount } = source;
const totalTaxes = ivaAmount.add(recAmount).add(retentionAmount);
const dto: CustomerInvoiceTaxCreationAttributes = { const dto: CustomerInvoiceTaxCreationAttributes = {
tax_id: UniqueID.generateNewID().toPrimitive(), tax_id: UniqueID.generateNewID().toPrimitive(),
invoice_id: parent.id.toPrimitive(), invoice_id: parent.id.toPrimitive(),
@ -55,35 +195,44 @@ export class SequelizeIssuedInvoiceTaxesDomainMapper extends SequelizeDomainMapp
taxable_amount_scale: source.taxableAmount.scale, taxable_amount_scale: source.taxableAmount.scale,
// IVA // IVA
iva_code: source.iva.code, iva_code: source.ivaCode,
iva_percentage_value: source.iva.value, iva_percentage_value: source.ivaPercentage.value,
iva_percentage_scale: source.iva.scale, iva_percentage_scale: source.ivaPercentage.scale,
iva_amount_value: ivaAmount.value, iva_amount_value: source.ivaAmount.value,
iva_amount_scale: ivaAmount.scale, iva_amount_scale: source.ivaAmount.scale,
// REC // REC
rec_code: toNullable(source.rec, (v) => v.code), rec_code: maybeToNullableString(source.recCode),
rec_percentage_value: toNullable(source.rec, (v) => v.percentage.value), rec_percentage_value: maybeToNullable(source.recPercentage, (v) => v.toPrimitive().value),
rec_percentage_scale: toNullable(source.rec, (v) => v.percentage.scale) ?? 2, rec_percentage_scale:
maybeToNullable(source.recPercentage, (v) => v.toPrimitive().scale) ?? 2,
rec_amount_value: recAmount.value, rec_amount_value: maybeToNullable(source.recAmount, (v) => v.toPrimitive().value),
rec_amount_scale: recAmount.scale, rec_amount_scale: maybeToNullable(source.recAmount, (v) => v.toPrimitive().scale) ?? 4,
// RET // RET
retention_code: toNullable(source.retention, (v) => v.code), retention_code: maybeToNullableString(source.retentionCode),
retention_percentage_value: toNullable(source.retention, (v) => v.percentage.value), retention_percentage_value: maybeToNullable(
retention_percentage_scale: toNullable(source.retention, (v) => v.percentage.scale) ?? 2, source.retentionPercentage,
(v) => v.toPrimitive().value
),
retention_percentage_scale:
maybeToNullable(source.retentionPercentage, (v) => v.toPrimitive().scale) ?? 2,
retention_amount_value: retentionAmount.value, retention_amount_value: maybeToNullable(
retention_amount_scale: retentionAmount.scale, source.retentionAmount,
(v) => v.toPrimitive().value
),
retention_amount_scale:
maybeToNullable(source.retentionAmount, (v) => v.toPrimitive().scale) ?? 4,
// TOTAL // TOTAL
taxes_amount_value: totalTaxes.value, taxes_amount_value: source.taxesAmount.value,
taxes_amount_scale: totalTaxes.scale, taxes_amount_scale: source.taxesAmount.scale,
}; };
return Result.ok(dto); return Result.ok(dto);

View File

@ -6,8 +6,8 @@ import {
ValidationErrorCollection, ValidationErrorCollection,
type ValidationErrorDetail, type ValidationErrorDetail,
extractOrPushError, extractOrPushError,
maybeFromNullableVO, maybeFromNullableResult,
toEmptyString, maybeToEmptyString,
} from "@repo/rdx-ddd"; } from "@repo/rdx-ddd";
import { Maybe, Result } from "@repo/rdx-utils"; import { Maybe, Result } from "@repo/rdx-utils";
@ -48,25 +48,25 @@ export class SequelizeIssuedInvoiceVerifactuDomainMapper extends SequelizeDomain
); );
const qr = extractOrPushError( const qr = extractOrPushError(
maybeFromNullableVO(source.qr, (value) => Result.ok(String(value))), maybeFromNullableResult(source.qr, (value) => Result.ok(String(value))),
"qr", "qr",
errors errors
); );
const url = extractOrPushError( const url = extractOrPushError(
maybeFromNullableVO(source.url, (value) => URLAddress.create(value)), maybeFromNullableResult(source.url, (value) => URLAddress.create(value)),
"url", "url",
errors errors
); );
const uuid = extractOrPushError( const uuid = extractOrPushError(
maybeFromNullableVO(source.uuid, (value) => Result.ok(String(value))), maybeFromNullableResult(source.uuid, (value) => Result.ok(String(value))),
"uuid", "uuid",
errors errors
); );
const operacion = extractOrPushError( const operacion = extractOrPushError(
maybeFromNullableVO(source.operacion, (value) => Result.ok(String(value))), maybeFromNullableResult(source.operacion, (value) => Result.ok(String(value))),
"operacion", "operacion",
errors errors
); );
@ -126,10 +126,10 @@ export class SequelizeIssuedInvoiceVerifactuDomainMapper extends SequelizeDomain
id: verifactu.id.toPrimitive(), id: verifactu.id.toPrimitive(),
invoice_id: parent.id.toPrimitive(), invoice_id: parent.id.toPrimitive(),
estado: verifactu.estado.toPrimitive(), estado: verifactu.estado.toPrimitive(),
qr: toEmptyString(verifactu.qrCode, (v) => v), qr: maybeToEmptyString(verifactu.qrCode, (v) => v),
url: toEmptyString(verifactu.url, (v) => v.toPrimitive()), url: maybeToEmptyString(verifactu.url, (v) => v.toPrimitive()),
uuid: toEmptyString(verifactu.uuid, (v) => v), uuid: maybeToEmptyString(verifactu.uuid, (v) => v),
operacion: toEmptyString(verifactu.operacion, (v) => v), operacion: maybeToEmptyString(verifactu.operacion, (v) => v),
}); });
} }
} }

View File

@ -10,7 +10,7 @@ import {
ValidationErrorCollection, ValidationErrorCollection,
type ValidationErrorDetail, type ValidationErrorDetail,
extractOrPushError, extractOrPushError,
maybeFromNullableVO, maybeFromNullableResult,
} from "@repo/rdx-ddd"; } from "@repo/rdx-ddd";
import { Result } from "@repo/rdx-utils"; import { Result } from "@repo/rdx-utils";
@ -59,37 +59,37 @@ export class SequelizeIssuedInvoiceRecipientListMapper extends SequelizeQueryMap
const customerTin = extractOrPushError(TINNumber.create(_tin!), "customer_tin", errors); const customerTin = extractOrPushError(TINNumber.create(_tin!), "customer_tin", errors);
const customerStreet = extractOrPushError( const customerStreet = extractOrPushError(
maybeFromNullableVO(_street, (value) => Street.create(value)), maybeFromNullableResult(_street, (value) => Street.create(value)),
"customer_street", "customer_street",
errors errors
); );
const customerStreet2 = extractOrPushError( const customerStreet2 = extractOrPushError(
maybeFromNullableVO(_street2, (value) => Street.create(value)), maybeFromNullableResult(_street2, (value) => Street.create(value)),
"customer_street2", "customer_street2",
errors errors
); );
const customerCity = extractOrPushError( const customerCity = extractOrPushError(
maybeFromNullableVO(_city, (value) => City.create(value)), maybeFromNullableResult(_city, (value) => City.create(value)),
"customer_city", "customer_city",
errors errors
); );
const customerProvince = extractOrPushError( const customerProvince = extractOrPushError(
maybeFromNullableVO(_province, (value) => Province.create(value)), maybeFromNullableResult(_province, (value) => Province.create(value)),
"customer_province", "customer_province",
errors errors
); );
const customerPostalCode = extractOrPushError( const customerPostalCode = extractOrPushError(
maybeFromNullableVO(_postal_code, (value) => PostalCode.create(value)), maybeFromNullableResult(_postal_code, (value) => PostalCode.create(value)),
"customer_postal_code", "customer_postal_code",
errors errors
); );
const customerCountry = extractOrPushError( const customerCountry = extractOrPushError(
maybeFromNullableVO(_country, (value) => Country.create(value)), maybeFromNullableResult(_country, (value) => Country.create(value)),
"customer_country", "customer_country",
errors errors
); );

View File

@ -7,7 +7,7 @@ import {
ValidationErrorCollection, ValidationErrorCollection,
type ValidationErrorDetail, type ValidationErrorDetail,
extractOrPushError, extractOrPushError,
maybeFromNullableVO, maybeFromNullableResult,
} from "@repo/rdx-ddd"; } from "@repo/rdx-ddd";
import { Maybe, Result } from "@repo/rdx-utils"; import { Maybe, Result } from "@repo/rdx-utils";
@ -126,7 +126,7 @@ export class SequelizeIssuedInvoiceListMapper
const status = extractOrPushError(InvoiceStatus.create(raw.status), "status", errors); const status = extractOrPushError(InvoiceStatus.create(raw.status), "status", errors);
const series = extractOrPushError( const series = extractOrPushError(
maybeFromNullableVO(raw.series, (value) => InvoiceSerie.create(value)), maybeFromNullableResult(raw.series, (value) => InvoiceSerie.create(value)),
"serie", "serie",
errors errors
); );
@ -144,19 +144,19 @@ export class SequelizeIssuedInvoiceListMapper
); );
const operationDate = extractOrPushError( const operationDate = extractOrPushError(
maybeFromNullableVO(raw.operation_date, (value) => UtcDate.createFromISO(value)), maybeFromNullableResult(raw.operation_date, (value) => UtcDate.createFromISO(value)),
"operation_date", "operation_date",
errors errors
); );
const reference = extractOrPushError( const reference = extractOrPushError(
maybeFromNullableVO(raw.reference, (value) => Result.ok(String(value))), maybeFromNullableResult(raw.reference, (value) => Result.ok(String(value))),
"description", "description",
errors errors
); );
const description = extractOrPushError( const description = extractOrPushError(
maybeFromNullableVO(raw.description, (value) => Result.ok(String(value))), maybeFromNullableResult(raw.description, (value) => Result.ok(String(value))),
"description", "description",
errors errors
); );

View File

@ -5,7 +5,7 @@ import {
ValidationErrorCollection, ValidationErrorCollection,
type ValidationErrorDetail, type ValidationErrorDetail,
extractOrPushError, extractOrPushError,
maybeFromNullableVO, maybeFromNullableResult,
} from "@repo/rdx-ddd"; } from "@repo/rdx-ddd";
import { Result } from "@repo/rdx-utils"; import { Result } from "@repo/rdx-utils";
@ -26,25 +26,25 @@ export class SequelizeVerifactuRecordListMapper extends SequelizeQueryMapper<
const estado = extractOrPushError(VerifactuRecordEstado.create(raw.estado), "estado", errors); const estado = extractOrPushError(VerifactuRecordEstado.create(raw.estado), "estado", errors);
const qr = extractOrPushError( const qr = extractOrPushError(
maybeFromNullableVO(raw.qr, (value) => Result.ok(String(value))), maybeFromNullableResult(raw.qr, (value) => Result.ok(String(value))),
"qr", "qr",
errors errors
); );
const url = extractOrPushError( const url = extractOrPushError(
maybeFromNullableVO(raw.url, (value) => URLAddress.create(value)), maybeFromNullableResult(raw.url, (value) => URLAddress.create(value)),
"url", "url",
errors errors
); );
const uuid = extractOrPushError( const uuid = extractOrPushError(
maybeFromNullableVO(raw.uuid, (value) => Result.ok(String(value))), maybeFromNullableResult(raw.uuid, (value) => Result.ok(String(value))),
"uuid", "uuid",
errors errors
); );
const operacion = extractOrPushError( const operacion = extractOrPushError(
maybeFromNullableVO(raw.operacion, (value) => Result.ok(String(value))), maybeFromNullableResult(raw.operacion, (value) => Result.ok(String(value))),
"operacion", "operacion",
errors errors
); );

View File

@ -9,8 +9,8 @@ import {
ValidationErrorCollection, ValidationErrorCollection,
type ValidationErrorDetail, type ValidationErrorDetail,
extractOrPushError, extractOrPushError,
maybeFromNullableVO, maybeFromNullableResult,
toNullable, maybeToNullable,
} from "@repo/rdx-ddd"; } from "@repo/rdx-ddd";
import { Maybe, Result, isNullishOrEmpty } from "@repo/rdx-utils"; import { Maybe, Result, isNullishOrEmpty } from "@repo/rdx-utils";
@ -66,7 +66,7 @@ export class SequelizeProformaDomainMapper
const isProforma = Boolean(source.is_proforma); const isProforma = Boolean(source.is_proforma);
const proformaId = extractOrPushError( const proformaId = extractOrPushError(
maybeFromNullableVO(source.proforma_id, (v) => UniqueID.create(v)), maybeFromNullableResult(source.proforma_id, (v) => UniqueID.create(v)),
"proforma_id", "proforma_id",
errors errors
); );
@ -74,7 +74,7 @@ export class SequelizeProformaDomainMapper
const status = extractOrPushError(InvoiceStatus.create(source.status), "status", errors); const status = extractOrPushError(InvoiceStatus.create(source.status), "status", errors);
const series = extractOrPushError( const series = extractOrPushError(
maybeFromNullableVO(source.series, (v) => InvoiceSerie.create(v)), maybeFromNullableResult(source.series, (v) => InvoiceSerie.create(v)),
"series", "series",
errors errors
); );
@ -93,7 +93,7 @@ export class SequelizeProformaDomainMapper
); );
const operationDate = extractOrPushError( const operationDate = extractOrPushError(
maybeFromNullableVO(source.operation_date, (v) => UtcDate.createFromISO(v)), maybeFromNullableResult(source.operation_date, (v) => UtcDate.createFromISO(v)),
"operation_date", "operation_date",
errors errors
); );
@ -113,19 +113,19 @@ export class SequelizeProformaDomainMapper
// Textos opcionales // Textos opcionales
const reference = extractOrPushError( const reference = extractOrPushError(
maybeFromNullableVO(source.reference, (value) => Result.ok(String(value))), maybeFromNullableResult(source.reference, (value) => Result.ok(String(value))),
"reference", "reference",
errors errors
); );
const description = extractOrPushError( const description = extractOrPushError(
maybeFromNullableVO(source.description, (value) => Result.ok(String(value))), maybeFromNullableResult(source.description, (value) => Result.ok(String(value))),
"description", "description",
errors errors
); );
const notes = extractOrPushError( const notes = extractOrPushError(
maybeFromNullableVO(source.notes, (value) => TextValue.create(value)), maybeFromNullableResult(source.notes, (value) => TextValue.create(value)),
"notes", "notes",
errors errors
); );
@ -333,17 +333,17 @@ export class SequelizeProformaDomainMapper
// Flags / estado / serie / número // Flags / estado / serie / número
is_proforma: source.isProforma, is_proforma: source.isProforma,
status: source.status.toPrimitive(), status: source.status.toPrimitive(),
series: toNullable(source.series, (v) => v.toPrimitive()), series: maybeToNullable(source.series, (v) => v.toPrimitive()),
invoice_number: source.invoiceNumber.toPrimitive(), invoice_number: source.invoiceNumber.toPrimitive(),
invoice_date: source.invoiceDate.toPrimitive(), invoice_date: source.invoiceDate.toPrimitive(),
operation_date: toNullable(source.operationDate, (v) => v.toPrimitive()), operation_date: maybeToNullable(source.operationDate, (v) => v.toPrimitive()),
language_code: source.languageCode.toPrimitive(), language_code: source.languageCode.toPrimitive(),
currency_code: source.currencyCode.toPrimitive(), currency_code: source.currencyCode.toPrimitive(),
reference: toNullable(source.reference, (reference) => reference), reference: maybeToNullable(source.reference, (reference) => reference),
description: toNullable(source.description, (description) => description), description: maybeToNullable(source.description, (description) => description),
notes: toNullable(source.notes, (v) => v.toPrimitive()), notes: maybeToNullable(source.notes, (v) => v.toPrimitive()),
subtotal_amount_value: allAmounts.subtotalAmount.value, subtotal_amount_value: allAmounts.subtotalAmount.value,
subtotal_amount_scale: allAmounts.subtotalAmount.scale, subtotal_amount_scale: allAmounts.subtotalAmount.scale,
@ -369,8 +369,11 @@ export class SequelizeProformaDomainMapper
total_amount_value: allAmounts.totalAmount.value, total_amount_value: allAmounts.totalAmount.value,
total_amount_scale: allAmounts.totalAmount.scale, total_amount_scale: allAmounts.totalAmount.scale,
payment_method_id: toNullable(source.paymentMethod, (payment) => payment.toObjectString().id), payment_method_id: maybeToNullable(
payment_method_description: toNullable( source.paymentMethod,
(payment) => payment.toObjectString().id
),
payment_method_description: maybeToNullable(
source.paymentMethod, source.paymentMethod,
(payment) => payment.toObjectString().payment_description (payment) => payment.toObjectString().payment_description
), ),

View File

@ -5,15 +5,15 @@ import {
ValidationErrorCollection, ValidationErrorCollection,
type ValidationErrorDetail, type ValidationErrorDetail,
extractOrPushError, extractOrPushError,
maybeFromNullableVO, maybeFromNullableResult,
toNullable, maybeToNullable,
} from "@repo/rdx-ddd"; } from "@repo/rdx-ddd";
import { Result } from "@repo/rdx-utils"; import { Result } from "@repo/rdx-utils";
import { import {
ItemAmount, ItemAmount,
ItemDescription, ItemDescription,
ItemDiscount, ItemDiscountPercentage,
ItemQuantity, ItemQuantity,
ItemTaxGroup, ItemTaxGroup,
type Proforma, type Proforma,
@ -63,19 +63,19 @@ export class SequelizeProformaItemDomainMapper extends SequelizeDomainMapper<
); );
const description = extractOrPushError( const description = extractOrPushError(
maybeFromNullableVO(source.description, (v) => ItemDescription.create(v)), maybeFromNullableResult(source.description, (v) => ItemDescription.create(v)),
`items[${index}].description`, `items[${index}].description`,
errors errors
); );
const quantity = extractOrPushError( const quantity = extractOrPushError(
maybeFromNullableVO(source.quantity_value, (v) => ItemQuantity.create({ value: v })), maybeFromNullableResult(source.quantity_value, (v) => ItemQuantity.create({ value: v })),
`items[${index}].quantity`, `items[${index}].quantity`,
errors errors
); );
const unitAmount = extractOrPushError( const unitAmount = extractOrPushError(
maybeFromNullableVO(source.unit_amount_value, (value) => maybeFromNullableResult(source.unit_amount_value, (value) =>
ItemAmount.create({ value, currency_code: attributes.currencyCode?.code }) ItemAmount.create({ value, currency_code: attributes.currencyCode?.code })
), ),
`items[${index}].unit_amount`, `items[${index}].unit_amount`,
@ -83,35 +83,39 @@ export class SequelizeProformaItemDomainMapper extends SequelizeDomainMapper<
); );
const discountPercentage = extractOrPushError( const discountPercentage = extractOrPushError(
maybeFromNullableVO(source.discount_percentage_value, (v) => maybeFromNullableResult(source.discount_percentage_value, (v) =>
ItemDiscount.create({ value: v }) ItemDiscountPercentage.create({ value: v })
), ),
`items[${index}].discount_percentage`, `items[${index}].discount_percentage`,
errors errors
); );
const globalDiscountPercentage = extractOrPushError( const globalDiscountPercentage = extractOrPushError(
maybeFromNullableVO(source.global_discount_percentage_value, (v) => maybeFromNullableResult(source.global_discount_percentage_value, (v) =>
ItemDiscount.create({ value: v }) ItemDiscountPercentage.create({ value: v })
), ),
`items[${index}].discount_percentage`, `items[${index}].discount_percentage`,
errors errors
); );
const iva = extractOrPushError( const iva = extractOrPushError(
maybeFromNullableVO(source.iva_code, (code) => Tax.createFromCode(code, this._taxCatalog)), maybeFromNullableResult(source.iva_code, (code) =>
Tax.createFromCode(code, this._taxCatalog)
),
`items[${index}].iva_code`, `items[${index}].iva_code`,
errors errors
); );
const rec = extractOrPushError( const rec = extractOrPushError(
maybeFromNullableVO(source.rec_code, (code) => Tax.createFromCode(code, this._taxCatalog)), maybeFromNullableResult(source.rec_code, (code) =>
Tax.createFromCode(code, this._taxCatalog)
),
`items[${index}].rec_code`, `items[${index}].rec_code`,
errors errors
); );
const retention = extractOrPushError( const retention = extractOrPushError(
maybeFromNullableVO(source.retention_code, (code) => maybeFromNullableResult(source.retention_code, (code) =>
Tax.createFromCode(code, this._taxCatalog) Tax.createFromCode(code, this._taxCatalog)
), ),
`items[${index}].retention_code`, `items[${index}].retention_code`,
@ -201,40 +205,42 @@ export class SequelizeProformaItemDomainMapper extends SequelizeDomainMapper<
invoice_id: parent.id.toPrimitive(), invoice_id: parent.id.toPrimitive(),
position: index, position: index,
description: toNullable(source.description, (v) => v.toPrimitive()), description: maybeToNullable(source.description, (v) => v.toPrimitive()),
quantity_value: toNullable(source.quantity, (v) => v.toPrimitive().value), quantity_value: maybeToNullable(source.quantity, (v) => v.toPrimitive().value),
quantity_scale: quantity_scale:
toNullable(source.quantity, (v) => v.toPrimitive().scale) ?? ItemQuantity.DEFAULT_SCALE, maybeToNullable(source.quantity, (v) => v.toPrimitive().scale) ??
ItemQuantity.DEFAULT_SCALE,
unit_amount_value: toNullable(source.unitAmount, (v) => v.toPrimitive().value), unit_amount_value: maybeToNullable(source.unitAmount, (v) => v.toPrimitive().value),
unit_amount_scale: unit_amount_scale:
toNullable(source.unitAmount, (v) => v.toPrimitive().scale) ?? ItemAmount.DEFAULT_SCALE, maybeToNullable(source.unitAmount, (v) => v.toPrimitive().scale) ??
ItemAmount.DEFAULT_SCALE,
subtotal_amount_value: allAmounts.subtotalAmount.value, subtotal_amount_value: allAmounts.subtotalAmount.value,
subtotal_amount_scale: allAmounts.subtotalAmount.scale, subtotal_amount_scale: allAmounts.subtotalAmount.scale,
// //
discount_percentage_value: toNullable( discount_percentage_value: maybeToNullable(
source.itemDiscountPercentage, source.itemDiscountPercentage,
(v) => v.toPrimitive().value (v) => v.toPrimitive().value
), ),
discount_percentage_scale: discount_percentage_scale:
toNullable(source.itemDiscountPercentage, (v) => v.toPrimitive().scale) ?? maybeToNullable(source.itemDiscountPercentage, (v) => v.toPrimitive().scale) ??
ItemDiscount.DEFAULT_SCALE, ItemDiscountPercentage.DEFAULT_SCALE,
discount_amount_value: allAmounts.itemDiscountAmount.value, discount_amount_value: allAmounts.itemDiscountAmount.value,
discount_amount_scale: allAmounts.itemDiscountAmount.scale, discount_amount_scale: allAmounts.itemDiscountAmount.scale,
// //
global_discount_percentage_value: toNullable( 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:
toNullable(source.globalDiscountPercentage, (v) => v.toPrimitive().scale) ?? maybeToNullable(source.globalDiscountPercentage, (v) => v.toPrimitive().scale) ??
ItemDiscount.DEFAULT_SCALE, ItemDiscountPercentage.DEFAULT_SCALE,
global_discount_amount_value: allAmounts.globalDiscountAmount.value, global_discount_amount_value: allAmounts.globalDiscountAmount.value,
global_discount_amount_scale: allAmounts.globalDiscountAmount.scale, global_discount_amount_scale: allAmounts.globalDiscountAmount.scale,
@ -248,29 +254,32 @@ export class SequelizeProformaItemDomainMapper extends SequelizeDomainMapper<
taxable_amount_scale: allAmounts.taxableAmount.scale, taxable_amount_scale: allAmounts.taxableAmount.scale,
// IVA // IVA
iva_code: toNullable(source.taxes.iva, (v) => v.code), iva_code: maybeToNullable(source.taxes.iva, (v) => v.code),
iva_percentage_value: toNullable(source.taxes.iva, (v) => v.percentage.value), iva_percentage_value: maybeToNullable(source.taxes.iva, (v) => v.percentage.value),
iva_percentage_scale: toNullable(source.taxes.iva, (v) => v.percentage.scale) ?? 2, iva_percentage_scale: maybeToNullable(source.taxes.iva, (v) => v.percentage.scale) ?? 2,
iva_amount_value: taxesAmounts.ivaAmount.value, iva_amount_value: taxesAmounts.ivaAmount.value,
iva_amount_scale: taxesAmounts.ivaAmount.scale, iva_amount_scale: taxesAmounts.ivaAmount.scale,
// REC // REC
rec_code: toNullable(source.taxes.rec, (v) => v.code), rec_code: maybeToNullable(source.taxes.rec, (v) => v.code),
rec_percentage_value: toNullable(source.taxes.rec, (v) => v.percentage.value), rec_percentage_value: maybeToNullable(source.taxes.rec, (v) => v.percentage.value),
rec_percentage_scale: toNullable(source.taxes.rec, (v) => v.percentage.scale) ?? 2, rec_percentage_scale: maybeToNullable(source.taxes.rec, (v) => v.percentage.scale) ?? 2,
rec_amount_value: taxesAmounts.recAmount.value, rec_amount_value: taxesAmounts.recAmount.value,
rec_amount_scale: taxesAmounts.recAmount.scale, rec_amount_scale: taxesAmounts.recAmount.scale,
// RET // RET
retention_code: toNullable(source.taxes.retention, (v) => v.code), retention_code: maybeToNullable(source.taxes.retention, (v) => v.code),
retention_percentage_value: toNullable(source.taxes.retention, (v) => v.percentage.value), retention_percentage_value: maybeToNullable(
source.taxes.retention,
(v) => v.percentage.value
),
retention_percentage_scale: retention_percentage_scale:
toNullable(source.taxes.retention, (v) => v.percentage.scale) ?? 2, maybeToNullable(source.taxes.retention, (v) => v.percentage.scale) ?? 2,
retention_amount_value: taxesAmounts.retentionAmount.value, retention_amount_value: taxesAmounts.retentionAmount.value,
retention_amount_scale: taxesAmounts.retentionAmount.scale, retention_amount_scale: taxesAmounts.retentionAmount.scale,

View File

@ -10,7 +10,7 @@ import {
ValidationErrorCollection, ValidationErrorCollection,
type ValidationErrorDetail, type ValidationErrorDetail,
extractOrPushError, extractOrPushError,
maybeFromNullableVO, maybeFromNullableResult,
} from "@repo/rdx-ddd"; } from "@repo/rdx-ddd";
import { Maybe, Result } from "@repo/rdx-utils"; import { Maybe, Result } from "@repo/rdx-utils";
@ -55,37 +55,37 @@ export class SequelizeProformaRecipientDomainMapper {
const customerTin = extractOrPushError(TINNumber.create(_tin!), "customer_tin", errors); const customerTin = extractOrPushError(TINNumber.create(_tin!), "customer_tin", errors);
const customerStreet = extractOrPushError( const customerStreet = extractOrPushError(
maybeFromNullableVO(_street, (value) => Street.create(value)), maybeFromNullableResult(_street, (value) => Street.create(value)),
"customer_street", "customer_street",
errors errors
); );
const customerStreet2 = extractOrPushError( const customerStreet2 = extractOrPushError(
maybeFromNullableVO(_street2, (value) => Street.create(value)), maybeFromNullableResult(_street2, (value) => Street.create(value)),
"customer_street2", "customer_street2",
errors errors
); );
const customerCity = extractOrPushError( const customerCity = extractOrPushError(
maybeFromNullableVO(_city, (value) => City.create(value)), maybeFromNullableResult(_city, (value) => City.create(value)),
"customer_city", "customer_city",
errors errors
); );
const customerProvince = extractOrPushError( const customerProvince = extractOrPushError(
maybeFromNullableVO(_province, (value) => Province.create(value)), maybeFromNullableResult(_province, (value) => Province.create(value)),
"customer_province", "customer_province",
errors errors
); );
const customerPostalCode = extractOrPushError( const customerPostalCode = extractOrPushError(
maybeFromNullableVO(_postal_code, (value) => PostalCode.create(value)), maybeFromNullableResult(_postal_code, (value) => PostalCode.create(value)),
"customer_postal_code", "customer_postal_code",
errors errors
); );
const customerCountry = extractOrPushError( const customerCountry = extractOrPushError(
maybeFromNullableVO(_country, (value) => Country.create(value)), maybeFromNullableResult(_country, (value) => Country.create(value)),
"customer_country", "customer_country",
errors errors
); );

View File

@ -1,5 +1,5 @@
import { type MapperParamsType, SequelizeDomainMapper } from "@erp/core/api"; import { type MapperParamsType, SequelizeDomainMapper } from "@erp/core/api";
import { UniqueID, type ValidationErrorDetail, toNullable } from "@repo/rdx-ddd"; import { UniqueID, type ValidationErrorDetail, maybeToNullable } from "@repo/rdx-ddd";
import { Result } from "@repo/rdx-utils"; import { Result } from "@repo/rdx-utils";
import type { InvoiceTaxGroup, Proforma } from "../../../../../../domain"; import type { InvoiceTaxGroup, Proforma } from "../../../../../../domain";
@ -64,19 +64,20 @@ export class SequelizeProformaTaxesDomainMapper extends SequelizeDomainMapper<
iva_amount_scale: ivaAmount.scale, iva_amount_scale: ivaAmount.scale,
// REC // REC
rec_code: toNullable(source.rec, (v) => v.code), rec_code: maybeToNullable(source.rec, (v) => v.code),
rec_percentage_value: toNullable(source.rec, (v) => v.percentage.value), rec_percentage_value: maybeToNullable(source.rec, (v) => v.percentage.value),
rec_percentage_scale: toNullable(source.rec, (v) => v.percentage.scale) ?? 2, rec_percentage_scale: maybeToNullable(source.rec, (v) => v.percentage.scale) ?? 2,
rec_amount_value: recAmount.value, rec_amount_value: recAmount.value,
rec_amount_scale: recAmount.scale, rec_amount_scale: recAmount.scale,
// RET // RET
retention_code: toNullable(source.retention, (v) => v.code), retention_code: maybeToNullable(source.retention, (v) => v.code),
retention_percentage_value: toNullable(source.retention, (v) => v.percentage.value), retention_percentage_value: maybeToNullable(source.retention, (v) => v.percentage.value),
retention_percentage_scale: toNullable(source.retention, (v) => v.percentage.scale) ?? 2, retention_percentage_scale:
maybeToNullable(source.retention, (v) => v.percentage.scale) ?? 2,
retention_amount_value: retentionAmount.value, retention_amount_value: retentionAmount.value,
retention_amount_scale: retentionAmount.scale, retention_amount_scale: retentionAmount.scale,

View File

@ -14,7 +14,7 @@ import {
ValidationErrorCollection, ValidationErrorCollection,
type ValidationErrorDetail, type ValidationErrorDetail,
extractOrPushError, extractOrPushError,
maybeFromNullableVO, maybeFromNullableResult,
} from "@repo/rdx-ddd"; } from "@repo/rdx-ddd";
import { Result } from "@repo/rdx-utils"; import { Result } from "@repo/rdx-utils";
@ -65,37 +65,37 @@ export class SequelizeInvoiceRecipientListMapper
const customerTin = extractOrPushError(TINNumber.create(_tin!), "customer_tin", errors); const customerTin = extractOrPushError(TINNumber.create(_tin!), "customer_tin", errors);
const customerStreet = extractOrPushError( const customerStreet = extractOrPushError(
maybeFromNullableVO(_street, (value) => Street.create(value)), maybeFromNullableResult(_street, (value) => Street.create(value)),
"customer_street", "customer_street",
errors errors
); );
const customerStreet2 = extractOrPushError( const customerStreet2 = extractOrPushError(
maybeFromNullableVO(_street2, (value) => Street.create(value)), maybeFromNullableResult(_street2, (value) => Street.create(value)),
"customer_street2", "customer_street2",
errors errors
); );
const customerCity = extractOrPushError( const customerCity = extractOrPushError(
maybeFromNullableVO(_city, (value) => City.create(value)), maybeFromNullableResult(_city, (value) => City.create(value)),
"customer_city", "customer_city",
errors errors
); );
const customerProvince = extractOrPushError( const customerProvince = extractOrPushError(
maybeFromNullableVO(_province, (value) => Province.create(value)), maybeFromNullableResult(_province, (value) => Province.create(value)),
"customer_province", "customer_province",
errors errors
); );
const customerPostalCode = extractOrPushError( const customerPostalCode = extractOrPushError(
maybeFromNullableVO(_postal_code, (value) => PostalCode.create(value)), maybeFromNullableResult(_postal_code, (value) => PostalCode.create(value)),
"customer_postal_code", "customer_postal_code",
errors errors
); );
const customerCountry = extractOrPushError( const customerCountry = extractOrPushError(
maybeFromNullableVO(_country, (value) => Country.create(value)), maybeFromNullableResult(_country, (value) => Country.create(value)),
"customer_country", "customer_country",
errors errors
); );

View File

@ -7,7 +7,7 @@ import {
ValidationErrorCollection, ValidationErrorCollection,
type ValidationErrorDetail, type ValidationErrorDetail,
extractOrPushError, extractOrPushError,
maybeFromNullableVO, maybeFromNullableResult,
} from "@repo/rdx-ddd"; } from "@repo/rdx-ddd";
import { Result } from "@repo/rdx-utils"; import { Result } from "@repo/rdx-utils";
@ -105,7 +105,7 @@ export class SequelizeProformaListMapper
const status = extractOrPushError(InvoiceStatus.create(raw.status), "status", errors); const status = extractOrPushError(InvoiceStatus.create(raw.status), "status", errors);
const series = extractOrPushError( const series = extractOrPushError(
maybeFromNullableVO(raw.series, (value) => InvoiceSerie.create(value)), maybeFromNullableResult(raw.series, (value) => InvoiceSerie.create(value)),
"serie", "serie",
errors errors
); );
@ -123,19 +123,19 @@ export class SequelizeProformaListMapper
); );
const operationDate = extractOrPushError( const operationDate = extractOrPushError(
maybeFromNullableVO(raw.operation_date, (value) => UtcDate.createFromISO(value)), maybeFromNullableResult(raw.operation_date, (value) => UtcDate.createFromISO(value)),
"operation_date", "operation_date",
errors errors
); );
const reference = extractOrPushError( const reference = extractOrPushError(
maybeFromNullableVO(raw.reference, (value) => Result.ok(String(value))), maybeFromNullableResult(raw.reference, (value) => Result.ok(String(value))),
"description", "description",
errors errors
); );
const description = extractOrPushError( const description = extractOrPushError(
maybeFromNullableVO(raw.description, (value) => Result.ok(String(value))), maybeFromNullableResult(raw.description, (value) => Result.ok(String(value))),
"description", "description",
errors errors
); );

View File

@ -1,5 +1,5 @@
import { Presenter } from "@erp/core/api"; import { Presenter } from "@erp/core/api";
import { toEmptyString } from "@repo/rdx-ddd"; import { maybeToEmptyString } from "@repo/rdx-ddd";
import type { GetCustomerByIdResponseDTO } from "../../../../common/dto"; import type { GetCustomerByIdResponseDTO } from "../../../../common/dto";
import type { Customer } from "../../../domain"; import type { Customer } from "../../../domain";
@ -12,33 +12,35 @@ export class CustomerFullPresenter extends Presenter<Customer, GetCustomerByIdRe
id: customer.id.toPrimitive(), id: customer.id.toPrimitive(),
company_id: customer.companyId.toPrimitive(), company_id: customer.companyId.toPrimitive(),
reference: toEmptyString(customer.reference, (value) => value.toPrimitive()), reference: maybeToEmptyString(customer.reference, (value) => value.toPrimitive()),
is_company: String(customer.isCompany), is_company: String(customer.isCompany),
name: customer.name.toPrimitive(), name: customer.name.toPrimitive(),
trade_name: toEmptyString(customer.tradeName, (value) => value.toPrimitive()), trade_name: maybeToEmptyString(customer.tradeName, (value) => value.toPrimitive()),
tin: toEmptyString(customer.tin, (value) => value.toPrimitive()), tin: maybeToEmptyString(customer.tin, (value) => value.toPrimitive()),
street: toEmptyString(address.street, (value) => value.toPrimitive()), street: maybeToEmptyString(address.street, (value) => value.toPrimitive()),
street2: toEmptyString(address.street2, (value) => value.toPrimitive()), street2: maybeToEmptyString(address.street2, (value) => value.toPrimitive()),
city: toEmptyString(address.city, (value) => value.toPrimitive()), city: maybeToEmptyString(address.city, (value) => value.toPrimitive()),
province: toEmptyString(address.province, (value) => value.toPrimitive()), province: maybeToEmptyString(address.province, (value) => value.toPrimitive()),
postal_code: toEmptyString(address.postalCode, (value) => value.toPrimitive()), postal_code: maybeToEmptyString(address.postalCode, (value) => value.toPrimitive()),
country: toEmptyString(address.country, (value) => value.toPrimitive()), country: maybeToEmptyString(address.country, (value) => value.toPrimitive()),
email_primary: toEmptyString(customer.emailPrimary, (value) => value.toPrimitive()), email_primary: maybeToEmptyString(customer.emailPrimary, (value) => value.toPrimitive()),
email_secondary: toEmptyString(customer.emailSecondary, (value) => value.toPrimitive()), email_secondary: maybeToEmptyString(customer.emailSecondary, (value) => value.toPrimitive()),
phone_primary: toEmptyString(customer.phonePrimary, (value) => value.toPrimitive()), phone_primary: maybeToEmptyString(customer.phonePrimary, (value) => value.toPrimitive()),
phone_secondary: toEmptyString(customer.phoneSecondary, (value) => value.toPrimitive()), phone_secondary: maybeToEmptyString(customer.phoneSecondary, (value) => value.toPrimitive()),
mobile_primary: toEmptyString(customer.mobilePrimary, (value) => value.toPrimitive()), mobile_primary: maybeToEmptyString(customer.mobilePrimary, (value) => value.toPrimitive()),
mobile_secondary: toEmptyString(customer.mobileSecondary, (value) => value.toPrimitive()), mobile_secondary: maybeToEmptyString(customer.mobileSecondary, (value) =>
value.toPrimitive()
),
fax: toEmptyString(customer.fax, (value) => value.toPrimitive()), fax: maybeToEmptyString(customer.fax, (value) => value.toPrimitive()),
website: toEmptyString(customer.website, (value) => value.toPrimitive()), website: maybeToEmptyString(customer.website, (value) => value.toPrimitive()),
legal_record: toEmptyString(customer.legalRecord, (value) => value.toPrimitive()), legal_record: maybeToEmptyString(customer.legalRecord, (value) => value.toPrimitive()),
default_taxes: customer.defaultTaxes.getAll().map((tax) => tax.toString()), default_taxes: customer.defaultTaxes.getAll().map((tax) => tax.toString()),

View File

@ -1,7 +1,7 @@
import type { CriteriaDTO } from "@erp/core"; import type { CriteriaDTO } from "@erp/core";
import { Presenter } from "@erp/core/api"; import { Presenter } from "@erp/core/api";
import type { Criteria } from "@repo/rdx-criteria/server"; import type { Criteria } from "@repo/rdx-criteria/server";
import { toEmptyString } from "@repo/rdx-ddd"; import { maybeToEmptyString } from "@repo/rdx-ddd";
import type { Collection } from "@repo/rdx-utils"; import type { Collection } from "@repo/rdx-utils";
import type { ListCustomersResponseDTO } from "../../../../common/dto"; import type { ListCustomersResponseDTO } from "../../../../common/dto";
@ -15,31 +15,33 @@ export class ListCustomersPresenter extends Presenter {
id: customer.id.toPrimitive(), id: customer.id.toPrimitive(),
company_id: customer.companyId.toPrimitive(), company_id: customer.companyId.toPrimitive(),
reference: toEmptyString(customer.reference, (value) => value.toPrimitive()), reference: maybeToEmptyString(customer.reference, (value) => value.toPrimitive()),
is_company: String(customer.isCompany), is_company: String(customer.isCompany),
name: customer.name.toPrimitive(), name: customer.name.toPrimitive(),
trade_name: toEmptyString(customer.tradeName, (value) => value.toPrimitive()), trade_name: maybeToEmptyString(customer.tradeName, (value) => value.toPrimitive()),
tin: toEmptyString(customer.tin, (value) => value.toPrimitive()), tin: maybeToEmptyString(customer.tin, (value) => value.toPrimitive()),
street: toEmptyString(address.street, (value) => value.toPrimitive()), street: maybeToEmptyString(address.street, (value) => value.toPrimitive()),
street2: toEmptyString(address.street2, (value) => value.toPrimitive()), street2: maybeToEmptyString(address.street2, (value) => value.toPrimitive()),
city: toEmptyString(address.city, (value) => value.toPrimitive()), city: maybeToEmptyString(address.city, (value) => value.toPrimitive()),
province: toEmptyString(address.province, (value) => value.toPrimitive()), province: maybeToEmptyString(address.province, (value) => value.toPrimitive()),
postal_code: toEmptyString(address.postalCode, (value) => value.toPrimitive()), postal_code: maybeToEmptyString(address.postalCode, (value) => value.toPrimitive()),
country: toEmptyString(address.country, (value) => value.toPrimitive()), country: maybeToEmptyString(address.country, (value) => value.toPrimitive()),
email_primary: toEmptyString(customer.emailPrimary, (value) => value.toPrimitive()), email_primary: maybeToEmptyString(customer.emailPrimary, (value) => value.toPrimitive()),
email_secondary: toEmptyString(customer.emailSecondary, (value) => value.toPrimitive()), email_secondary: maybeToEmptyString(customer.emailSecondary, (value) => value.toPrimitive()),
phone_primary: toEmptyString(customer.phonePrimary, (value) => value.toPrimitive()), phone_primary: maybeToEmptyString(customer.phonePrimary, (value) => value.toPrimitive()),
phone_secondary: toEmptyString(customer.phoneSecondary, (value) => value.toPrimitive()), phone_secondary: maybeToEmptyString(customer.phoneSecondary, (value) => value.toPrimitive()),
mobile_primary: toEmptyString(customer.mobilePrimary, (value) => value.toPrimitive()), mobile_primary: maybeToEmptyString(customer.mobilePrimary, (value) => value.toPrimitive()),
mobile_secondary: toEmptyString(customer.mobileSecondary, (value) => value.toPrimitive()), mobile_secondary: maybeToEmptyString(customer.mobileSecondary, (value) =>
value.toPrimitive()
),
fax: toEmptyString(customer.fax, (value) => value.toPrimitive()), fax: maybeToEmptyString(customer.fax, (value) => value.toPrimitive()),
website: toEmptyString(customer.website, (value) => value.toPrimitive()), website: maybeToEmptyString(customer.website, (value) => value.toPrimitive()),
status: customer.status ? "active" : "inactive", status: customer.status ? "active" : "inactive",
language_code: customer.languageCode.toPrimitive(), language_code: customer.languageCode.toPrimitive(),

View File

@ -17,13 +17,14 @@ import {
URLAddress, URLAddress,
UniqueID, UniqueID,
ValidationErrorCollection, ValidationErrorCollection,
ValidationErrorDetail, type ValidationErrorDetail,
extractOrPushError, extractOrPushError,
maybeFromNullableVO, maybeFromNullableResult,
} from "@repo/rdx-ddd"; } from "@repo/rdx-ddd";
import { Collection, Result, isNullishOrEmpty } from "@repo/rdx-utils"; import { Collection, Result, isNullishOrEmpty } from "@repo/rdx-utils";
import { CreateCustomerRequestDTO } from "../../../../common";
import { CustomerProps, CustomerStatus } from "../../../domain"; import type { CreateCustomerRequestDTO } from "../../../../common";
import { type CustomerProps, CustomerStatus } from "../../../domain";
/** /**
* Convierte el DTO a las props validadas (CustomerProps). * Convierte el DTO a las props validadas (CustomerProps).
@ -45,7 +46,7 @@ export function mapDTOToCreateCustomerProps(dto: CreateCustomerRequestDTO) {
const isCompany = dto.is_company === "true"; const isCompany = dto.is_company === "true";
const reference = extractOrPushError( const reference = extractOrPushError(
maybeFromNullableVO(dto.reference, (value) => Name.create(value)), maybeFromNullableResult(dto.reference, (value) => Name.create(value)),
"reference", "reference",
errors errors
); );
@ -53,103 +54,103 @@ export function mapDTOToCreateCustomerProps(dto: CreateCustomerRequestDTO) {
const name = extractOrPushError(Name.create(dto.name), "name", errors); const name = extractOrPushError(Name.create(dto.name), "name", errors);
const tradeName = extractOrPushError( const tradeName = extractOrPushError(
maybeFromNullableVO(dto.trade_name, (value) => Name.create(value)), maybeFromNullableResult(dto.trade_name, (value) => Name.create(value)),
"trade_name", "trade_name",
errors errors
); );
const tinNumber = extractOrPushError( const tinNumber = extractOrPushError(
maybeFromNullableVO(dto.tin, (value) => TINNumber.create(value)), maybeFromNullableResult(dto.tin, (value) => TINNumber.create(value)),
"tin", "tin",
errors errors
); );
const street = extractOrPushError( const street = extractOrPushError(
maybeFromNullableVO(dto.street, (value) => Street.create(value)), maybeFromNullableResult(dto.street, (value) => Street.create(value)),
"street", "street",
errors errors
); );
const street2 = extractOrPushError( const street2 = extractOrPushError(
maybeFromNullableVO(dto.street2, (value) => Street.create(value)), maybeFromNullableResult(dto.street2, (value) => Street.create(value)),
"street2", "street2",
errors errors
); );
const city = extractOrPushError( const city = extractOrPushError(
maybeFromNullableVO(dto.city, (value) => City.create(value)), maybeFromNullableResult(dto.city, (value) => City.create(value)),
"city", "city",
errors errors
); );
const province = extractOrPushError( const province = extractOrPushError(
maybeFromNullableVO(dto.province, (value) => Province.create(value)), maybeFromNullableResult(dto.province, (value) => Province.create(value)),
"province", "province",
errors errors
); );
const postalCode = extractOrPushError( const postalCode = extractOrPushError(
maybeFromNullableVO(dto.postal_code, (value) => PostalCode.create(value)), maybeFromNullableResult(dto.postal_code, (value) => PostalCode.create(value)),
"postal_code", "postal_code",
errors errors
); );
const country = extractOrPushError( const country = extractOrPushError(
maybeFromNullableVO(dto.country, (value) => Country.create(value)), maybeFromNullableResult(dto.country, (value) => Country.create(value)),
"country", "country",
errors errors
); );
const primaryEmailAddress = extractOrPushError( const primaryEmailAddress = extractOrPushError(
maybeFromNullableVO(dto.email_primary, (value) => EmailAddress.create(value)), maybeFromNullableResult(dto.email_primary, (value) => EmailAddress.create(value)),
"email_primary", "email_primary",
errors errors
); );
const secondaryEmailAddress = extractOrPushError( const secondaryEmailAddress = extractOrPushError(
maybeFromNullableVO(dto.email_secondary, (value) => EmailAddress.create(value)), maybeFromNullableResult(dto.email_secondary, (value) => EmailAddress.create(value)),
"email_secondary", "email_secondary",
errors errors
); );
const primaryPhoneNumber = extractOrPushError( const primaryPhoneNumber = extractOrPushError(
maybeFromNullableVO(dto.phone_primary, (value) => PhoneNumber.create(value)), maybeFromNullableResult(dto.phone_primary, (value) => PhoneNumber.create(value)),
"phone_primary", "phone_primary",
errors errors
); );
const secondaryPhoneNumber = extractOrPushError( const secondaryPhoneNumber = extractOrPushError(
maybeFromNullableVO(dto.phone_secondary, (value) => PhoneNumber.create(value)), maybeFromNullableResult(dto.phone_secondary, (value) => PhoneNumber.create(value)),
"phone_secondary", "phone_secondary",
errors errors
); );
const primaryMobileNumber = extractOrPushError( const primaryMobileNumber = extractOrPushError(
maybeFromNullableVO(dto.mobile_primary, (value) => PhoneNumber.create(value)), maybeFromNullableResult(dto.mobile_primary, (value) => PhoneNumber.create(value)),
"mobile_primary", "mobile_primary",
errors errors
); );
const secondaryMobileNumber = extractOrPushError( const secondaryMobileNumber = extractOrPushError(
maybeFromNullableVO(dto.mobile_secondary, (value) => PhoneNumber.create(value)), maybeFromNullableResult(dto.mobile_secondary, (value) => PhoneNumber.create(value)),
"mobile_secondary", "mobile_secondary",
errors errors
); );
const faxNumber = extractOrPushError( const faxNumber = extractOrPushError(
maybeFromNullableVO(dto.fax, (value) => PhoneNumber.create(value)), maybeFromNullableResult(dto.fax, (value) => PhoneNumber.create(value)),
"fax", "fax",
errors errors
); );
const website = extractOrPushError( const website = extractOrPushError(
maybeFromNullableVO(dto.website, (value) => URLAddress.create(value)), maybeFromNullableResult(dto.website, (value) => URLAddress.create(value)),
"website", "website",
errors errors
); );
const legalRecord = extractOrPushError( const legalRecord = extractOrPushError(
maybeFromNullableVO(dto.legal_record, (value) => TextValue.create(value)), maybeFromNullableResult(dto.legal_record, (value) => TextValue.create(value)),
"legal_record", "legal_record",
errors errors
); );

View File

@ -1,21 +1,13 @@
import {
DomainError,
ValidationErrorCollection,
ValidationErrorDetail,
extractOrPushError,
} from "@repo/rdx-ddd";
import { UpdateCustomerByIdRequestDTO } from "../../../../common";
import { CustomerPatchProps } from "../../../domain";
import { import {
City, City,
Country, Country,
CurrencyCode, CurrencyCode,
DomainError,
EmailAddress, EmailAddress,
LanguageCode, LanguageCode,
Name, Name,
PhoneNumber, PhoneNumber,
PostalAddressPatchProps, type PostalAddressPatchProps,
PostalCode, PostalCode,
Province, Province,
Street, Street,
@ -23,10 +15,16 @@ import {
TaxCode, TaxCode,
TextValue, TextValue,
URLAddress, URLAddress,
maybeFromNullableVO, ValidationErrorCollection,
type ValidationErrorDetail,
extractOrPushError,
maybeFromNullableResult,
} from "@repo/rdx-ddd"; } from "@repo/rdx-ddd";
import { Collection, Result, isNullishOrEmpty, toPatchField } from "@repo/rdx-utils"; import { Collection, Result, isNullishOrEmpty, toPatchField } from "@repo/rdx-utils";
import type { UpdateCustomerByIdRequestDTO } from "../../../../common";
import type { CustomerPatchProps } from "../../../domain";
/** /**
* mapDTOToUpdateCustomerPatchProps * mapDTOToUpdateCustomerPatchProps
* Convierte el DTO a las props validadas (CustomerProps). * Convierte el DTO a las props validadas (CustomerProps).
@ -48,7 +46,7 @@ export function mapDTOToUpdateCustomerPatchProps(dto: UpdateCustomerByIdRequestD
toPatchField(dto.reference).ifSet((reference) => { toPatchField(dto.reference).ifSet((reference) => {
customerPatchProps.reference = extractOrPushError( customerPatchProps.reference = extractOrPushError(
maybeFromNullableVO(reference, (value) => Name.create(value)), maybeFromNullableResult(reference, (value) => Name.create(value)),
"reference", "reference",
errors errors
); );
@ -76,7 +74,7 @@ export function mapDTOToUpdateCustomerPatchProps(dto: UpdateCustomerByIdRequestD
toPatchField(dto.trade_name).ifSet((trade_name) => { toPatchField(dto.trade_name).ifSet((trade_name) => {
customerPatchProps.tradeName = extractOrPushError( customerPatchProps.tradeName = extractOrPushError(
maybeFromNullableVO(trade_name, (value) => Name.create(value)), maybeFromNullableResult(trade_name, (value) => Name.create(value)),
"trade_name", "trade_name",
errors errors
); );
@ -84,7 +82,7 @@ export function mapDTOToUpdateCustomerPatchProps(dto: UpdateCustomerByIdRequestD
toPatchField(dto.tin).ifSet((tin) => { toPatchField(dto.tin).ifSet((tin) => {
customerPatchProps.tin = extractOrPushError( customerPatchProps.tin = extractOrPushError(
maybeFromNullableVO(tin, (value) => TINNumber.create(value)), maybeFromNullableResult(tin, (value) => TINNumber.create(value)),
"tin", "tin",
errors errors
); );
@ -92,7 +90,7 @@ export function mapDTOToUpdateCustomerPatchProps(dto: UpdateCustomerByIdRequestD
toPatchField(dto.email_primary).ifSet((email_primary) => { toPatchField(dto.email_primary).ifSet((email_primary) => {
customerPatchProps.emailPrimary = extractOrPushError( customerPatchProps.emailPrimary = extractOrPushError(
maybeFromNullableVO(email_primary, (value) => EmailAddress.create(value)), maybeFromNullableResult(email_primary, (value) => EmailAddress.create(value)),
"email_primary", "email_primary",
errors errors
); );
@ -100,7 +98,7 @@ export function mapDTOToUpdateCustomerPatchProps(dto: UpdateCustomerByIdRequestD
toPatchField(dto.email_secondary).ifSet((email_secondary) => { toPatchField(dto.email_secondary).ifSet((email_secondary) => {
customerPatchProps.emailSecondary = extractOrPushError( customerPatchProps.emailSecondary = extractOrPushError(
maybeFromNullableVO(email_secondary, (value) => EmailAddress.create(value)), maybeFromNullableResult(email_secondary, (value) => EmailAddress.create(value)),
"email_secondary", "email_secondary",
errors errors
); );
@ -108,7 +106,7 @@ export function mapDTOToUpdateCustomerPatchProps(dto: UpdateCustomerByIdRequestD
toPatchField(dto.mobile_primary).ifSet((mobile_primary) => { toPatchField(dto.mobile_primary).ifSet((mobile_primary) => {
customerPatchProps.mobilePrimary = extractOrPushError( customerPatchProps.mobilePrimary = extractOrPushError(
maybeFromNullableVO(mobile_primary, (value) => PhoneNumber.create(value)), maybeFromNullableResult(mobile_primary, (value) => PhoneNumber.create(value)),
"mobile_primary", "mobile_primary",
errors errors
); );
@ -116,7 +114,7 @@ export function mapDTOToUpdateCustomerPatchProps(dto: UpdateCustomerByIdRequestD
toPatchField(dto.mobile_secondary).ifSet((mobile_secondary) => { toPatchField(dto.mobile_secondary).ifSet((mobile_secondary) => {
customerPatchProps.mobilePrimary = extractOrPushError( customerPatchProps.mobilePrimary = extractOrPushError(
maybeFromNullableVO(mobile_secondary, (value) => PhoneNumber.create(value)), maybeFromNullableResult(mobile_secondary, (value) => PhoneNumber.create(value)),
"mobile_secondary", "mobile_secondary",
errors errors
); );
@ -124,7 +122,7 @@ export function mapDTOToUpdateCustomerPatchProps(dto: UpdateCustomerByIdRequestD
toPatchField(dto.phone_primary).ifSet((phone_primary) => { toPatchField(dto.phone_primary).ifSet((phone_primary) => {
customerPatchProps.phonePrimary = extractOrPushError( customerPatchProps.phonePrimary = extractOrPushError(
maybeFromNullableVO(phone_primary, (value) => PhoneNumber.create(value)), maybeFromNullableResult(phone_primary, (value) => PhoneNumber.create(value)),
"phone_primary", "phone_primary",
errors errors
); );
@ -132,7 +130,7 @@ export function mapDTOToUpdateCustomerPatchProps(dto: UpdateCustomerByIdRequestD
toPatchField(dto.phone_secondary).ifSet((phone_secondary) => { toPatchField(dto.phone_secondary).ifSet((phone_secondary) => {
customerPatchProps.phoneSecondary = extractOrPushError( customerPatchProps.phoneSecondary = extractOrPushError(
maybeFromNullableVO(phone_secondary, (value) => PhoneNumber.create(value)), maybeFromNullableResult(phone_secondary, (value) => PhoneNumber.create(value)),
"phone_secondary", "phone_secondary",
errors errors
); );
@ -140,7 +138,7 @@ export function mapDTOToUpdateCustomerPatchProps(dto: UpdateCustomerByIdRequestD
toPatchField(dto.fax).ifSet((fax) => { toPatchField(dto.fax).ifSet((fax) => {
customerPatchProps.fax = extractOrPushError( customerPatchProps.fax = extractOrPushError(
maybeFromNullableVO(fax, (value) => PhoneNumber.create(value)), maybeFromNullableResult(fax, (value) => PhoneNumber.create(value)),
"fax", "fax",
errors errors
); );
@ -148,7 +146,7 @@ export function mapDTOToUpdateCustomerPatchProps(dto: UpdateCustomerByIdRequestD
toPatchField(dto.website).ifSet((website) => { toPatchField(dto.website).ifSet((website) => {
customerPatchProps.website = extractOrPushError( customerPatchProps.website = extractOrPushError(
maybeFromNullableVO(website, (value) => URLAddress.create(value)), maybeFromNullableResult(website, (value) => URLAddress.create(value)),
"website", "website",
errors errors
); );
@ -156,7 +154,7 @@ export function mapDTOToUpdateCustomerPatchProps(dto: UpdateCustomerByIdRequestD
toPatchField(dto.legal_record).ifSet((legalRecord) => { toPatchField(dto.legal_record).ifSet((legalRecord) => {
customerPatchProps.legalRecord = extractOrPushError( customerPatchProps.legalRecord = extractOrPushError(
maybeFromNullableVO(legalRecord, (value) => TextValue.create(value)), maybeFromNullableResult(legalRecord, (value) => TextValue.create(value)),
"legal_record", "legal_record",
errors errors
); );
@ -231,7 +229,7 @@ function mapDTOToUpdatePostalAddressPatchProps(
toPatchField(dto.street).ifSet((street) => { toPatchField(dto.street).ifSet((street) => {
postalAddressPatchProps.street = extractOrPushError( postalAddressPatchProps.street = extractOrPushError(
maybeFromNullableVO(street, (value) => Street.create(value)), maybeFromNullableResult(street, (value) => Street.create(value)),
"street", "street",
errors errors
); );
@ -239,7 +237,7 @@ function mapDTOToUpdatePostalAddressPatchProps(
toPatchField(dto.street2).ifSet((street2) => { toPatchField(dto.street2).ifSet((street2) => {
postalAddressPatchProps.street2 = extractOrPushError( postalAddressPatchProps.street2 = extractOrPushError(
maybeFromNullableVO(street2, (value) => Street.create(value)), maybeFromNullableResult(street2, (value) => Street.create(value)),
"street2", "street2",
errors errors
); );
@ -247,7 +245,7 @@ function mapDTOToUpdatePostalAddressPatchProps(
toPatchField(dto.city).ifSet((city) => { toPatchField(dto.city).ifSet((city) => {
postalAddressPatchProps.city = extractOrPushError( postalAddressPatchProps.city = extractOrPushError(
maybeFromNullableVO(city, (value) => City.create(value)), maybeFromNullableResult(city, (value) => City.create(value)),
"city", "city",
errors errors
); );
@ -255,7 +253,7 @@ function mapDTOToUpdatePostalAddressPatchProps(
toPatchField(dto.province).ifSet((province) => { toPatchField(dto.province).ifSet((province) => {
postalAddressPatchProps.province = extractOrPushError( postalAddressPatchProps.province = extractOrPushError(
maybeFromNullableVO(province, (value) => Province.create(value)), maybeFromNullableResult(province, (value) => Province.create(value)),
"province", "province",
errors errors
); );
@ -263,7 +261,7 @@ function mapDTOToUpdatePostalAddressPatchProps(
toPatchField(dto.postal_code).ifSet((postalCode) => { toPatchField(dto.postal_code).ifSet((postalCode) => {
postalAddressPatchProps.postalCode = extractOrPushError( postalAddressPatchProps.postalCode = extractOrPushError(
maybeFromNullableVO(postalCode, (value) => PostalCode.create(value)), maybeFromNullableResult(postalCode, (value) => PostalCode.create(value)),
"postal_code", "postal_code",
errors errors
); );
@ -271,7 +269,7 @@ function mapDTOToUpdatePostalAddressPatchProps(
toPatchField(dto.country).ifSet((country) => { toPatchField(dto.country).ifSet((country) => {
postalAddressPatchProps.country = extractOrPushError( postalAddressPatchProps.country = extractOrPushError(
maybeFromNullableVO(country, (value) => Country.create(value)), maybeFromNullableResult(country, (value) => Country.create(value)),
"country", "country",
errors errors
); );

View File

@ -1,30 +1,35 @@
import { ISequelizeDomainMapper, MapperParamsType, SequelizeDomainMapper } from "@erp/core/api"; import {
type ISequelizeDomainMapper,
type MapperParamsType,
SequelizeDomainMapper,
} from "@erp/core/api";
import { import {
City, City,
Country, Country,
CurrencyCode, CurrencyCode,
EmailAddress, EmailAddress,
extractOrPushError,
LanguageCode, LanguageCode,
maybeFromNullableVO,
Name, Name,
PhoneNumber, PhoneNumber,
PostalAddress, PostalAddress,
PostalCode, PostalCode,
Province, Province,
Street, Street,
TINNumber,
TaxCode, TaxCode,
TextValue, TextValue,
TINNumber,
toNullable,
UniqueID,
URLAddress, URLAddress,
UniqueID,
ValidationErrorCollection, ValidationErrorCollection,
ValidationErrorDetail, type ValidationErrorDetail,
extractOrPushError,
maybeFromNullableResult,
maybeToNullable,
} from "@repo/rdx-ddd"; } from "@repo/rdx-ddd";
import { Collection, isNullishOrEmpty, Result } from "@repo/rdx-utils"; import { Collection, Result, isNullishOrEmpty } from "@repo/rdx-utils";
import { Customer, CustomerProps, CustomerStatus } from "../../../domain";
import { CustomerCreationAttributes, CustomerModel } from "../../sequelize"; import { Customer, type CustomerProps, CustomerStatus } from "../../../domain";
import type { CustomerCreationAttributes, CustomerModel } from "../../sequelize";
export interface ICustomerDomainMapper export interface ICustomerDomainMapper
extends ISequelizeDomainMapper<CustomerModel, CustomerCreationAttributes, Customer> {} extends ISequelizeDomainMapper<CustomerModel, CustomerCreationAttributes, Customer> {}
@ -47,7 +52,7 @@ export class CustomerDomainMapper
const isCompany = source.is_company; const isCompany = source.is_company;
const status = extractOrPushError(CustomerStatus.create(source.status), "status", errors); const status = extractOrPushError(CustomerStatus.create(source.status), "status", errors);
const reference = extractOrPushError( const reference = extractOrPushError(
maybeFromNullableVO(source.reference, (value) => Name.create(value)), maybeFromNullableResult(source.reference, (value) => Name.create(value)),
"reference", "reference",
errors errors
); );
@ -55,103 +60,103 @@ export class CustomerDomainMapper
const name = extractOrPushError(Name.create(source.name), "name", errors); const name = extractOrPushError(Name.create(source.name), "name", errors);
const tradeName = extractOrPushError( const tradeName = extractOrPushError(
maybeFromNullableVO(source.trade_name, (value) => Name.create(value)), maybeFromNullableResult(source.trade_name, (value) => Name.create(value)),
"trade_name", "trade_name",
errors errors
); );
const tinNumber = extractOrPushError( const tinNumber = extractOrPushError(
maybeFromNullableVO(source.tin, (value) => TINNumber.create(value)), maybeFromNullableResult(source.tin, (value) => TINNumber.create(value)),
"tin", "tin",
errors errors
); );
const street = extractOrPushError( const street = extractOrPushError(
maybeFromNullableVO(source.street, (value) => Street.create(value)), maybeFromNullableResult(source.street, (value) => Street.create(value)),
"street", "street",
errors errors
); );
const street2 = extractOrPushError( const street2 = extractOrPushError(
maybeFromNullableVO(source.street2, (value) => Street.create(value)), maybeFromNullableResult(source.street2, (value) => Street.create(value)),
"street2", "street2",
errors errors
); );
const city = extractOrPushError( const city = extractOrPushError(
maybeFromNullableVO(source.city, (value) => City.create(value)), maybeFromNullableResult(source.city, (value) => City.create(value)),
"city", "city",
errors errors
); );
const province = extractOrPushError( const province = extractOrPushError(
maybeFromNullableVO(source.province, (value) => Province.create(value)), maybeFromNullableResult(source.province, (value) => Province.create(value)),
"province", "province",
errors errors
); );
const postalCode = extractOrPushError( const postalCode = extractOrPushError(
maybeFromNullableVO(source.postal_code, (value) => PostalCode.create(value)), maybeFromNullableResult(source.postal_code, (value) => PostalCode.create(value)),
"postal_code", "postal_code",
errors errors
); );
const country = extractOrPushError( const country = extractOrPushError(
maybeFromNullableVO(source.country, (value) => Country.create(value)), maybeFromNullableResult(source.country, (value) => Country.create(value)),
"country", "country",
errors errors
); );
const emailPrimaryAddress = extractOrPushError( const emailPrimaryAddress = extractOrPushError(
maybeFromNullableVO(source.email_primary, (value) => EmailAddress.create(value)), maybeFromNullableResult(source.email_primary, (value) => EmailAddress.create(value)),
"email_primary", "email_primary",
errors errors
); );
const emailSecondaryAddress = extractOrPushError( const emailSecondaryAddress = extractOrPushError(
maybeFromNullableVO(source.email_secondary, (value) => EmailAddress.create(value)), maybeFromNullableResult(source.email_secondary, (value) => EmailAddress.create(value)),
"email_secondary", "email_secondary",
errors errors
); );
const phonePrimaryNumber = extractOrPushError( const phonePrimaryNumber = extractOrPushError(
maybeFromNullableVO(source.phone_primary, (value) => PhoneNumber.create(value)), maybeFromNullableResult(source.phone_primary, (value) => PhoneNumber.create(value)),
"phone_primary", "phone_primary",
errors errors
); );
const phoneSecondaryNumber = extractOrPushError( const phoneSecondaryNumber = extractOrPushError(
maybeFromNullableVO(source.phone_secondary, (value) => PhoneNumber.create(value)), maybeFromNullableResult(source.phone_secondary, (value) => PhoneNumber.create(value)),
"phone_secondary", "phone_secondary",
errors errors
); );
const mobilePrimaryNumber = extractOrPushError( const mobilePrimaryNumber = extractOrPushError(
maybeFromNullableVO(source.mobile_primary, (value) => PhoneNumber.create(value)), maybeFromNullableResult(source.mobile_primary, (value) => PhoneNumber.create(value)),
"mobile_primary", "mobile_primary",
errors errors
); );
const mobileSecondaryNumber = extractOrPushError( const mobileSecondaryNumber = extractOrPushError(
maybeFromNullableVO(source.mobile_secondary, (value) => PhoneNumber.create(value)), maybeFromNullableResult(source.mobile_secondary, (value) => PhoneNumber.create(value)),
"mobile_secondary", "mobile_secondary",
errors errors
); );
const faxNumber = extractOrPushError( const faxNumber = extractOrPushError(
maybeFromNullableVO(source.fax, (value) => PhoneNumber.create(value)), maybeFromNullableResult(source.fax, (value) => PhoneNumber.create(value)),
"fax", "fax",
errors errors
); );
const website = extractOrPushError( const website = extractOrPushError(
maybeFromNullableVO(source.website, (value) => URLAddress.create(value)), maybeFromNullableResult(source.website, (value) => URLAddress.create(value)),
"website", "website",
errors errors
); );
const legalRecord = extractOrPushError( const legalRecord = extractOrPushError(
maybeFromNullableVO(source.legal_record, (value) => TextValue.create(value)), maybeFromNullableResult(source.legal_record, (value) => TextValue.create(value)),
"legal_record", "legal_record",
errors errors
); );
@ -241,22 +246,22 @@ export class CustomerDomainMapper
id: source.id.toPrimitive(), id: source.id.toPrimitive(),
company_id: source.companyId.toPrimitive(), company_id: source.companyId.toPrimitive(),
reference: toNullable(source.reference, (reference) => reference.toPrimitive()), reference: maybeToNullable(source.reference, (reference) => reference.toPrimitive()),
is_company: source.isCompany, is_company: source.isCompany,
name: source.name.toPrimitive(), name: source.name.toPrimitive(),
trade_name: toNullable(source.tradeName, (tradeName) => tradeName.toPrimitive()), trade_name: maybeToNullable(source.tradeName, (tradeName) => tradeName.toPrimitive()),
tin: toNullable(source.tin, (tin) => tin.toPrimitive()), tin: maybeToNullable(source.tin, (tin) => tin.toPrimitive()),
email_primary: toNullable(source.emailPrimary, (email) => email.toPrimitive()), email_primary: maybeToNullable(source.emailPrimary, (email) => email.toPrimitive()),
email_secondary: toNullable(source.emailSecondary, (email) => email.toPrimitive()), email_secondary: maybeToNullable(source.emailSecondary, (email) => email.toPrimitive()),
phone_primary: toNullable(source.phonePrimary, (phone) => phone.toPrimitive()), phone_primary: maybeToNullable(source.phonePrimary, (phone) => phone.toPrimitive()),
phone_secondary: toNullable(source.phoneSecondary, (phone) => phone.toPrimitive()), phone_secondary: maybeToNullable(source.phoneSecondary, (phone) => phone.toPrimitive()),
mobile_primary: toNullable(source.mobilePrimary, (mobile) => mobile.toPrimitive()), mobile_primary: maybeToNullable(source.mobilePrimary, (mobile) => mobile.toPrimitive()),
mobile_secondary: toNullable(source.mobileSecondary, (mobile) => mobile.toPrimitive()), mobile_secondary: maybeToNullable(source.mobileSecondary, (mobile) => mobile.toPrimitive()),
fax: toNullable(source.fax, (fax) => fax.toPrimitive()), fax: maybeToNullable(source.fax, (fax) => fax.toPrimitive()),
website: toNullable(source.website, (website) => website.toPrimitive()), website: maybeToNullable(source.website, (website) => website.toPrimitive()),
legal_record: toNullable(source.legalRecord, (legalRecord) => legalRecord.toPrimitive()), legal_record: maybeToNullable(source.legalRecord, (legalRecord) => legalRecord.toPrimitive()),
default_taxes: source.defaultTaxes.map((taxItem) => taxItem.toPrimitive()).join(", "), default_taxes: source.defaultTaxes.map((taxItem) => taxItem.toPrimitive()).join(", "),
status: source.isActive ? "active" : "inactive", status: source.isActive ? "active" : "inactive",
@ -266,14 +271,14 @@ export class CustomerDomainMapper
if (source.address) { if (source.address) {
Object.assign(customerValues, { Object.assign(customerValues, {
street: toNullable(source.address.street, (street) => street.toPrimitive()), street: maybeToNullable(source.address.street, (street) => street.toPrimitive()),
street2: toNullable(source.address.street2, (street2) => street2.toPrimitive()), street2: maybeToNullable(source.address.street2, (street2) => street2.toPrimitive()),
city: toNullable(source.address.city, (city) => city.toPrimitive()), city: maybeToNullable(source.address.city, (city) => city.toPrimitive()),
province: toNullable(source.address.province, (province) => province.toPrimitive()), province: maybeToNullable(source.address.province, (province) => province.toPrimitive()),
postal_code: toNullable(source.address.postalCode, (postalCode) => postal_code: maybeToNullable(source.address.postalCode, (postalCode) =>
postalCode.toPrimitive() postalCode.toPrimitive()
), ),
country: toNullable(source.address.country, (country) => country.toPrimitive()), country: maybeToNullable(source.address.country, (country) => country.toPrimitive()),
}); });
} }

View File

@ -1,5 +1,8 @@
import { ValidationErrorCollection, ValidationErrorDetail } from "@repo/rdx-ddd"; import {
type ISequelizeQueryMapper,
type MapperParamsType,
SequelizeQueryMapper,
} from "@erp/core/api";
import { import {
City, City,
Country, Country,
@ -16,15 +19,15 @@ import {
TextValue, TextValue,
URLAddress, URLAddress,
UniqueID, UniqueID,
ValidationErrorCollection,
type ValidationErrorDetail,
extractOrPushError, extractOrPushError,
maybeFromNullableVO, maybeFromNullableResult,
} from "@repo/rdx-ddd"; } from "@repo/rdx-ddd";
import { type Maybe, Result } from "@repo/rdx-utils";
import { ISequelizeQueryMapper, MapperParamsType, SequelizeQueryMapper } from "@erp/core/api";
import { Maybe, Result } from "@repo/rdx-utils";
import { CustomerStatus } from "../../../domain"; import { CustomerStatus } from "../../../domain";
import { CustomerModel } from "../../sequelize"; import type { CustomerModel } from "../../sequelize";
export type CustomerListDTO = { export type CustomerListDTO = {
id: UniqueID; id: UniqueID;
@ -70,7 +73,7 @@ export class CustomerListMapper
const isCompany = raw.is_company; const isCompany = raw.is_company;
const status = extractOrPushError(CustomerStatus.create(raw.status), "status", errors); const status = extractOrPushError(CustomerStatus.create(raw.status), "status", errors);
const reference = extractOrPushError( const reference = extractOrPushError(
maybeFromNullableVO(raw.reference, (value) => Name.create(value)), maybeFromNullableResult(raw.reference, (value) => Name.create(value)),
"reference", "reference",
errors errors
); );
@ -78,103 +81,103 @@ export class CustomerListMapper
const name = extractOrPushError(Name.create(raw.name), "name", errors); const name = extractOrPushError(Name.create(raw.name), "name", errors);
const tradeName = extractOrPushError( const tradeName = extractOrPushError(
maybeFromNullableVO(raw.trade_name, (value) => Name.create(value)), maybeFromNullableResult(raw.trade_name, (value) => Name.create(value)),
"trade_name", "trade_name",
errors errors
); );
const tinNumber = extractOrPushError( const tinNumber = extractOrPushError(
maybeFromNullableVO(raw.tin, (value) => TINNumber.create(value)), maybeFromNullableResult(raw.tin, (value) => TINNumber.create(value)),
"tin", "tin",
errors errors
); );
const street = extractOrPushError( const street = extractOrPushError(
maybeFromNullableVO(raw.street, (value) => Street.create(value)), maybeFromNullableResult(raw.street, (value) => Street.create(value)),
"street", "street",
errors errors
); );
const street2 = extractOrPushError( const street2 = extractOrPushError(
maybeFromNullableVO(raw.street2, (value) => Street.create(value)), maybeFromNullableResult(raw.street2, (value) => Street.create(value)),
"street2", "street2",
errors errors
); );
const city = extractOrPushError( const city = extractOrPushError(
maybeFromNullableVO(raw.city, (value) => City.create(value)), maybeFromNullableResult(raw.city, (value) => City.create(value)),
"city", "city",
errors errors
); );
const province = extractOrPushError( const province = extractOrPushError(
maybeFromNullableVO(raw.province, (value) => Province.create(value)), maybeFromNullableResult(raw.province, (value) => Province.create(value)),
"province", "province",
errors errors
); );
const postalCode = extractOrPushError( const postalCode = extractOrPushError(
maybeFromNullableVO(raw.postal_code, (value) => PostalCode.create(value)), maybeFromNullableResult(raw.postal_code, (value) => PostalCode.create(value)),
"postal_code", "postal_code",
errors errors
); );
const country = extractOrPushError( const country = extractOrPushError(
maybeFromNullableVO(raw.country, (value) => Country.create(value)), maybeFromNullableResult(raw.country, (value) => Country.create(value)),
"country", "country",
errors errors
); );
const emailPrimaryAddress = extractOrPushError( const emailPrimaryAddress = extractOrPushError(
maybeFromNullableVO(raw.email_primary, (value) => EmailAddress.create(value)), maybeFromNullableResult(raw.email_primary, (value) => EmailAddress.create(value)),
"email_primary", "email_primary",
errors errors
); );
const emailSecondaryAddress = extractOrPushError( const emailSecondaryAddress = extractOrPushError(
maybeFromNullableVO(raw.email_secondary, (value) => EmailAddress.create(value)), maybeFromNullableResult(raw.email_secondary, (value) => EmailAddress.create(value)),
"email_secondary", "email_secondary",
errors errors
); );
const phonePrimaryNumber = extractOrPushError( const phonePrimaryNumber = extractOrPushError(
maybeFromNullableVO(raw.phone_primary, (value) => PhoneNumber.create(value)), maybeFromNullableResult(raw.phone_primary, (value) => PhoneNumber.create(value)),
"phone_primary", "phone_primary",
errors errors
); );
const phoneSecondaryNumber = extractOrPushError( const phoneSecondaryNumber = extractOrPushError(
maybeFromNullableVO(raw.phone_secondary, (value) => PhoneNumber.create(value)), maybeFromNullableResult(raw.phone_secondary, (value) => PhoneNumber.create(value)),
"phone_secondary", "phone_secondary",
errors errors
); );
const mobilePrimaryNumber = extractOrPushError( const mobilePrimaryNumber = extractOrPushError(
maybeFromNullableVO(raw.mobile_primary, (value) => PhoneNumber.create(value)), maybeFromNullableResult(raw.mobile_primary, (value) => PhoneNumber.create(value)),
"mobile_primary", "mobile_primary",
errors errors
); );
const mobileSecondaryNumber = extractOrPushError( const mobileSecondaryNumber = extractOrPushError(
maybeFromNullableVO(raw.mobile_secondary, (value) => PhoneNumber.create(value)), maybeFromNullableResult(raw.mobile_secondary, (value) => PhoneNumber.create(value)),
"mobile_secondary", "mobile_secondary",
errors errors
); );
const faxNumber = extractOrPushError( const faxNumber = extractOrPushError(
maybeFromNullableVO(raw.fax, (value) => PhoneNumber.create(value)), maybeFromNullableResult(raw.fax, (value) => PhoneNumber.create(value)),
"fax", "fax",
errors errors
); );
const website = extractOrPushError( const website = extractOrPushError(
maybeFromNullableVO(raw.website, (value) => URLAddress.create(value)), maybeFromNullableResult(raw.website, (value) => URLAddress.create(value)),
"website", "website",
errors errors
); );
const legalRecord = extractOrPushError( const legalRecord = extractOrPushError(
maybeFromNullableVO(raw.legal_record, (value) => TextValue.create(value)), maybeFromNullableResult(raw.legal_record, (value) => TextValue.create(value)),
"legal_record", "legal_record",
errors errors
); );

View File

@ -3,37 +3,37 @@
import { Maybe, Result, isNullishOrEmpty } from "@repo/rdx-utils"; import { Maybe, Result, isNullishOrEmpty } from "@repo/rdx-utils";
/** any | null | undefined -> Maybe<T> usando fábrica VO */ /** any | null | undefined -> Maybe<T> usando validación */
export function maybeFromNullableVO<T>( export function maybeFromNullableResult<T>(
input: any, input: any,
voFactory: (raw: any) => Result<T> validate: (raw: any) => Result<T>
): Result<Maybe<T>> { ): Result<Maybe<T>> {
if (isNullishOrEmpty(input)) return Result.ok(Maybe.none<T>()); if (isNullishOrEmpty(input)) return Result.ok(Maybe.none<T>());
const vo = voFactory(input); const value = validate(input);
return vo.isSuccess ? Result.ok(Maybe.some(vo.data)) : Result.fail(vo.error); return value.isSuccess ? Result.ok(Maybe.some(value.data)) : Result.fail(value.error);
} }
/** string | null | undefined -> Maybe<string> (trim, vacío => None) */ /** string | null | undefined -> Maybe<string> (trim, vacío => None) */
export function maybeFromNullableString(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>();
const t = (input as string).trim(); const t = input as string;
return t ? Maybe.some(t) : Maybe.none<string>(); return t ? Maybe.some(t) : Maybe.none<string>();
} }
/** Maybe<T> -> null para transporte */ /** Maybe<T> -> null para transporte */
export function toNullable<T, R>(m: Maybe<T>, map: (t: T) => R): R | null { export function maybeToNullable<T, R>(m: Maybe<T>, map: (t: T) => R): R | null {
if (!m || m.isNone()) return null; if (!m || m.isNone()) return null;
return map(m.unwrap() as T); return map(m.unwrap() as T);
} }
export function toNullable2<T>(m: Maybe<T>, map?: (t: T) => unknown): unknown | null { export function maybeToNullableString<T>(m: Maybe<T>, map?: (t: T) => string): string | null {
if (!m || m.isNone()) return null; if (!m || m.isNone()) return null;
const v = m.unwrap() as T; const v = m.unwrap() as T;
return map ? String(map(v)) : String(v); return map ? String(map(v)) : String(v);
} }
/** Maybe<T> -> "" para transporte */ /** Maybe<T> -> "" para transporte */
export function toEmptyString<T>(m: Maybe<T>, map?: (t: T) => string): string { export function maybeToEmptyString<T>(m: Maybe<T>, map?: (t: T) => string): string {
if (!m || m.isNone()) return ""; if (!m || m.isNone()) return "";
const v = m.unwrap() as T; const v = m.unwrap() as T;
return map ? map(v) : String(v); return map ? map(v) : String(v);

View File

@ -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;
@ -62,6 +64,10 @@ export class Percentage extends ValueObject<PercentageProps> {
return Result.ok(new Percentage({ value, scale })); return Result.ok(new Percentage({ value, scale }));
} }
static zero() {
return Percentage.create({ value: 0, scale: Percentage.DEFAULT_SCALE }).data;
}
get value(): number { get value(): number {
return this.props.value; return this.props.value;
} }

View File

@ -1,10 +1,12 @@
import { Maybe, Result } from "@repo/rdx-utils"; import { type Maybe, Result } from "@repo/rdx-utils";
import { toEmptyString } from "../helpers";
import { City } from "./city"; import { maybeToEmptyString } from "../helpers";
import { Country } from "./country";
import { PostalCode } from "./postal-code"; import type { City } from "./city";
import { Province } from "./province"; import type { Country } from "./country";
import { Street } from "./street"; import type { PostalCode } from "./postal-code";
import type { Province } from "./province";
import type { Street } from "./street";
import { ValueObject } from "./value-object"; import { ValueObject } from "./value-object";
export interface PostalAddressProps { export interface PostalAddressProps {
@ -75,12 +77,12 @@ export class PostalAddress extends ValueObject<PostalAddressProps> {
toString() { toString() {
return { return {
street: toEmptyString(this.street, (value) => value.toString()), street: maybeToEmptyString(this.street, (value) => value.toString()),
street2: toEmptyString(this.street2, (value) => value.toString()), street2: maybeToEmptyString(this.street2, (value) => value.toString()),
city: toEmptyString(this.city, (value) => value.toString()), city: maybeToEmptyString(this.city, (value) => value.toString()),
postal_code: toEmptyString(this.postalCode, (value) => value.toString()), postal_code: maybeToEmptyString(this.postalCode, (value) => value.toString()),
province: toEmptyString(this.province, (value) => value.toString()), province: maybeToEmptyString(this.province, (value) => value.toString()),
country: toEmptyString(this.country, (value) => value.toString()), country: maybeToEmptyString(this.country, (value) => value.toString()),
}; };
} }