import { getDiscount, getMaximumValue, roundToMultipleQuantity, } from "./helpers"; import { ItemQuantityError } from "./itemQuantityError"; export enum ItemType { PRODUCT = "PRODUCT", COMBO = "COMBO", } export type ItemOptions = { id: number | string; warehouseId: number; name: string; stock: number; image: string; packagingType: string; minQuantity?: number; multipleQuantity?: number; }; export abstract class Item { public readonly id: number | string; public readonly warehouseId: number; public readonly type: ItemType; public readonly name: string; protected _quantity = 0; public readonly _stock: number; public readonly image: string; public readonly packagingType: string; public readonly minQuantity: number; public readonly multipleQuantity: number; constructor( type: ItemType, { stock, multipleQuantity, name, image, id, warehouseId, packagingType, minQuantity, }: ItemOptions ) { this.id = id; this.warehouseId = warehouseId; this.type = type; this.name = name; this._stock = stock; this.image = image; this.packagingType = packagingType; this.minQuantity = minQuantity ?? 1; this.multipleQuantity = multipleQuantity ?? 1; } get stock(): number { return this._stock; } abstract clone(): Item; set quantity(quantity: number) { if (quantity && quantity < this.minQuantity) { throw new ItemQuantityError( `Quantity can't be less than minQuantity(${this.minQuantity})`, this.minQuantity, "MinQuantity" ); } if (quantity && quantity > this.stock) { const newQuantity = getMaximumValue( this.stock, this.maxQuantity ?? this.stock, this.multipleQuantity ); throw new ItemQuantityError( `Quantity can't be more than stock(${this.stock})`, newQuantity, "Stock" ); } if (quantity && this.maxQuantity && quantity > this.maxQuantity) { const newQuantity = getMaximumValue( this.stock, this.maxQuantity, this.multipleQuantity ); throw new ItemQuantityError( `Quantity can't be more than maxQuantity(${this.maxQuantity})`, newQuantity, "MaxQuantity" ); } //? always validate after `maxQuantity` if (quantity && quantity % this.multipleQuantity !== 0) { const newQuantity = roundToMultipleQuantity( quantity, this.multipleQuantity, this.stock ); throw new ItemQuantityError( `Quantity can't be different of a multipleQuantity(${this.multipleQuantity})`, newQuantity, "MultipleQuantity" ); } this._quantity = quantity; } get quantity(): number { return this._quantity; } /** `discount` is the difference between `regularPrice` and `discountedPrice` in %*/ get discount(): number { return this.discountedPrice ? getDiscount(this.regularPrice, this.discountedPrice) : 0; } abstract get maxQuantity(): number | undefined; abstract get regularPrice(): number; abstract get discountedPrice(): number | undefined; abstract get total(): number; abstract get subtotal(): number; // create toJson method toJSON() { return { id: this.id, warehouseId: this.warehouseId, type: this.type, name: this.name, stock: this.stock, quantity: this.quantity, image: this.image, medium: this.image, // deprecated packagingType: this.packagingType, minQuantity: this.minQuantity, multipleQuantity: this.multipleQuantity, total: this.total, subtotal: this.subtotal, maxQuantity: this.maxQuantity, maximumQuantity: this.maxQuantity, // deprecated regularPrice: this.regularPrice, discountedPrice: this.discountedPrice, }; } }