UNPKG

@chiper-inc/ecommerce-lib

Version:
267 lines (252 loc) 7.37 kB
import { MaxQuantityHelper, getDiscount } from "./helpers"; export type PriceOptions = { ico: number; iva: number; base: number; subtotal: number; total: number; measurementTotal: number; externalId?: number; maxQuantity?: number; discountedExternalId?: number; expireDate?: Date | null; quantity?: number; discount?: number | null; }; export class Price { public readonly ico: number; public readonly iva: number; public readonly base: number; public readonly subtotal: number; public readonly total: number; public readonly measurementTotal: number; public readonly externalId?: number; public readonly maxQuantity?: number; public readonly discountedExternalId?: number; public readonly expireDate?: Date | null; private _quantity?: number; public readonly discount?: number | null; constructor({ ico, iva, base, subtotal, total, measurementTotal, externalId, maxQuantity, discountedExternalId, expireDate, quantity, discount, }: PriceOptions) { this.ico = ico; this.iva = iva; this.base = base; this.subtotal = subtotal; this.total = total; this.measurementTotal = measurementTotal; this.externalId = externalId; this.maxQuantity = maxQuantity; this.discountedExternalId = discountedExternalId; this.expireDate = expireDate; this._quantity = quantity; this.discount = discount; } get isExpired(): boolean { return !!this.expireDate && new Date() > this.expireDate; } /** * Set the price quantity until maxQuantity and returns the remaining quantity * @param quantity the quantity * @returns the remaining quantity */ set quantity(quantity: number | undefined) { if (quantity != undefined) { if (this.isExpired && quantity > 0) { throw new Error("Price is expired"); } if ( this.maxQuantity !== undefined && this.maxQuantity !== null && this.maxQuantity !== 0 && quantity > this.maxQuantity ) { throw new Error( `Quantity can't be higher than maxQuantity(${this.maxQuantity})` ); } } this._quantity = quantity; } get quantity(): number | undefined { return this._quantity; } /** * Calculates the total based on quantity * * @returns the total * quantity */ get extendedTotal() { return this.quantity == null ? null : this.total * this.quantity; } /** * Calculates the subtotal based on quantity * * @returns the total * subtotal */ get extendedSubtotal() { return this.quantity == null ? null : this.subtotal * this.quantity; } static fromPricing(json: any): Price[] { const prices = []; for (const item of json) { const { values, ico, iva, scheduleEndDate, discountedMaximumQuantity, maximumQuantity, } = item; const maxHelper = new MaxQuantityHelper( maximumQuantity, discountedMaximumQuantity ); for (const value of values) { const { externalId, discountedExternalId, startQuantity, endQuantity } = value; if (value.discountedTotal && value.discountedTotal < value.total) { const { discountedPrice: base, discountedSubtotal: subtotal, discountedTotal: total, discountedTotalPerUnit, total: regularTotal, } = value; const expireDate = scheduleEndDate ? new Date(scheduleEndDate) : undefined; const maxQuantity = expireDate && expireDate < new Date() ? 0 : maxHelper.discountedMaxQuantity(startQuantity, endQuantity); if (maxQuantity !== 0) { prices.push( new Price({ ico, iva, base, subtotal, total, externalId, maxQuantity, discountedExternalId, measurementTotal: discountedTotalPerUnit, expireDate: scheduleEndDate ? new Date(scheduleEndDate) : undefined, discount: getDiscount(regularTotal, total), }) ); } } const { price: base, subtotal, total, totalPerUnit } = value; const maxQuantity = maxHelper.maxQuantity(startQuantity, endQuantity); prices.push( new Price({ ico, iva, base, subtotal, total, measurementTotal: totalPerUnit, externalId, maxQuantity, }) ); } } return prices; } static fromCatalogue(json: any): Price[] { const prices: Price[] = []; const maxHelper = new MaxQuantityHelper( json.maximumQuantity, json.discountedMaximumQuantity ); for (const item of json.prices) { if (item.discountedTotal) { const ico = item.discountedSubtotal - item.discountedBase; const iva = (item.discountedTotal - ico) / item.discountedBase - 1; const expireDate = json.scheduleEndDate ? new Date(json.scheduleEndDate) : undefined; const maxQuantity = expireDate && expireDate < new Date() ? 0 : maxHelper.discountedMaxQuantity( item.startQuantity, item.endQuantity ); if (maxQuantity !== 0) { prices.push( new Price({ ico, iva: Math.round(iva * 100) / 100, base: item.discountedBase, subtotal: item.discountedSubtotal, total: item.discountedTotal, measurementTotal: item.unitPrice, discount: item.discount, externalId: item.externalId, discountedExternalId: item.discountedExternalId, maxQuantity, expireDate, }) ); } } const ico = item.managerSubtotal - item.managerPrice; const iva = (item.managerTotal - ico) / item.managerPrice - 1; const maxQuantity = maxHelper.maxQuantity( item.startQuantity, item.endQuantity ); prices.push( new Price({ ico, iva: Math.round(iva * 100) / 100, base: item.managerPrice, subtotal: item.managerSubtotal, total: item.managerTotal, externalId: item.externalId, measurementTotal: item.unitPrice, maxQuantity, }) ); } return prices; } toJSON(customerTotal: number) { return { customerTotal, // deprecated ico: this.ico, iva: this.iva, base: this.base, subtotal: this.subtotal, managerSubtotal: this.subtotal, // deprecated total: this.total, measurementTotal: this.measurementTotal, externalId: this.externalId, maxQuantity: this.maxQuantity, discountedExternalId: this.discountedExternalId ? this.discountedExternalId : null, expireDate: this.expireDate, quantity: this.quantity, discount: this.discount != null ? Math.round(this.discount * 100) / 100 : null, }; } }