2026-03-16 17:45:45 +00:00
|
|
|
import type { JsonTaxCatalogProvider } from "@erp/core";
|
|
|
|
|
import { DiscountPercentage, Tax } from "@erp/core/api";
|
|
|
|
|
import {
|
2026-03-23 17:51:49 +00:00
|
|
|
type IProformaItemCreateProps,
|
2026-03-16 17:45:45 +00:00
|
|
|
InvoicePaymentMethod,
|
|
|
|
|
InvoiceSerie,
|
|
|
|
|
ItemAmount,
|
|
|
|
|
ItemDescription,
|
|
|
|
|
ItemQuantity,
|
|
|
|
|
type ProformaItemTaxesProps,
|
|
|
|
|
} from "@erp/customer-invoices/api/domain";
|
|
|
|
|
import {
|
|
|
|
|
City,
|
|
|
|
|
Country,
|
|
|
|
|
CurrencyCode,
|
|
|
|
|
DomainError,
|
|
|
|
|
EmailAddress,
|
|
|
|
|
LanguageCode,
|
|
|
|
|
Name,
|
|
|
|
|
PhoneNumber,
|
|
|
|
|
type PostalAddressProps,
|
|
|
|
|
PostalCode,
|
|
|
|
|
Province,
|
|
|
|
|
Street,
|
|
|
|
|
TINNumber,
|
|
|
|
|
TextValue,
|
|
|
|
|
URLAddress,
|
|
|
|
|
type UniqueID,
|
|
|
|
|
UtcDate,
|
|
|
|
|
ValidationErrorCollection,
|
|
|
|
|
type ValidationErrorDetail,
|
|
|
|
|
extractOrPushError,
|
|
|
|
|
isValidationErrorCollection,
|
|
|
|
|
maybeFromNullableResult,
|
|
|
|
|
} from "@repo/rdx-ddd";
|
|
|
|
|
import { Maybe, Result } from "@repo/rdx-utils";
|
|
|
|
|
|
|
|
|
|
import type {
|
|
|
|
|
CreateProformaFromFactugesRequestDTO,
|
|
|
|
|
CreateProformaItemFromFactugesRequestDTO,
|
|
|
|
|
} from "../../../common";
|
|
|
|
|
|
|
|
|
|
export interface IProformaFromFactuGESProps {
|
|
|
|
|
customerLookup: {
|
|
|
|
|
tin: TINNumber;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
customerDraft: {
|
|
|
|
|
//reference: Maybe<Name>;
|
|
|
|
|
|
|
|
|
|
isCompany: boolean;
|
|
|
|
|
name: Name;
|
|
|
|
|
//tradeName: Maybe<Name>;
|
|
|
|
|
tin: TINNumber;
|
|
|
|
|
|
|
|
|
|
address: PostalAddressProps;
|
|
|
|
|
|
|
|
|
|
emailPrimary: Maybe<EmailAddress>;
|
|
|
|
|
emailSecondary: Maybe<EmailAddress>;
|
|
|
|
|
|
|
|
|
|
phonePrimary: Maybe<PhoneNumber>;
|
|
|
|
|
phoneSecondary: Maybe<PhoneNumber>;
|
|
|
|
|
|
|
|
|
|
mobilePrimary: Maybe<PhoneNumber>;
|
|
|
|
|
mobileSecondary: Maybe<PhoneNumber>;
|
|
|
|
|
|
|
|
|
|
//fax: Maybe<PhoneNumber>;
|
|
|
|
|
website: Maybe<URLAddress>;
|
|
|
|
|
|
|
|
|
|
//legalRecord: Maybe<TextValue>;
|
|
|
|
|
|
|
|
|
|
//defaultTaxes: CustomerTaxesProps;
|
|
|
|
|
|
|
|
|
|
languageCode: LanguageCode;
|
|
|
|
|
currencyCode: CurrencyCode;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
proformaDraft: {
|
|
|
|
|
series: Maybe<InvoiceSerie>;
|
|
|
|
|
|
|
|
|
|
invoiceDate: UtcDate;
|
|
|
|
|
operationDate: Maybe<UtcDate>;
|
|
|
|
|
|
|
|
|
|
reference: Maybe<string>;
|
|
|
|
|
description: Maybe<string>;
|
|
|
|
|
notes: Maybe<TextValue>;
|
|
|
|
|
|
|
|
|
|
languageCode: LanguageCode;
|
|
|
|
|
currencyCode: CurrencyCode;
|
|
|
|
|
|
|
|
|
|
paymentMethod: Maybe<InvoicePaymentMethod>;
|
|
|
|
|
|
2026-03-23 17:51:49 +00:00
|
|
|
items: IProformaItemCreateProps[];
|
2026-03-16 17:45:45 +00:00
|
|
|
globalDiscountPercentage: DiscountPercentage;
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface ICreateProformaFromFactugesInputMapper {
|
|
|
|
|
map(
|
|
|
|
|
dto: CreateProformaFromFactugesRequestDTO,
|
|
|
|
|
params: { companyId: UniqueID }
|
|
|
|
|
): Result<IProformaFromFactuGESProps>;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export class CreateProformaFromFactugesInputMapper
|
|
|
|
|
implements ICreateProformaFromFactugesInputMapper
|
|
|
|
|
{
|
|
|
|
|
private readonly taxCatalog: JsonTaxCatalogProvider;
|
|
|
|
|
|
|
|
|
|
constructor(params: { taxCatalog: JsonTaxCatalogProvider }) {
|
|
|
|
|
this.taxCatalog = params.taxCatalog;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public map(
|
|
|
|
|
dto: CreateProformaFromFactugesRequestDTO,
|
|
|
|
|
params: { companyId: UniqueID }
|
|
|
|
|
): Result<IProformaFromFactuGESProps> {
|
|
|
|
|
try {
|
|
|
|
|
const errors: ValidationErrorDetail[] = [];
|
|
|
|
|
const { companyId } = params;
|
|
|
|
|
const currencyCode = CurrencyCode.fromEUR();
|
|
|
|
|
|
|
|
|
|
const proformaProps = this.mapProformaProps(dto, {
|
|
|
|
|
companyId,
|
|
|
|
|
currencyCode,
|
|
|
|
|
errors,
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
const customerProps = this.mapCustomerProps(dto.customer, {
|
|
|
|
|
companyId,
|
|
|
|
|
currencyCode,
|
|
|
|
|
errors,
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
this.throwIfValidationErrors(errors);
|
|
|
|
|
|
|
|
|
|
return Result.ok({
|
|
|
|
|
customerLookup: {
|
|
|
|
|
tin: customerProps.tin,
|
|
|
|
|
},
|
|
|
|
|
customerDraft: customerProps,
|
|
|
|
|
proformaDraft: proformaProps,
|
|
|
|
|
});
|
|
|
|
|
} catch (err: unknown) {
|
|
|
|
|
const error = isValidationErrorCollection(err)
|
|
|
|
|
? (err as ValidationErrorCollection)
|
|
|
|
|
: new DomainError("Customer props mapping failed", { cause: (err as Error).message });
|
|
|
|
|
return Result.fail(error);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public mapProformaProps(
|
|
|
|
|
dto: CreateProformaFromFactugesRequestDTO,
|
|
|
|
|
params: {
|
|
|
|
|
companyId: UniqueID;
|
|
|
|
|
currencyCode: CurrencyCode;
|
|
|
|
|
errors: ValidationErrorDetail[];
|
|
|
|
|
}
|
|
|
|
|
): IProformaFromFactuGESProps["proformaDraft"] {
|
|
|
|
|
const errors: ValidationErrorDetail[] = [];
|
|
|
|
|
const { companyId } = params;
|
|
|
|
|
|
|
|
|
|
//const defaultStatus = InvoiceStatus.fromApproved();
|
|
|
|
|
|
|
|
|
|
//const proformaId = extractOrPushError(UniqueID.create(dto.id), "id", errors);
|
|
|
|
|
|
|
|
|
|
const series = extractOrPushError(
|
|
|
|
|
maybeFromNullableResult(dto.series, (value) => InvoiceSerie.create(value)),
|
|
|
|
|
"series",
|
|
|
|
|
errors
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
/*const proformaNumber = extractOrPushError(
|
|
|
|
|
InvoiceNumber.create(dto.),
|
|
|
|
|
"invoice_number",
|
|
|
|
|
errors
|
|
|
|
|
);*/
|
|
|
|
|
|
|
|
|
|
//const factugesID = String(dto.factuges_id);
|
|
|
|
|
|
|
|
|
|
const reference = extractOrPushError(
|
|
|
|
|
maybeFromNullableResult(dto.reference, (value) => Result.ok(String(value))),
|
|
|
|
|
"reference",
|
|
|
|
|
errors
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
const invoiceDate = extractOrPushError(
|
|
|
|
|
UtcDate.createFromISO(dto.invoice_date),
|
|
|
|
|
"invoice_date",
|
|
|
|
|
errors
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
const operationDate = extractOrPushError(
|
|
|
|
|
maybeFromNullableResult(dto.operation_date, (value) => UtcDate.createFromISO(value)),
|
|
|
|
|
"operation_date",
|
|
|
|
|
errors
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
const description = extractOrPushError(
|
|
|
|
|
maybeFromNullableResult(dto.reference, (value) => Result.ok(String(value))),
|
|
|
|
|
"description",
|
|
|
|
|
errors
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
const notes = extractOrPushError(
|
|
|
|
|
maybeFromNullableResult(dto.notes, (value) => TextValue.create(value)),
|
|
|
|
|
"notes",
|
|
|
|
|
errors
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
const paymentMethod = extractOrPushError(
|
|
|
|
|
maybeFromNullableResult(dto.payment_method, (value) =>
|
|
|
|
|
InvoicePaymentMethod.create({ paymentDescription: value })
|
|
|
|
|
),
|
|
|
|
|
"payment_method",
|
|
|
|
|
errors
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
const globalDiscountPercentage = extractOrPushError(
|
2026-03-19 15:08:02 +00:00
|
|
|
DiscountPercentage.create({ value: Number(dto.global_discount_percentage_value) }),
|
|
|
|
|
"global_discount_percentage_value",
|
|
|
|
|
params.errors
|
2026-03-16 17:45:45 +00:00
|
|
|
);
|
|
|
|
|
|
|
|
|
|
const languageCode = extractOrPushError(
|
|
|
|
|
LanguageCode.create(dto.customer.language_code),
|
|
|
|
|
"language_code",
|
|
|
|
|
errors
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
const currencyCode = CurrencyCode.fromEUR();
|
|
|
|
|
|
|
|
|
|
const itemsProps = this.mapItemsProps(dto, {
|
|
|
|
|
languageCode: languageCode!,
|
|
|
|
|
currencyCode: currencyCode,
|
|
|
|
|
globalDiscountPercentage: globalDiscountPercentage!,
|
|
|
|
|
errors,
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
const props: IProformaFromFactuGESProps["proformaDraft"] = {
|
|
|
|
|
//companyId,
|
|
|
|
|
//status: defaultStatus,
|
|
|
|
|
|
|
|
|
|
//invoiceNumber: proformaNumber!,
|
|
|
|
|
series: series!,
|
|
|
|
|
|
|
|
|
|
invoiceDate: invoiceDate!,
|
|
|
|
|
operationDate: operationDate!,
|
|
|
|
|
|
|
|
|
|
//customerId: customerId!,
|
|
|
|
|
//recipient,
|
|
|
|
|
|
|
|
|
|
reference: reference!,
|
|
|
|
|
description: description!,
|
|
|
|
|
notes: notes!,
|
|
|
|
|
|
|
|
|
|
languageCode: languageCode!,
|
|
|
|
|
currencyCode: currencyCode!,
|
|
|
|
|
|
|
|
|
|
paymentMethod: paymentMethod!,
|
|
|
|
|
globalDiscountPercentage: globalDiscountPercentage!,
|
|
|
|
|
|
|
|
|
|
items: itemsProps, // ← IProformaItemProps[]
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
return props;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private mapCustomerProps(
|
|
|
|
|
dto: CreateProformaFromFactugesRequestDTO["customer"],
|
|
|
|
|
params: {
|
|
|
|
|
companyId: UniqueID;
|
|
|
|
|
currencyCode: CurrencyCode;
|
|
|
|
|
errors: ValidationErrorDetail[];
|
|
|
|
|
}
|
|
|
|
|
): IProformaFromFactuGESProps["customerDraft"] {
|
|
|
|
|
const { errors, currencyCode } = params;
|
|
|
|
|
|
|
|
|
|
const isCompany = dto.is_company === "1";
|
|
|
|
|
const name = extractOrPushError(Name.create(dto.name), "name", errors);
|
|
|
|
|
const tinNumber = extractOrPushError(TINNumber.create(dto.tin), "tin", errors);
|
|
|
|
|
|
|
|
|
|
const street = extractOrPushError(
|
|
|
|
|
maybeFromNullableResult(dto.street, (value) => Street.create(value)),
|
|
|
|
|
"street",
|
|
|
|
|
errors
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
const city = extractOrPushError(
|
|
|
|
|
maybeFromNullableResult(dto.city, (value) => City.create(value)),
|
|
|
|
|
"city",
|
|
|
|
|
errors
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
const province = extractOrPushError(
|
|
|
|
|
maybeFromNullableResult(dto.province, (value) => Province.create(value)),
|
|
|
|
|
"province",
|
|
|
|
|
errors
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
const postalCode = extractOrPushError(
|
|
|
|
|
maybeFromNullableResult(dto.postal_code, (value) => PostalCode.create(value)),
|
|
|
|
|
"postal_code",
|
|
|
|
|
errors
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
const country = extractOrPushError(
|
|
|
|
|
maybeFromNullableResult(dto.country, (value) => Country.create(value)),
|
|
|
|
|
"country",
|
|
|
|
|
errors
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
const primaryEmailAddress = extractOrPushError(
|
|
|
|
|
maybeFromNullableResult(dto.email_primary, (value) => EmailAddress.create(value)),
|
|
|
|
|
"email_primary",
|
|
|
|
|
errors
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
const secondaryEmailAddress = extractOrPushError(
|
|
|
|
|
maybeFromNullableResult(dto.email_secondary, (value) => EmailAddress.create(value)),
|
|
|
|
|
"email_secondary",
|
|
|
|
|
errors
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
const primaryPhoneNumber = extractOrPushError(
|
|
|
|
|
maybeFromNullableResult(dto.phone_primary, (value) => PhoneNumber.create(value)),
|
|
|
|
|
"phone_primary",
|
|
|
|
|
errors
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
const secondaryPhoneNumber = extractOrPushError(
|
|
|
|
|
maybeFromNullableResult(dto.phone_secondary, (value) => PhoneNumber.create(value)),
|
|
|
|
|
"phone_secondary",
|
|
|
|
|
errors
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
const primaryMobileNumber = extractOrPushError(
|
|
|
|
|
maybeFromNullableResult(dto.mobile_primary, (value) => PhoneNumber.create(value)),
|
|
|
|
|
"mobile_primary",
|
|
|
|
|
errors
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
const secondaryMobileNumber = extractOrPushError(
|
|
|
|
|
maybeFromNullableResult(dto.mobile_secondary, (value) => PhoneNumber.create(value)),
|
|
|
|
|
"mobile_secondary",
|
|
|
|
|
errors
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
const website = extractOrPushError(
|
|
|
|
|
maybeFromNullableResult(dto.website, (value) => URLAddress.create(value)),
|
|
|
|
|
"website",
|
|
|
|
|
errors
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
const languageCode = extractOrPushError(
|
|
|
|
|
LanguageCode.create(dto.language_code),
|
|
|
|
|
"language_code",
|
|
|
|
|
errors
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
this.throwIfValidationErrors(errors);
|
|
|
|
|
|
|
|
|
|
const postalAddressProps: PostalAddressProps = {
|
|
|
|
|
street: street!,
|
|
|
|
|
street2: Maybe.none(),
|
|
|
|
|
city: city!,
|
|
|
|
|
postalCode: postalCode!,
|
|
|
|
|
province: province!,
|
|
|
|
|
country: country!,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/*const customerTaxes = this.mapCustomerTaxesProps(dto, {
|
|
|
|
|
errors,
|
|
|
|
|
});*/
|
|
|
|
|
|
|
|
|
|
const customerProps: IProformaFromFactuGESProps["customerDraft"] = {
|
|
|
|
|
//companyId,
|
|
|
|
|
//status: status!,
|
|
|
|
|
|
|
|
|
|
isCompany: isCompany,
|
|
|
|
|
name: name!,
|
|
|
|
|
tin: tinNumber!,
|
|
|
|
|
//tradeName: Maybe.none(),
|
|
|
|
|
//reference: Maybe.none(),
|
|
|
|
|
|
|
|
|
|
address: postalAddressProps!,
|
|
|
|
|
|
|
|
|
|
emailPrimary: primaryEmailAddress!,
|
|
|
|
|
emailSecondary: secondaryEmailAddress!,
|
|
|
|
|
|
|
|
|
|
phonePrimary: primaryPhoneNumber!,
|
|
|
|
|
phoneSecondary: secondaryPhoneNumber!,
|
|
|
|
|
|
|
|
|
|
mobilePrimary: primaryMobileNumber!,
|
|
|
|
|
mobileSecondary: secondaryMobileNumber!,
|
|
|
|
|
|
|
|
|
|
//fax: Maybe.none(),
|
|
|
|
|
website: website!,
|
|
|
|
|
|
|
|
|
|
//legalRecord: Maybe.none(),
|
|
|
|
|
|
|
|
|
|
//defaultTaxes: customerTaxes,
|
|
|
|
|
|
|
|
|
|
languageCode: languageCode!,
|
|
|
|
|
currencyCode: currencyCode!,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
return customerProps;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private mapItemsProps(
|
|
|
|
|
dto: CreateProformaFromFactugesRequestDTO,
|
|
|
|
|
params: {
|
|
|
|
|
languageCode: LanguageCode;
|
|
|
|
|
currencyCode: CurrencyCode;
|
|
|
|
|
globalDiscountPercentage: DiscountPercentage;
|
|
|
|
|
errors: ValidationErrorDetail[];
|
|
|
|
|
}
|
2026-03-23 17:51:49 +00:00
|
|
|
): IProformaItemCreateProps[] {
|
|
|
|
|
const itemsProps: IProformaItemCreateProps[] = [];
|
2026-03-16 17:45:45 +00:00
|
|
|
|
|
|
|
|
dto.items.forEach((item, index) => {
|
|
|
|
|
const description = extractOrPushError(
|
2026-03-19 15:08:02 +00:00
|
|
|
maybeFromNullableResult(item.description, (value) => ItemDescription.create(value)),
|
2026-03-16 17:45:45 +00:00
|
|
|
`items[${index}].description`,
|
|
|
|
|
params.errors
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
const quantity = extractOrPushError(
|
2026-03-19 15:08:02 +00:00
|
|
|
maybeFromNullableResult(item.quantity_value, (value) =>
|
|
|
|
|
ItemQuantity.create({ value: Number(value) })
|
|
|
|
|
),
|
|
|
|
|
"items[$index].quantity_value",
|
2026-03-16 17:45:45 +00:00
|
|
|
params.errors
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
const unitAmount = extractOrPushError(
|
2026-03-19 15:08:02 +00:00
|
|
|
maybeFromNullableResult(item.unit_value, (value) =>
|
|
|
|
|
ItemAmount.create({ value: Number(value) })
|
|
|
|
|
),
|
|
|
|
|
`items[${index}].unit_value`,
|
2026-03-16 17:45:45 +00:00
|
|
|
params.errors
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
const discountPercentage = extractOrPushError(
|
2026-03-19 15:08:02 +00:00
|
|
|
maybeFromNullableResult(item.discount_percentage_value, (value) =>
|
|
|
|
|
DiscountPercentage.create({ value: Number(value) })
|
2026-03-16 17:45:45 +00:00
|
|
|
),
|
2026-03-19 15:08:02 +00:00
|
|
|
`items[${index}].discount_percentage_value`,
|
2026-03-16 17:45:45 +00:00
|
|
|
params.errors
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
const taxes = this.mapItempTaxesProps(item, {
|
|
|
|
|
itemIndex: index,
|
|
|
|
|
errors: params.errors,
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
this.throwIfValidationErrors(params.errors);
|
|
|
|
|
|
|
|
|
|
itemsProps.push({
|
|
|
|
|
description: description!,
|
2026-03-23 17:51:49 +00:00
|
|
|
|
2026-03-16 17:45:45 +00:00
|
|
|
quantity: quantity!,
|
|
|
|
|
unitAmount: unitAmount!,
|
2026-03-23 17:51:49 +00:00
|
|
|
|
2026-03-16 17:45:45 +00:00
|
|
|
itemDiscountPercentage: discountPercentage!,
|
2026-03-23 17:51:49 +00:00
|
|
|
|
2026-03-16 17:45:45 +00:00
|
|
|
taxes,
|
2026-03-23 17:51:49 +00:00
|
|
|
|
|
|
|
|
globalDiscountPercentage: params.globalDiscountPercentage,
|
|
|
|
|
languageCode: params.languageCode,
|
|
|
|
|
currencyCode: params.currencyCode,
|
2026-03-16 17:45:45 +00:00
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
return itemsProps;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Devuelve las propiedades de los impustos de una línea de detalle */
|
|
|
|
|
|
|
|
|
|
private mapItempTaxesProps(
|
|
|
|
|
itemDTO: CreateProformaItemFromFactugesRequestDTO,
|
|
|
|
|
params: { itemIndex: number; errors: ValidationErrorDetail[] }
|
|
|
|
|
): ProformaItemTaxesProps {
|
|
|
|
|
const { itemIndex, errors } = params;
|
|
|
|
|
|
|
|
|
|
const taxesProps: ProformaItemTaxesProps = {
|
|
|
|
|
iva: Maybe.none(),
|
|
|
|
|
retention: Maybe.none(),
|
|
|
|
|
rec: Maybe.none(),
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// Normaliza: "" -> []
|
|
|
|
|
// IVA por defecto => iva_21
|
|
|
|
|
const taxStrCodes = [itemDTO.iva_code === "" ? "iva_21" : itemDTO.iva_code];
|
|
|
|
|
|
|
|
|
|
if (itemDTO.rec_code) taxStrCodes.push(itemDTO.rec_code);
|
|
|
|
|
if (itemDTO.retention_code) taxStrCodes.push(itemDTO.retention_code);
|
|
|
|
|
|
|
|
|
|
taxStrCodes.forEach((strCode, taxIndex) => {
|
|
|
|
|
const taxResult = Tax.createFromCode(strCode, this.taxCatalog);
|
|
|
|
|
|
|
|
|
|
if (!taxResult.isSuccess) {
|
|
|
|
|
errors.push({
|
|
|
|
|
path: `items[${itemIndex}].taxes[${taxIndex}]`,
|
|
|
|
|
message: taxResult.error.message,
|
|
|
|
|
});
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const tax = taxResult.data;
|
|
|
|
|
|
|
|
|
|
if (tax.isVATLike()) {
|
|
|
|
|
if (taxesProps.iva.isSome()) {
|
|
|
|
|
errors.push({
|
|
|
|
|
path: `items[${itemIndex}].taxes`,
|
|
|
|
|
message: "Multiple taxes for group VAT are not allowed",
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
taxesProps.iva = Maybe.some(tax);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (tax.isRetention()) {
|
|
|
|
|
if (taxesProps.retention.isSome()) {
|
|
|
|
|
errors.push({
|
|
|
|
|
path: `items[${itemIndex}].taxes`,
|
|
|
|
|
message: "Multiple taxes for group retention are not allowed",
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
taxesProps.retention = Maybe.some(tax);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (tax.isRec()) {
|
|
|
|
|
if (taxesProps.rec.isSome()) {
|
|
|
|
|
errors.push({
|
|
|
|
|
path: `items[${itemIndex}].taxes`,
|
|
|
|
|
message: "Multiple taxes for group rec are not allowed",
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
taxesProps.rec = Maybe.some(tax);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
this.throwIfValidationErrors(errors);
|
|
|
|
|
|
|
|
|
|
return taxesProps;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private throwIfValidationErrors(errors: ValidationErrorDetail[]): void {
|
|
|
|
|
if (errors.length > 0) {
|
|
|
|
|
throw new ValidationErrorCollection("Customer proforma props mapping failed", errors);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|