Poder hacer una proforma con un cliente sin TIN

This commit is contained in:
David Arranz 2026-06-28 21:43:25 +02:00
parent 4bbecb223f
commit 95fe0127a3
9 changed files with 56 additions and 38 deletions

View File

@ -1,5 +1,5 @@
import type { ISnapshotBuilder } from "@erp/core/api";
import { DomainValidationError, maybeToNullable } from "@repo/rdx-ddd";
import { DomainValidationError, maybeToEmptyString, maybeToNullable } from "@repo/rdx-ddd";
import type { IssuedInvoice } from "../../../../domain";
@ -22,7 +22,7 @@ export class IssuedInvoiceRecipientFullSnapshotBuilder
return {
id: invoice.customerId.toString(),
name: recipient.name.toString(),
tin: recipient.tin.toString(),
tin: maybeToEmptyString(recipient.tin, (v) => v.toString()),
street: maybeToNullable(recipient.street, (v) => v.toString()),
street2: maybeToNullable(recipient.street2, (v) => v.toString()),
city: maybeToNullable(recipient.city, (v) => v.toString()),

View File

@ -19,7 +19,7 @@ export class ProformaRecipientFullSnapshotBuilder implements IProformaRecipientF
(recipient: InvoiceRecipient) => ({
id: proforma.customerId.toString(),
name: recipient.name.toString(),
tin: recipient.tin.toString(),
tin: maybeToNullable(recipient.tin, (v) => v.toString()),
street: maybeToNullable(recipient.street, (v) => v.toString()),
street2: maybeToNullable(recipient.street2, (v) => v.toString()),
city: maybeToNullable(recipient.city, (v) => v.toString()),

View File

@ -13,7 +13,7 @@ import { type Maybe, Result } from "@repo/rdx-utils";
export type InvoiceRecipientProps = {
name: Name;
tin: TINNumber;
tin: Maybe<TINNumber>;
street: Maybe<Street>;
street2: Maybe<Street>;
city: Maybe<City>;
@ -50,7 +50,7 @@ export class InvoiceRecipient extends ValueObject<InvoiceRecipientProps> {
return this.props.name;
}
public get tin(): TINNumber {
public get tin(): Maybe<TINNumber> {
return this.props.tin;
}
@ -88,7 +88,7 @@ export class InvoiceRecipient extends ValueObject<InvoiceRecipientProps> {
toObjectString() {
return {
tin: this.tin.toString(),
tin: maybeToNullable(this.tin, (value) => value.toString()),
name: this.name.toString(),
street: maybeToNullable(this.street, (value) => value.toString()),
street2: maybeToNullable(this.street2, (value) => value.toString()),

View File

@ -44,7 +44,12 @@ export class SequelizeIssuedInvoiceRecipientDomainMapper {
// Customer (snapshot)
const customerName = extractOrPushError(Name.create(_name!), "customer_name", errors);
const customerTin = extractOrPushError(TINNumber.create(_tin!), "customer_tin", errors);
//const customerTin = extractOrPushError(TINNumber.create(_tin!), "customer_tin", errors);
const customerTin = extractOrPushError(
maybeFromNullableResult(_tin, (value) => TINNumber.create(value)),
"customer_tin",
errors
);
const customerStreet = extractOrPushError(
maybeFromNullableResult(_street, (value) => Street.create(value)),
@ -122,7 +127,7 @@ export class SequelizeIssuedInvoiceRecipientDomainMapper {
const recipient = source;
return {
customer_tin: recipient.tin.toPrimitive(),
customer_tin: maybeToNullable(recipient.tin, (value) => value.toString()),
customer_name: recipient.name.toPrimitive(),
customer_street: maybeToNullable(recipient.street, (v) => v.toPrimitive()),
customer_street2: maybeToNullable(recipient.street2, (v) => v.toPrimitive()),

View File

@ -229,6 +229,7 @@ export class SequelizeProformaDomainMapper extends SequelizeDomainMapper<
// 4) Si hubo errores de mapeo, devolvemos colección de validación
if (errors.length > 0) {
console.error(errors);
return Result.fail(
new ValidationErrorCollection("Customer invoice mapping failed [mapToDomain]", errors)
);

View File

@ -43,7 +43,11 @@ export class SequelizeProformaRecipientDomainMapper {
// Customer (snapshot)
const customerName = extractOrPushError(Name.create(_name!), "customer_name", errors);
const customerTin = extractOrPushError(TINNumber.create(_tin!), "customer_tin", errors);
const customerTin = extractOrPushError(
maybeFromNullableResult(_tin, (value) => TINNumber.create(value)),
"customer_tin",
errors
);
const customerStreet = extractOrPushError(
maybeFromNullableResult(_street, (value) => Street.create(value)),

View File

@ -43,19 +43,24 @@ export class SequelizeInvoiceRecipientSummaryMapper extends SequelizeQueryMapper
message: "Current customer not included in query (SequelizeInvoiceRecipientListMapper)",
});
}
const _name = raw.current_customer.name;
const _tin = raw.current_customer.tin;
const _street = raw.current_customer.street;
const _street2 = raw.current_customer.street2;
const _city = raw.current_customer.city;
const _postal_code = raw.current_customer.postal_code;
const _province = raw.current_customer.province;
const _country = raw.current_customer.country;
const _name = raw.current_customer!.name;
const _tin = raw.current_customer!.tin;
const _street = raw.current_customer!.street;
const _street2 = raw.current_customer!.street2;
const _city = raw.current_customer!.city;
const _postal_code = raw.current_customer!.postal_code;
const _province = raw.current_customer!.province;
const _country = raw.current_customer!.country;
// Customer (snapshot)
const customerName = extractOrPushError(Name.create(_name!), "customer_name", errors);
const customerTin = extractOrPushError(TINNumber.create(_tin!), "customer_tin", errors);
//const customerTin = extractOrPushError(TINNumber.create(_tin!), "customer_tin", errors);
const customerTin = extractOrPushError(
maybeFromNullableResult(_tin, (value) => TINNumber.create(value)),
"customer_tin",
errors
);
const customerStreet = extractOrPushError(
maybeFromNullableResult(_street, (value) => Street.create(value)),

View File

@ -12,7 +12,6 @@ import {
Province,
Street,
TINNumber,
type TaxCode,
TextValue,
URLAddress,
UniqueID,
@ -68,85 +67,89 @@ export class CreateCustomerInputMapper implements ICreateCustomerInputMapper {
);
const street = extractOrPushError(
maybeFromNullableResult(dto.street, (value) => Street.create(value)),
maybeFromNullableResult(dto.address.street, (value) => Street.create(value)),
"street",
errors
);
const street2 = extractOrPushError(
maybeFromNullableResult(dto.street2, (value) => Street.create(value)),
maybeFromNullableResult(dto.address.street2, (value) => Street.create(value)),
"street2",
errors
);
const city = extractOrPushError(
maybeFromNullableResult(dto.city, (value) => City.create(value)),
maybeFromNullableResult(dto.address.city, (value) => City.create(value)),
"city",
errors
);
const province = extractOrPushError(
maybeFromNullableResult(dto.province, (value) => Province.create(value)),
maybeFromNullableResult(dto.address.province, (value) => Province.create(value)),
"province",
errors
);
const postalCode = extractOrPushError(
maybeFromNullableResult(dto.postal_code, (value) => PostalCode.create(value)),
maybeFromNullableResult(dto.address.postal_code, (value) => PostalCode.create(value)),
"postal_code",
errors
);
const country = extractOrPushError(
maybeFromNullableResult(dto.country, (value) => Country.create(value)),
maybeFromNullableResult(dto.address.country, (value) => Country.create(value)),
"country",
errors
);
const primaryEmailAddress = extractOrPushError(
maybeFromNullableResult(dto.email_primary, (value) => EmailAddress.create(value)),
maybeFromNullableResult(dto.contact?.email_primary, (value) => EmailAddress.create(value)),
"email_primary",
errors
);
const secondaryEmailAddress = extractOrPushError(
maybeFromNullableResult(dto.email_secondary, (value) => EmailAddress.create(value)),
maybeFromNullableResult(dto.contact?.email_secondary, (value) =>
EmailAddress.create(value)
),
"email_secondary",
errors
);
const primaryPhoneNumber = extractOrPushError(
maybeFromNullableResult(dto.phone_primary, (value) => PhoneNumber.create(value)),
maybeFromNullableResult(dto.contact?.phone_primary, (value) => PhoneNumber.create(value)),
"phone_primary",
errors
);
const secondaryPhoneNumber = extractOrPushError(
maybeFromNullableResult(dto.phone_secondary, (value) => PhoneNumber.create(value)),
maybeFromNullableResult(dto.contact?.phone_secondary, (value) => PhoneNumber.create(value)),
"phone_secondary",
errors
);
const primaryMobileNumber = extractOrPushError(
maybeFromNullableResult(dto.mobile_primary, (value) => PhoneNumber.create(value)),
maybeFromNullableResult(dto.contact?.mobile_primary, (value) => PhoneNumber.create(value)),
"mobile_primary",
errors
);
const secondaryMobileNumber = extractOrPushError(
maybeFromNullableResult(dto.mobile_secondary, (value) => PhoneNumber.create(value)),
maybeFromNullableResult(dto.contact?.mobile_secondary, (value) =>
PhoneNumber.create(value)
),
"mobile_secondary",
errors
);
const faxNumber = extractOrPushError(
maybeFromNullableResult(dto.fax, (value) => PhoneNumber.create(value)),
maybeFromNullableResult(dto.contact?.fax, (value) => PhoneNumber.create(value)),
"fax",
errors
);
const website = extractOrPushError(
maybeFromNullableResult(dto.website, (value) => URLAddress.create(value)),
maybeFromNullableResult(dto.contact?.website, (value) => URLAddress.create(value)),
"website",
errors
);
@ -190,8 +193,6 @@ export class CreateCustomerInputMapper implements ICreateCustomerInputMapper {
errors
);
const defaultTaxes: TaxCode[] = [];
if (errors.length > 0) {
return Result.fail(new ValidationErrorCollection("Customer props mapping failed", errors));
}

View File

@ -6,14 +6,16 @@ export const useCustomerCreatePageController = () => {
const [searchParams] = useSearchParams();
const navigate = useNavigate();
const returnTo = searchParams.get("returnTo") ?? "/customers";
const createCtrl = useCustomerCreateController({
onCreated: (createdCustomer) => {
navigate(`/customers/${createdCustomer.id}/edit`);
navigate(
`/customers/${createdCustomer.id}/edit${returnTo ? `?returnTo=${encodeURIComponent(returnTo)}` : ""}`
);
},
});
const returnTo = searchParams.get("returnTo") ?? "/customers";
return {
createCtrl,
returnTo,