@chiper-inc/ecommerce-lib
Version:
Chiper Inc Ecommerce Lib
267 lines (252 loc) • 7.37 kB
text/typescript
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,
};
}
}