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 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"; import type { IssuedInvoice } from "../../../../domain";
@ -22,7 +22,7 @@ export class IssuedInvoiceRecipientFullSnapshotBuilder
return { return {
id: invoice.customerId.toString(), id: invoice.customerId.toString(),
name: recipient.name.toString(), name: recipient.name.toString(),
tin: recipient.tin.toString(), tin: maybeToEmptyString(recipient.tin, (v) => v.toString()),
street: maybeToNullable(recipient.street, (v) => v.toString()), street: maybeToNullable(recipient.street, (v) => v.toString()),
street2: maybeToNullable(recipient.street2, (v) => v.toString()), street2: maybeToNullable(recipient.street2, (v) => v.toString()),
city: maybeToNullable(recipient.city, (v) => v.toString()), city: maybeToNullable(recipient.city, (v) => v.toString()),

View File

@ -19,7 +19,7 @@ export class ProformaRecipientFullSnapshotBuilder implements IProformaRecipientF
(recipient: InvoiceRecipient) => ({ (recipient: InvoiceRecipient) => ({
id: proforma.customerId.toString(), id: proforma.customerId.toString(),
name: recipient.name.toString(), name: recipient.name.toString(),
tin: recipient.tin.toString(), tin: maybeToNullable(recipient.tin, (v) => v.toString()),
street: maybeToNullable(recipient.street, (v) => v.toString()), street: maybeToNullable(recipient.street, (v) => v.toString()),
street2: maybeToNullable(recipient.street2, (v) => v.toString()), street2: maybeToNullable(recipient.street2, (v) => v.toString()),
city: maybeToNullable(recipient.city, (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 = { export type InvoiceRecipientProps = {
name: Name; name: Name;
tin: TINNumber; tin: Maybe<TINNumber>;
street: Maybe<Street>; street: Maybe<Street>;
street2: Maybe<Street>; street2: Maybe<Street>;
city: Maybe<City>; city: Maybe<City>;
@ -50,7 +50,7 @@ export class InvoiceRecipient extends ValueObject<InvoiceRecipientProps> {
return this.props.name; return this.props.name;
} }
public get tin(): TINNumber { public get tin(): Maybe<TINNumber> {
return this.props.tin; return this.props.tin;
} }
@ -88,7 +88,7 @@ export class InvoiceRecipient extends ValueObject<InvoiceRecipientProps> {
toObjectString() { toObjectString() {
return { return {
tin: this.tin.toString(), tin: maybeToNullable(this.tin, (value) => value.toString()),
name: this.name.toString(), name: this.name.toString(),
street: maybeToNullable(this.street, (value) => value.toString()), street: maybeToNullable(this.street, (value) => value.toString()),
street2: maybeToNullable(this.street2, (value) => value.toString()), street2: maybeToNullable(this.street2, (value) => value.toString()),

View File

@ -44,7 +44,12 @@ export class SequelizeIssuedInvoiceRecipientDomainMapper {
// Customer (snapshot) // Customer (snapshot)
const customerName = extractOrPushError(Name.create(_name!), "customer_name", errors); 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( const customerStreet = extractOrPushError(
maybeFromNullableResult(_street, (value) => Street.create(value)), maybeFromNullableResult(_street, (value) => Street.create(value)),
@ -122,7 +127,7 @@ export class SequelizeIssuedInvoiceRecipientDomainMapper {
const recipient = source; const recipient = source;
return { return {
customer_tin: recipient.tin.toPrimitive(), customer_tin: maybeToNullable(recipient.tin, (value) => value.toString()),
customer_name: recipient.name.toPrimitive(), customer_name: recipient.name.toPrimitive(),
customer_street: maybeToNullable(recipient.street, (v) => v.toPrimitive()), customer_street: maybeToNullable(recipient.street, (v) => v.toPrimitive()),
customer_street2: maybeToNullable(recipient.street2, (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 // 4) Si hubo errores de mapeo, devolvemos colección de validación
if (errors.length > 0) { if (errors.length > 0) {
console.error(errors);
return Result.fail( return Result.fail(
new ValidationErrorCollection("Customer invoice mapping failed [mapToDomain]", errors) new ValidationErrorCollection("Customer invoice mapping failed [mapToDomain]", errors)
); );

View File

@ -43,7 +43,11 @@ export class SequelizeProformaRecipientDomainMapper {
// Customer (snapshot) // Customer (snapshot)
const customerName = extractOrPushError(Name.create(_name!), "customer_name", errors); 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( const customerStreet = extractOrPushError(
maybeFromNullableResult(_street, (value) => Street.create(value)), 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)", message: "Current customer not included in query (SequelizeInvoiceRecipientListMapper)",
}); });
} }
const _name = raw.current_customer.name; const _name = raw.current_customer!.name;
const _tin = raw.current_customer.tin; const _tin = raw.current_customer!.tin;
const _street = raw.current_customer.street; const _street = raw.current_customer!.street;
const _street2 = raw.current_customer.street2; const _street2 = raw.current_customer!.street2;
const _city = raw.current_customer.city; const _city = raw.current_customer!.city;
const _postal_code = raw.current_customer.postal_code; const _postal_code = raw.current_customer!.postal_code;
const _province = raw.current_customer.province; const _province = raw.current_customer!.province;
const _country = raw.current_customer.country; const _country = raw.current_customer!.country;
// Customer (snapshot) // Customer (snapshot)
const customerName = extractOrPushError(Name.create(_name!), "customer_name", errors); 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( const customerStreet = extractOrPushError(
maybeFromNullableResult(_street, (value) => Street.create(value)), maybeFromNullableResult(_street, (value) => Street.create(value)),

View File

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

View File

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