Presupuestador_web/server/src/contexts/sales/infrastructure/mappers/quote.mapper.ts

189 lines
6.9 KiB
TypeScript
Raw Normal View History

2024-07-12 16:37:41 +00:00
import {
CurrencyData,
Language,
Note,
Percentage,
TextValueObject,
UTCDateValue,
UniqueID,
} from "@shared/contexts";
2024-05-26 17:09:43 +00:00
import { ISequelizeMapper, SequelizeMapper } from "@/contexts/common/infrastructure";
2024-08-23 16:47:51 +00:00
import {
IQuoteProps,
Quote,
QuoteCustomer,
QuoteCustomerReference,
QuoteReference,
} from "../../domain";
2024-07-01 17:12:15 +00:00
import { QuoteStatus } from "../../domain/entities/Quotes/QuoteStatus";
2024-05-26 17:09:43 +00:00
import { ISalesContext } from "../Sales.context";
2026-10-05 10:04:43 +00:00
import { DEFAULT_QUOTE_TAX_LABEL, QuoteCreationAttributes, Quote_Model } from "../sequelize";
2026-10-19 11:55:16 +00:00
import { createQuoteChapterMapper, IQuoteChapterMapper } from "./quoteChapter.mapper";
2024-05-26 17:09:43 +00:00
import { IQuoteItemMapper, createQuoteItemMapper } from "./quoteItem.mapper";
export interface IQuoteMapper
extends ISequelizeMapper<Quote_Model, QuoteCreationAttributes, Quote> {}
export const createQuoteMapper = (context: ISalesContext): IQuoteMapper =>
new QuoteMapper({
context,
quoteItemMapper: createQuoteItemMapper(context),
2026-10-19 11:55:16 +00:00
quoteChapterMapper: createQuoteChapterMapper(),
2024-05-26 17:09:43 +00:00
});
class QuoteMapper
extends SequelizeMapper<Quote_Model, QuoteCreationAttributes, Quote>
implements IQuoteMapper
{
2026-10-19 11:55:16 +00:00
public constructor(props: { quoteChapterMapper: IQuoteChapterMapper; quoteItemMapper: IQuoteItemMapper; context: ISalesContext }) {
2024-05-26 17:09:43 +00:00
super(props);
}
protected toDomainMappingImpl(source: Quote_Model): Quote {
const id = this.mapsValue(source, "id", UniqueID.create);
2026-10-19 11:55:16 +00:00
const items = (this.props.quoteItemMapper as IQuoteItemMapper).mapArrayToDomain(source.items ? [...source.items].sort((a, b) => a.position - b.position) : [], {
2024-05-26 17:09:43 +00:00
sourceParent: source,
});
2026-10-19 11:55:16 +00:00
const chapters = (this.props.quoteChapterMapper as IQuoteChapterMapper)
.mapArrayToDomain([...(source.chapters ?? [])].sort((a, b) => a.position - b.position)).toArray();
2024-05-26 17:09:43 +00:00
const props: IQuoteProps = {
2026-10-19 11:55:16 +00:00
chapters,
showChapterLineAmounts: source.show_chapter_line_amounts ?? true,
2024-05-26 17:09:43 +00:00
status: this.mapsValue(source, "status", QuoteStatus.create),
2024-07-09 16:21:12 +00:00
date: this.mapsValue(source, "date", UTCDateValue.create),
2024-07-02 20:15:59 +00:00
reference: this.mapsValue(source, "reference", QuoteReference.create),
2024-07-09 16:21:12 +00:00
currency: this.mapsValue(source, "currency_code", CurrencyData.createFromCode),
language: this.mapsValue(
source,
"lang_code",
(value) => Language.createFromCode(value || Language.DEFAULT_LANGUAGE_CODE)
),
2024-08-23 16:47:51 +00:00
customerReference: this.mapsValue(
source,
"customer_reference",
QuoteCustomerReference.create
),
2024-07-09 16:21:12 +00:00
customer: this.mapsValue(source, "customer_information", QuoteCustomer.create),
2024-07-02 20:15:59 +00:00
validity: this.mapsValue(source, "validity", Note.create),
2024-07-09 16:21:12 +00:00
paymentMethod: this.mapsValue(source, "payment_method", Note.create),
2024-07-12 16:37:41 +00:00
notes: this.mapsValue(source, "notes", TextValueObject.create),
showLineDiscountColumn: source.show_line_discount_column ?? true,
additionalCurrency: source.additional_currency_code
? this.mapsValue(source, "additional_currency_code", CurrencyData.createFromCode)
: undefined,
additionalCurrencyRate: source.additional_currency_rate === null ? null : Number(source.additional_currency_rate),
additionalCurrencyDate: source.additional_currency_date
? this.mapsValue(source, "additional_currency_date", UTCDateValue.create)
: undefined,
2024-05-26 17:09:43 +00:00
items,
2024-07-02 20:15:59 +00:00
2024-07-09 16:21:12 +00:00
/*subtotal: this.mapsValue(source, "subtotal_price", (subtotal_price) =>
MoneyValue.create({
amount: subtotal_price,
currencyCode: source.currency_code,
precision: 2,
})
),*/
discount: this.mapsValue(source, "discount", (discount) =>
Percentage.create({
amount: discount,
2024-07-15 16:53:33 +00:00
scale: 2,
2024-07-09 16:21:12 +00:00
})
),
2024-07-19 15:02:19 +00:00
tax: this.mapsValue(source, "tax", (tax) =>
Percentage.create({
amount: tax,
scale: 2,
})
),
2026-10-05 10:04:43 +00:00
taxLabel: this.mapsValue(source, "tax_label", (label) =>
TextValueObject.create(label ?? DEFAULT_QUOTE_TAX_LABEL)
),
2024-07-19 15:02:19 +00:00
2024-07-09 16:21:12 +00:00
/*totalPrice: this.mapsValue(source, "total_price", (total_price) =>
MoneyValue.create({
amount: total_price,
currencyCode: source.currency_code,
precision: 2,
})
),*/
2024-07-02 20:15:59 +00:00
dealerId: this.mapsValue(source, "dealer_id", UniqueID.create),
2024-10-03 14:23:46 +00:00
dateSent: this.mapsValue(source, "date_sent", UTCDateValue.create),
2024-05-26 17:09:43 +00:00
};
const quoteOrError = Quote.create(props, id);
if (quoteOrError.isFailure) {
throw quoteOrError.error;
}
return quoteOrError.object;
}
protected toPersistenceMappingImpl(source: Quote) {
const items = (this.props.quoteItemMapper as IQuoteItemMapper).mapCollectionToPersistence(
source.items,
{ sourceParent: source }
);
2026-10-19 11:55:16 +00:00
const chapters = source.chapters.map((chapter, index) =>
(this.props.quoteChapterMapper as IQuoteChapterMapper).mapToPersistence(chapter, { index })
);
// Canonical flat order: chapters first, preserving the relative detail order.
const orderedItems = chapters.length
? chapters.flatMap((chapter) => items.filter((item) => item.chapter_id === chapter.chapter_id))
: items;
2024-05-26 17:09:43 +00:00
const quote: QuoteCreationAttributes = {
2026-10-19 11:55:16 +00:00
chapters,
show_chapter_line_amounts: source.showChapterLineAmounts,
2024-05-26 17:09:43 +00:00
id: source.id.toPrimitive(),
status: source.status.toPrimitive(),
date: source.date.toPrimitive(),
2024-07-02 20:15:59 +00:00
reference: source.reference.toPrimitive(),
2024-05-26 17:09:43 +00:00
currency_code: source.currency.toPrimitive(),
2024-07-01 17:12:15 +00:00
lang_code: source.language.toPrimitive(),
2024-08-23 16:47:51 +00:00
customer_reference: source.customerReference.toPrimitive(),
2024-07-02 20:15:59 +00:00
customer_information: source.customer.toPrimitive(),
validity: source.validity.toPrimitive(),
payment_method: source.paymentMethod.toPrimitive(),
notes: source.notes.toPrimitive(),
show_line_discount_column: source.showLineDiscountColumn,
additional_currency_code: source.additionalCurrency?.code ?? null,
additional_currency_rate: source.additionalCurrencyRate,
additional_currency_date: source.additionalCurrencyDate?.toString() ?? null,
additional_currency_total: source.additionalCurrencyTotal?.convertScale(2).toPrimitive() ?? null,
2024-07-02 20:15:59 +00:00
2024-07-15 16:53:33 +00:00
subtotal_price: source.subtotalPrice.convertScale(2).toPrimitive(),
2024-07-19 15:02:19 +00:00
2024-07-15 16:53:33 +00:00
discount: source.discount.convertScale(2).toPrimitive(),
2024-07-19 15:02:19 +00:00
discount_price: source.discountPrice.convertScale(2).toPrimitive(),
before_tax_price: source.beforeTaxPrice.convertScale(2).toPrimitive(),
tax: source.tax.convertScale(2).toPrimitive(),
2026-10-05 10:04:43 +00:00
tax_label: source.taxLabel.toPrimitive(),
2024-07-19 15:02:19 +00:00
tax_price: source.taxPrice.convertScale(2).toPrimitive(),
2024-07-15 16:53:33 +00:00
total_price: source.totalPrice.convertScale(2).toPrimitive(),
2024-07-02 20:15:59 +00:00
2026-10-19 11:55:16 +00:00
items: orderedItems.map((item, position) => ({ ...item, position })),
2024-07-02 20:15:59 +00:00
dealer_id: source.dealerId.toPrimitive(),
2024-10-03 14:23:46 +00:00
2024-10-08 16:53:22 +00:00
date_sent: source.dateSent.toPrimitive() === "" ? null : source.dateSent.toPrimitive(),
2024-05-26 17:09:43 +00:00
};
return quote;
}
}