UIKit/lib/utils/cart/calcCart.ts
nflnkr 79adf3ca86 add cart privilege applied discounts field
change allAppliedDiscounts cart field type to Set
2024-03-27 17:29:32 +03:00

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;
}