193 lines
7.6 KiB
TypeScript
193 lines
7.6 KiB
TypeScript
import { CartData, PrivilegeCartData, TariffCartData } from "../../model/cart";
|
|
import { Discount } from "../../model/discount";
|
|
import { Tariff } from "../../model/tariff";
|
|
import { findCartDiscount, findDiscountFactor, findLoyaltyDiscount, findNkoDiscount, findPrivilegeDiscount, findServiceDiscount } from "./utils";
|
|
|
|
|
|
export function calcCart(tariffs: Tariff[], discounts: Discount[], purchasesAmount: number, userId: string, isUserNko?: boolean): CartData {
|
|
const cartData: CartData = {
|
|
services: [],
|
|
priceBeforeDiscounts: 0,
|
|
priceAfterDiscounts: 0,
|
|
allAppliedDiscounts: new Set(),
|
|
};
|
|
const privilegeAmountById = new Map<string, number>();
|
|
const servicePriceByKey = new Map<string, number>();
|
|
|
|
tariffs.forEach(tariff => {
|
|
if (tariff.privileges === undefined) return;
|
|
if (
|
|
(tariff.price || 0) > 0
|
|
&& tariff.privileges.length !== 1
|
|
) throw new Error("Price is defined for tariff with several privileges");
|
|
|
|
let serviceData = cartData.services.find(service => (service.serviceKey === "custom" && tariff.isCustom));
|
|
if (!serviceData && !tariff.isCustom) serviceData = cartData.services.find(service => service.serviceKey === tariff.privileges[0]?.serviceKey);
|
|
|
|
if (!serviceData) {
|
|
serviceData = {
|
|
serviceKey: tariff.isCustom ? "custom" : tariff.privileges[0]?.serviceKey,
|
|
tariffs: [],
|
|
price: 0,
|
|
};
|
|
cartData.services.push(serviceData);
|
|
}
|
|
|
|
const tariffCartData: TariffCartData = {
|
|
price: tariff.price ?? 0,
|
|
isCustom: tariff.isCustom,
|
|
privileges: [],
|
|
id: tariff._id,
|
|
name: tariff.name,
|
|
};
|
|
serviceData.tariffs.push(tariffCartData);
|
|
|
|
tariff.privileges.forEach(privilege => {
|
|
let privilegePrice = privilege.amount * privilege.price;
|
|
if (!tariff.price) tariffCartData.price += privilegePrice;
|
|
else privilegePrice = tariff.price;
|
|
|
|
const privilegeCartData: PrivilegeCartData = {
|
|
serviceKey: privilege.serviceKey,
|
|
privilegeId: privilege.privilegeId,
|
|
description: privilege.description,
|
|
price: privilegePrice,
|
|
amount: privilege.amount,
|
|
appliedDiscounts: new Set(),
|
|
};
|
|
|
|
privilegeAmountById.set(
|
|
privilege.privilegeId,
|
|
privilege.amount + (privilegeAmountById.get(privilege.privilegeId) ?? 0)
|
|
);
|
|
servicePriceByKey.set(
|
|
privilege.serviceKey,
|
|
privilegePrice + (servicePriceByKey.get(privilege.serviceKey) ?? 0)
|
|
);
|
|
|
|
tariffCartData.privileges.push(privilegeCartData);
|
|
});
|
|
|
|
serviceData.price += tariffCartData.price;
|
|
});
|
|
|
|
cartData.priceBeforeDiscounts = Array.from(servicePriceByKey.values()).reduce((a, b) => a + b, 0);
|
|
cartData.priceAfterDiscounts = cartData.priceBeforeDiscounts;
|
|
|
|
const nkoDiscount = findNkoDiscount(discounts);
|
|
if (isUserNko && nkoDiscount) {
|
|
cartData.allAppliedDiscounts.add(nkoDiscount);
|
|
|
|
cartData.services.forEach(service => {
|
|
service.tariffs.forEach(tariff => {
|
|
tariff.privileges.forEach(privilege => {
|
|
privilege.appliedDiscounts.add(nkoDiscount);
|
|
|
|
const discountAmount = privilege.price * (1 - findDiscountFactor(nkoDiscount));
|
|
|
|
privilege.price -= discountAmount;
|
|
tariff.price -= discountAmount;
|
|
service.price -= discountAmount;
|
|
cartData.priceAfterDiscounts -= discountAmount;
|
|
});
|
|
});
|
|
});
|
|
|
|
return cartData;
|
|
}
|
|
|
|
cartData.services.forEach(service => {
|
|
service.tariffs.forEach(tariff => {
|
|
tariff.privileges.forEach(privilege => {
|
|
const privilegeTotalAmount = privilegeAmountById.get(privilege.privilegeId) ?? 0;
|
|
|
|
const discount = findPrivilegeDiscount(privilege.privilegeId, privilegeTotalAmount, discounts, userId);
|
|
if (!discount) return;
|
|
|
|
cartData.allAppliedDiscounts.add(discount);
|
|
privilege.appliedDiscounts.add(discount);
|
|
|
|
const discountAmount = privilege.price * (1 - findDiscountFactor(discount));
|
|
|
|
privilege.price -= discountAmount;
|
|
tariff.price -= discountAmount;
|
|
service.price -= discountAmount;
|
|
cartData.priceAfterDiscounts -= discountAmount;
|
|
|
|
const serviceTotalPrice = servicePriceByKey.get(privilege.serviceKey);
|
|
if (!serviceTotalPrice) throw new Error(`Service key ${privilege.serviceKey} not found in servicePriceByKey`);
|
|
|
|
servicePriceByKey.set(privilege.serviceKey, serviceTotalPrice - discountAmount);
|
|
});
|
|
});
|
|
});
|
|
|
|
cartData.services.forEach(service => {
|
|
service.tariffs.map(tariff => {
|
|
tariff.privileges.forEach(privilege => {
|
|
const serviceTotalPrice = servicePriceByKey.get(privilege.serviceKey);
|
|
if (!serviceTotalPrice) throw new Error(`Service key ${privilege.serviceKey} not found in servicePriceByKey`);
|
|
|
|
const discount = findServiceDiscount(privilege.serviceKey, serviceTotalPrice, discounts, userId);
|
|
if (!discount) return;
|
|
|
|
cartData.allAppliedDiscounts.add(discount);
|
|
privilege.appliedDiscounts.add(discount);
|
|
|
|
const discountAmount = privilege.price * (1 - findDiscountFactor(discount));
|
|
|
|
privilege.price -= discountAmount;
|
|
tariff.price -= discountAmount;
|
|
service.price -= discountAmount;
|
|
cartData.priceAfterDiscounts -= discountAmount;
|
|
});
|
|
});
|
|
});
|
|
|
|
const userDiscount = discounts.find(discount => discount.Condition.User === userId);
|
|
|
|
const cartDiscount = findCartDiscount(cartData.priceAfterDiscounts, discounts);
|
|
if (cartDiscount) {
|
|
cartData.services.forEach(service => {
|
|
if (service.serviceKey === userDiscount?.Condition.Group) return;
|
|
|
|
service.tariffs.forEach(tariff => {
|
|
tariff.privileges.forEach(privilege => {
|
|
cartData.allAppliedDiscounts.add(cartDiscount);
|
|
privilege.appliedDiscounts.add(cartDiscount);
|
|
|
|
const discountAmount = privilege.price * (1 - findDiscountFactor(cartDiscount));
|
|
|
|
privilege.price -= discountAmount;
|
|
tariff.price -= discountAmount;
|
|
service.price -= discountAmount;
|
|
cartData.priceAfterDiscounts -= discountAmount;
|
|
});
|
|
});
|
|
});
|
|
}
|
|
|
|
const loyalDiscount = findLoyaltyDiscount(purchasesAmount, discounts);
|
|
if (loyalDiscount) {
|
|
cartData.services.forEach(service => {
|
|
if (service.serviceKey === userDiscount?.Condition.Group) return;
|
|
|
|
service.tariffs.forEach(tariff => {
|
|
tariff.privileges.forEach(privilege => {
|
|
cartData.allAppliedDiscounts.add(loyalDiscount);
|
|
privilege.appliedDiscounts.add(loyalDiscount);
|
|
|
|
const discountAmount = privilege.price * (1 - findDiscountFactor(loyalDiscount));
|
|
|
|
privilege.price -= discountAmount;
|
|
tariff.price -= discountAmount;
|
|
service.price -= discountAmount;
|
|
cartData.priceAfterDiscounts -= discountAmount;
|
|
});
|
|
});
|
|
});
|
|
}
|
|
|
|
return cartData;
|
|
}
|