From 2ae118d1ffd72b74cce9cf607a9d44982255dc4e Mon Sep 17 00:00:00 2001 From: david Date: Wed, 25 Mar 2026 14:26:10 +0100 Subject: [PATCH] =?UTF-8?q?Importaci=C3=B3n=20desde=20FactuGES?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../proforma-items/proforma-item.entity.ts | 2 +- ...ate-proforma-from-factuges-input.mapper.ts | 309 +++++++++++++----- .../create-proforma-from-factuges.use-case.ts | 19 +- ...eate-proforma-from-factuges.request.dto.ts | 6 +- 4 files changed, 235 insertions(+), 101 deletions(-) diff --git a/modules/customer-invoices/src/api/domain/proformas/entities/proforma-items/proforma-item.entity.ts b/modules/customer-invoices/src/api/domain/proformas/entities/proforma-items/proforma-item.entity.ts index 690bb48e..1987e136 100644 --- a/modules/customer-invoices/src/api/domain/proformas/entities/proforma-items/proforma-item.entity.ts +++ b/modules/customer-invoices/src/api/domain/proformas/entities/proforma-items/proforma-item.entity.ts @@ -170,7 +170,7 @@ export class ProformaItem extends DomainEntity implem // Todos a 4 decimales public isValued(): boolean { - return this.props.quantity.isSome() || this.props.unitAmount.isSome(); + return this.props.quantity.isSome() && this.props.unitAmount.isSome(); } public subtotalAmount(): ItemAmount { diff --git a/modules/factuges/src/api/application/mappers/create-proforma-from-factuges-input.mapper.ts b/modules/factuges/src/api/application/mappers/create-proforma-from-factuges-input.mapper.ts index f67b48a4..3d4b98b8 100644 --- a/modules/factuges/src/api/application/mappers/create-proforma-from-factuges-input.mapper.ts +++ b/modules/factuges/src/api/application/mappers/create-proforma-from-factuges-input.mapper.ts @@ -1,7 +1,7 @@ import type { JsonTaxCatalogProvider } from "@erp/core"; import { DiscountPercentage, Tax } from "@erp/core/api"; import { - type IProformaItemCreateProps, + InvoiceAmount, InvoiceSerie, ItemAmount, ItemDescription, @@ -39,73 +39,86 @@ import type { CreateProformaItemFromFactugesRequestDTO, } from "../../../common"; -export interface IProformaFromFactuGESProps { - customerLookup: { - tin: TINNumber; - }; +export type ProformaCustomerLookup = { + tin: TINNumber; +}; - paymentLookup: { - factuges_id: string; - }; +export type ProformaPaymentLookup = { + factuges_id: string; +}; - customerDraft: { - //reference: Maybe; +export type ProformaCustomerDraft = { + isCompany: boolean; + name: Name; + tin: TINNumber; + address: PostalAddressProps; + emailPrimary: Maybe; + emailSecondary: Maybe; + phonePrimary: Maybe; + phoneSecondary: Maybe; + mobilePrimary: Maybe; + mobileSecondary: Maybe; + website: Maybe; + languageCode: LanguageCode; + currencyCode: CurrencyCode; +}; - isCompany: boolean; - name: Name; - //tradeName: Maybe; - tin: TINNumber; +export type ProformaDraftItem = { + position: string; + description: Maybe; + quantity: Maybe; + unitAmount: Maybe; + subtotalAmount: Maybe; + itemDiscountPercentage: Maybe; + itemDiscountAmount: Maybe; + globalDiscountPercentage: DiscountPercentage; + globalDiscountAmount: Maybe; + totalDiscountAmount: Maybe; + taxableAmount: Maybe; + taxes: ProformaItemTaxesProps; + taxesAmount: Maybe; + totalAmount: Maybe; + languageCode: LanguageCode; + currencyCode: CurrencyCode; +}; - address: PostalAddressProps; +export type ProformaDraft = { + series: Maybe; + invoiceDate: UtcDate; + operationDate: Maybe; + reference: Maybe; + description: Maybe; + notes: Maybe; + languageCode: LanguageCode; + currencyCode: CurrencyCode; + subtotalAmount: Maybe; + globalDiscountPercentage: DiscountPercentage; + itemsDiscountAmount: Maybe; + taxableAmount: Maybe; + taxes: ProformaItemTaxesProps; + taxesAmount: Maybe; + totalAmount: Maybe; + items: ProformaDraftItem[]; +}; - emailPrimary: Maybe; - emailSecondary: Maybe; +export type ProformaPaymentDraft = { + factuges_id: string; + description: string; +}; - phonePrimary: Maybe; - phoneSecondary: Maybe; - - mobilePrimary: Maybe; - mobileSecondary: Maybe; - - //fax: Maybe; - website: Maybe; - - //legalRecord: Maybe; - - //defaultTaxes: CustomerTaxesProps; - - languageCode: LanguageCode; - currencyCode: CurrencyCode; - }; - - proformaDraft: { - series: Maybe; - - invoiceDate: UtcDate; - operationDate: Maybe; - - reference: Maybe; - description: Maybe; - notes: Maybe; - - languageCode: LanguageCode; - currencyCode: CurrencyCode; - - items: IProformaItemCreateProps[]; - globalDiscountPercentage: DiscountPercentage; - }; - - paymentDraft: { - factuges_id: string; - description: string; - }; -} +export type FactugesProformaPayload = { + customerLookup: ProformaCustomerLookup; + paymentLookup: ProformaPaymentLookup; + customerDraft: ProformaCustomerDraft; + proformaDraft: ProformaDraft; + paymentDraft: ProformaPaymentDraft; +}; export interface ICreateProformaFromFactugesInputMapper { map( dto: CreateProformaFromFactugesRequestDTO, params: { companyId: UniqueID } - ): Result; + ): Result; } export class CreateProformaFromFactugesInputMapper @@ -120,7 +133,7 @@ export class CreateProformaFromFactugesInputMapper public map( dto: CreateProformaFromFactugesRequestDTO, params: { companyId: UniqueID } - ): Result { + ): Result { try { const errors: ValidationErrorDetail[] = []; const { companyId } = params; @@ -172,7 +185,7 @@ export class CreateProformaFromFactugesInputMapper currencyCode: CurrencyCode; errors: ValidationErrorDetail[]; } - ): IProformaFromFactuGESProps["paymentDraft"] { + ): ProformaPaymentDraft { const errors: ValidationErrorDetail[] = []; const { companyId } = params; @@ -189,7 +202,7 @@ export class CreateProformaFromFactugesInputMapper currencyCode: CurrencyCode; errors: ValidationErrorDetail[]; } - ): IProformaFromFactuGESProps["proformaDraft"] { + ): ProformaDraft { const errors: ValidationErrorDetail[] = []; const { companyId } = params; @@ -230,7 +243,7 @@ export class CreateProformaFromFactugesInputMapper ); const description = extractOrPushError( - maybeFromNullableResult(dto.reference, (value) => Result.ok(String(value))), + maybeFromNullableResult(dto.description, (value) => Result.ok(String(value))), "description", errors ); @@ -241,12 +254,6 @@ export class CreateProformaFromFactugesInputMapper errors ); - const globalDiscountPercentage = extractOrPushError( - DiscountPercentage.create({ value: Number(dto.global_discount_percentage_value) }), - "global_discount_percentage_value", - params.errors - ); - const languageCode = extractOrPushError( LanguageCode.create(dto.customer.language_code), "language_code", @@ -255,6 +262,59 @@ export class CreateProformaFromFactugesInputMapper const currencyCode = CurrencyCode.fromEUR(); + const subtotalAmount = extractOrPushError( + maybeFromNullableResult(dto.subtotal_amount_value, (value) => + InvoiceAmount.create({ value: Number(value) }) + ), + "subtotal_amount_value", + params.errors + ); + + const globalDiscountPercentage = extractOrPushError( + DiscountPercentage.create({ value: Number(dto.global_discount_percentage_value) }), + "global_discount_percentage_value", + params.errors + ); + + const itemsDiscountAmount = extractOrPushError( + maybeFromNullableResult(dto.discount_amount_value, (value) => + InvoiceAmount.create({ value: Number(value) }) + ), + "discount_amount_value", + params.errors + ); + + const taxableAmount = extractOrPushError( + maybeFromNullableResult(dto.taxable_amount_value, (value) => + InvoiceAmount.create({ value: Number(value) }) + ), + "taxable_amount_value", + params.errors + ); + + // TODO: Determinar cómo calcular los impuestos de la cabecera de la proforma + const taxes: ProformaItemTaxesProps = { + iva: Maybe.none(), + retention: Maybe.none(), + rec: Maybe.none(), + }; + + const taxesAmount = extractOrPushError( + maybeFromNullableResult(dto.taxes_amount_value, (value) => + InvoiceAmount.create({ value: Number(value) }) + ), + "taxes_amount_value", + params.errors + ); + + const totalAmount = extractOrPushError( + maybeFromNullableResult(dto.total_amount_value, (value) => + InvoiceAmount.create({ value: Number(value) }) + ), + "total_amount_value", + params.errors + ); + const itemsProps = this.mapItemsProps(dto, { languageCode: languageCode!, currencyCode: currencyCode, @@ -262,7 +322,7 @@ export class CreateProformaFromFactugesInputMapper errors, }); - const props: IProformaFromFactuGESProps["proformaDraft"] = { + const props: ProformaDraft = { //companyId, //status: defaultStatus, @@ -282,9 +342,16 @@ export class CreateProformaFromFactugesInputMapper languageCode: languageCode!, currencyCode: currencyCode!, + subtotalAmount: subtotalAmount!, globalDiscountPercentage: globalDiscountPercentage!, + itemsDiscountAmount: itemsDiscountAmount!, - items: itemsProps, // ← IProformaItemProps[] + taxableAmount: taxableAmount!, + taxes: taxes, + taxesAmount: taxesAmount!, + totalAmount: totalAmount!, + + items: itemsProps, }; return props; @@ -297,7 +364,7 @@ export class CreateProformaFromFactugesInputMapper currencyCode: CurrencyCode; errors: ValidationErrorDetail[]; } - ): IProformaFromFactuGESProps["customerDraft"] { + ): ProformaCustomerDraft { const { errors, currencyCode } = params; const isCompany = dto.is_company === "1"; @@ -397,7 +464,7 @@ export class CreateProformaFromFactugesInputMapper errors, });*/ - const customerProps: IProformaFromFactuGESProps["customerDraft"] = { + const customerProps: ProformaCustomerDraft = { //companyId, //status: status!, @@ -440,10 +507,12 @@ export class CreateProformaFromFactugesInputMapper globalDiscountPercentage: DiscountPercentage; errors: ValidationErrorDetail[]; } - ): IProformaItemCreateProps[] { - const itemsProps: IProformaItemCreateProps[] = []; + ): ProformaDraftItem[] { + const itemsProps: ProformaDraftItem[] = []; dto.items.forEach((item, index) => { + const position = String(item.position); + const description = extractOrPushError( maybeFromNullableResult(item.description, (value) => ItemDescription.create(value)), `items[${index}].description`, @@ -454,19 +523,27 @@ export class CreateProformaFromFactugesInputMapper maybeFromNullableResult(item.quantity_value, (value) => ItemQuantity.create({ value: Number(value) }) ), - "items[$index].quantity_value", + `items[${index}].quantity_value`, params.errors ); const unitAmount = extractOrPushError( - maybeFromNullableResult(item.unit_value, (value) => + maybeFromNullableResult(item.unit_amount_value, (value) => ItemAmount.create({ value: Number(value) }) ), - `items[${index}].unit_value`, + `items[${index}].unit_amount_value`, params.errors ); - const discountPercentage = extractOrPushError( + const subtotalAmount = extractOrPushError( + maybeFromNullableResult(item.subtotal_amount_value, (value) => + ItemAmount.create({ value: Number(value) }) + ), + `items[${index}].subtotal_amount_value`, + params.errors + ); + + const itemDiscountPercentage = extractOrPushError( maybeFromNullableResult(item.item_discount_percentage_value, (value) => DiscountPercentage.create({ value: Number(value) }) ), @@ -474,35 +551,93 @@ export class CreateProformaFromFactugesInputMapper params.errors ); - const taxes = this.mapItempTaxesProps(item, { + const itemDiscountAmount = extractOrPushError( + maybeFromNullableResult(item.item_discount_amount_value, (value) => + ItemAmount.create({ value: Number(value) }) + ), + `items[${index}].item_discount_amount_value`, + params.errors + ); + + const globalDiscountAmount = extractOrPushError( + maybeFromNullableResult(item.global_discount_amount_value, (value) => + ItemAmount.create({ value: Number(value) }) + ), + `items[${index}].global_discount_amount_value`, + params.errors + ); + + const totalDiscountAmount = extractOrPushError( + maybeFromNullableResult(item.total_discount_amount_value, (value) => + ItemAmount.create({ value: Number(value) }) + ), + `items[${index}].total_discount_amount_value`, + params.errors + ); + + const taxableAmount = extractOrPushError( + maybeFromNullableResult(item.taxable_amount_value, (value) => + ItemAmount.create({ value: Number(value) }) + ), + `items[${index}].taxable_amount_value`, + params.errors + ); + + const taxesAmount = extractOrPushError( + maybeFromNullableResult(item.taxes_amount_value, (value) => + ItemAmount.create({ value: Number(value) }) + ), + `items[${index}].taxes_amount_value`, + params.errors + ); + + const totalAmount = extractOrPushError( + maybeFromNullableResult(item.total_amount_value, (value) => + ItemAmount.create({ value: Number(value) }) + ), + `items[${index}].total_amount_value`, + params.errors + ); + + const taxes = this.mapItemTaxesProps(item, { itemIndex: index, errors: params.errors, }); - this.throwIfValidationErrors(params.errors); - - itemsProps.push({ + const _item: ProformaDraftItem = { + position, description: description!, quantity: quantity!, unitAmount: unitAmount!, + subtotalAmount: subtotalAmount!, - itemDiscountPercentage: discountPercentage!, - - taxes, - + itemDiscountPercentage: itemDiscountPercentage!, + itemDiscountAmount: itemDiscountAmount!, globalDiscountPercentage: params.globalDiscountPercentage, + globalDiscountAmount: globalDiscountAmount!, + totalDiscountAmount: totalDiscountAmount!, + + taxableAmount: taxableAmount!, + taxes, + taxesAmount: taxesAmount!, + totalAmount: totalAmount!, + languageCode: params.languageCode, currencyCode: params.currencyCode, - }); + }; + + itemsProps.push(_item); }); + this.throwIfValidationErrors(params.errors); + return itemsProps; } /* Devuelve las propiedades de los impustos de una línea de detalle */ - private mapItempTaxesProps( + private mapItemTaxesProps( itemDTO: CreateProformaItemFromFactugesRequestDTO, params: { itemIndex: number; errors: ValidationErrorDetail[] } ): ProformaItemTaxesProps { diff --git a/modules/factuges/src/api/application/use-cases/create-proforma-from-factuges.use-case.ts b/modules/factuges/src/api/application/use-cases/create-proforma-from-factuges.use-case.ts index 1925d619..c8c624e7 100644 --- a/modules/factuges/src/api/application/use-cases/create-proforma-from-factuges.use-case.ts +++ b/modules/factuges/src/api/application/use-cases/create-proforma-from-factuges.use-case.ts @@ -18,10 +18,7 @@ import { Maybe, Result } from "@repo/rdx-utils"; import type { Transaction } from "sequelize"; import type { CreateProformaFromFactugesRequestDTO } from "../../../common"; -import type { - ICreateProformaFromFactugesInputMapper, - IProformaFromFactuGESProps, -} from "../mappers"; +import type { FactugesProformaPayload, ICreateProformaFromFactugesInputMapper } from "../mappers"; import paymentsCatalog from "./payments.json"; @@ -139,6 +136,8 @@ export class CreateProformaFromFactugesUseCase { const snapshot = readResult.data; + //const comparisonResults = this.compare() + const result = { customer_id: customer.id.toString(), proforma_id: snapshot.id.toString(), @@ -152,7 +151,7 @@ export class CreateProformaFromFactugesUseCase { } private buildProformaCreateProps(deps: { - proformaDraft: IProformaFromFactuGESProps["proformaDraft"]; + proformaDraft: FactugesProformaPayload["proformaDraft"]; customerId: UniqueID; payment: FakePaymentMethod; context: { @@ -193,8 +192,8 @@ export class CreateProformaFromFactugesUseCase { * @returns `Result` con el cliente resuelto o el error producido. */ private async resolveCustomer( - customerLookup: IProformaFromFactuGESProps["customerLookup"], - customerDraft: IProformaFromFactuGESProps["customerDraft"], + customerLookup: FactugesProformaPayload["customerLookup"], + customerDraft: FactugesProformaPayload["customerDraft"], context: { companyId: UniqueID; transaction: Transaction; @@ -227,8 +226,8 @@ export class CreateProformaFromFactugesUseCase { } private async resolvePayment( - paymentLookup: IProformaFromFactuGESProps["paymentLookup"], - paymentDraft: IProformaFromFactuGESProps["paymentDraft"], + paymentLookup: FactugesProformaPayload["paymentLookup"], + paymentDraft: FactugesProformaPayload["paymentDraft"], context: { companyId: UniqueID; transaction: Transaction; @@ -254,7 +253,7 @@ export class CreateProformaFromFactugesUseCase { } private buildCustomerCreateProps( - customerDraft: IProformaFromFactuGESProps["customerDraft"], + customerDraft: FactugesProformaPayload["customerDraft"], context: { companyId: UniqueID; transaction: Transaction; diff --git a/modules/factuges/src/common/dto/request/create-proforma-from-factuges.request.dto.ts b/modules/factuges/src/common/dto/request/create-proforma-from-factuges.request.dto.ts index 256b5988..8351c388 100644 --- a/modules/factuges/src/common/dto/request/create-proforma-from-factuges.request.dto.ts +++ b/modules/factuges/src/common/dto/request/create-proforma-from-factuges.request.dto.ts @@ -5,9 +5,9 @@ export const CreateProformaItemFromFactugesRequestSchema = z.object({ position: z.string(), description: z.string().default(""), quantity_value: NumericStringSchema.default(""), // Ya viene escalado - unit_value: NumericStringSchema.default(""), + unit_amount_value: NumericStringSchema.default(""), - subtotal_amuount_value: NumericStringSchema.default(""), + subtotal_amount_value: NumericStringSchema.default(""), item_discount_percentage_value: NumericStringSchema.default(""), item_discount_amount_value: NumericStringSchema.default(""), @@ -17,7 +17,7 @@ export const CreateProformaItemFromFactugesRequestSchema = z.object({ total_discount_amount_value: NumericStringSchema.default(""), taxable_amount_value: NumericStringSchema.default(""), - total_value: NumericStringSchema.default(""), + total_amount_value: NumericStringSchema.default(""), iva_code: z.string().default(""), iva_percentage_value: NumericStringSchema.default(""),