import { Item, ItemOptions, ItemType } from "./item"; import { Price, PriceOptions } from "./price"; import { Product } from "./product"; export type PromotionOptions = ItemOptions & { products: Product[]; termsUrl: string; banner?: string; quantity: number; }; export class Promotion extends Item { public readonly products: Product[]; public readonly termsUrl: string; public readonly banner?: string; constructor({ stock, multipleQuantity, name, warehouseId, image, id, packagingType, products, termsUrl, banner, quantity, }: PromotionOptions) { super(ItemType.COMBO, { stock, multipleQuantity, name, image, id, packagingType, warehouseId, }); this.products = products; this.termsUrl = termsUrl; this.banner = banner; this.quantity = quantity; } override get stock(): number { const stocks = this.products.map((p) => Math.floor(p.stock / p.multipleQuantity) ); stocks.push(this._stock); return Math.min(...stocks); } get subtotal(): number { return +this.products .reduce((total: number, product: Product) => total + product.subtotal, 0) .toFixed(2); } get total(): number { return +this.products.reduce( (total: number, product: Product) => total + product.total, 0 ); } increase() { this.quantity = this.quantity + this.multipleQuantity; } decrease() { this.quantity = this.quantity - this.multipleQuantity; } override set quantity(quantity: number) { super.quantity = quantity; this.products.forEach((product: Product) => { product.quantity = quantity * product.multipleQuantity; }); } override get quantity(): number { return super.quantity; } get regularPrice(): number { return this.products.reduce( (total: number, product: Product) => total + product.multipleQuantity * product.regularPrice, 0 ); } 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); } return undefined; } get maxQuantity(): number | undefined { 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, }: any): any { return new Promotion({ products: products.map((product: any) => Product.fromShopCart( Object.assign(product, { multipleQuantity: product.quantity, stock: product.stock ?? stock * product.quantity, }) ) ), warehouseId, stock, quantity, name, image: medium, id, packagingType, termsUrl, banner, }); } static from({ products, quantity, stock, name, medium, id, warehouseId, packagingType, termsUrl, banner, }: any): 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: Math.max(product.quantity / quantity, 1), stock: product.stock ?? stock * product.quantity, }) ), stock, quantity, name, image: medium, id, warehouseId, packagingType, termsUrl, banner, }); } static fromCatalog({ detailsDescription, stock, quantity = 0, name, medium, id, warehouseId, packagingType, termsUrl, banner, }: any): Promotion { return new Promotion({ products: detailsDescription.map((detail: any) => Product.fromPromoDetail(detail)), stock, quantity, name, image: medium, id, warehouseId, packagingType, termsUrl, banner, }); } 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, }); } // create toJSON function toJSON(): any { return { ...super.toJSON(), products: this.products.map((product: Product) => product.toJSON()), termsUrl: this.termsUrl, banner: this.banner, }; } }