@chiper-inc/ecommerce-lib
Version:
Chiper Inc Ecommerce Lib
329 lines (305 loc) • 8.07 kB
text/typescript
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: ""
};
}
}