UNPKG

@chiper-inc/ecommerce-lib

Version:
329 lines (305 loc) 8.07 kB
import { CartEvent } from '../event'; import { Item, ItemOptions, ItemType } from "./item"; import { New } from './new'; import { Price, PriceOptions } from "./price"; import { Product } from "./product"; export type PromotionOptions = ItemOptions & { products: Product[]; termsUrl: string; banner?: string; maxQuantity?: number; }; export class Promotion extends Item { public readonly products: Product[]; public readonly termsUrl: string; public readonly banner?: string; public readonly _maxQuantity?: number; constructor({ stock, multipleQuantity, name, warehouseId, image, id, packagingType, products, termsUrl, banner, quantity, maxQuantity, }: PromotionOptions, rate: number) { super(ItemType.COMBO, { stock, multipleQuantity, name, image, id, packagingType, warehouseId, measurement:{quantity:0, unit:""} }, rate); this.products = products; this.termsUrl = termsUrl; this.banner = banner; this._maxQuantity = maxQuantity; this.quantity = quantity; } override get stock(): number { if ( this.products && this.products.length > 0 && this.products.every((p) => p.stock !== undefined) ) { return Math.min( ...this.products.map((p) => Math.floor(p.stock / p.multipleQuantity)) ); } return this._stock; } override set stock(stock: number) { this._stock = stock; for (const product of this.products) { product.stock = stock * product.multipleQuantity; } if (this.quantity && this.stock < this.quantity) { this.emit(CartEvent.NEWS, { id: this.id, cardType: this.stock === 0 ? "unavailable" : "lowStock", productType: this.type, medium: this.image, name: this.name, packagingType: this.packagingType, previousTotal: this.regularPrice, quantity: this.quantity, stock: this.stock, total: this.regularPrice, warehouseId: this.warehouseId, } as New); } } get subtotal(): number | null { if(this.quantity == null) return null; return +this.products .reduce((total: number, product: Product) => total + (product.subtotal??0), 0) .toFixed(2); } get total(): number | null { if(this.quantity == null) return null; return +this.products.reduce( (total: number, product: Product) => total + (product.total??0), 0 ).toFixed(2); } get totalDollars(): number | null { if(this.quantity == null) return null; return +(this.products.reduce( (total: number, product: Product) => total + (product.total??0), 0 )* this.rate).toFixed(2); } increase() { this.quantity = this.quantity == null ? this.minQuantity : this.quantity + this.multipleQuantity; } decrease() { this.quantity = this.quantity == null ? this.minQuantity : this.quantity - this.multipleQuantity; } override set quantity(quantity: number | undefined) { super.quantity = quantity; if(quantity != null) { this.products.forEach((product: Product) => { product.quantity = quantity * product.multipleQuantity; }); } } override get quantity(): number | undefined { return super.quantity; } get regularPrice(): number { return +this.products.reduce( (total: number, product: Product) => total + product.multipleQuantity * product.regularPrice, 0 ).toFixed(2); } get regularPriceDolar(): number{ return +(this.products.reduce( (total: number, product: Product) => total + product.multipleQuantity * product.regularPrice, 0 ) * this.rate).toFixed(2); } get price(): number { return +this.products.reduce( (total: number, product: Product) => total + product.multipleQuantity * product.price, 0 ).toFixed(2); } get discountedPrice(): number | undefined { if ( this.products.some((product) => product.discountedPrice !== undefined) ) { return +this.products.reduce((total: number, product: Product) => { return ( total + product.multipleQuantity * (product.discountedPrice ?? product.regularPrice) ); }, 0).toFixed(2); } return undefined; } get chiperPrice(): number { return +this.products.reduce((total: number, product: Product) => ( product.multipleQuantity * (product.chiperPrice || product.regularPrice) + total ) , 0).toFixed(2); } get maxQuantity(): number | undefined { if(this._maxQuantity) return this._maxQuantity; return this.products.reduce( (total: number | undefined, product: Product) => { let max = product.maxQuantity; if (max === undefined) return total; max = +(max / product.multipleQuantity).toFixed(0); return total === undefined ? max : Math.min(total, max); }, undefined ); } static fromShopCart({ products, stock, quantity, name, medium, id, warehouseId, packagingType, termsUrl, banner, maximumQuantity, }: any, rate: number): any { return new Promotion({ products: products.map((product: any) => Product.fromShopCart( Object.assign(product, { multipleQuantity: product.quantity, stock: product.stock ?? stock * product.quantity, }), rate ) ), warehouseId, stock, quantity, name, image: medium, id, packagingType, termsUrl, banner, maxQuantity: maximumQuantity, measurement:{quantity:0, unit:""} }, rate); } static from({ products, quantity, stock, name, medium, id, warehouseId, packagingType, termsUrl, maximumQuantity, maxQuantity, banner, }: any, rate: number): Item { return new Promotion({ products: products.map( (product: any) => new Product({ ...product, prices: product.prices.map( (p: PriceOptions) => new Price({ ...p, expireDate: p.expireDate && new Date(p.expireDate), }) ), multipleQuantity: product.multipleQuantity ?? Math.max(product.quantity / quantity, 1), stock: product.stock ?? stock * product.quantity, }, rate) ), stock, quantity, name, image: medium, id, warehouseId, packagingType, termsUrl, maxQuantity: maxQuantity ?? maximumQuantity, banner, measurement:{quantity:0, unit:""} }, rate); } static fromCatalog({ detailsDescription, stock, name, medium, id, warehouseId, packagingType, termsUrl, banner, quantity, maxQuantity, }: any, rate: number): Promotion { return new Promotion({ products: detailsDescription.map((detail: any) => Product.fromPromoDetail(detail, rate) ), stock, name, image: medium, id, warehouseId, packagingType, termsUrl, banner, quantity, maxQuantity, measurement:{quantity:0, unit:""} }, rate); } clone(): Promotion { return new Promotion({ id: this.id, warehouseId: this.warehouseId, name: this.name, image: this.image, packagingType: this.packagingType, products: this.products, quantity: this.quantity, stock: this.stock, termsUrl: this.termsUrl, banner: this.banner, minQuantity: this.minQuantity, multipleQuantity: this.multipleQuantity, measurement:{quantity:0, unit:""} }, this.rate); } // create toJSON function toJSON(): any { return { ...super.toJSON(), products: this.products.map((product: Product) => product.toJSON()), termsUrl: this.termsUrl, banner: this.banner, citrusAdId: "" }; } }