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(); const servicePriceByKey = new Map(); 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; }