import { Cart } from "../../../../model/cart"; import { SERVICE_LIST, Tariffs } from "../../../../model/tariff"; import { User } from "../../../../model/user"; export function calcCartData( user: User, cartItems: Cart.CartItem[], discounts: Cart.AnyDiscount[], privileges: Tariffs.Privilege[], promocode?: Cart.Promocode, ): Cart.CartTotal { const cartTotal: Cart.CartTotal = { items: [], totalPrice: 0, priceByService: { templategen: 0, squiz: 0, dwarfener: 0, }, }; debugger; // TODO layer 0 for (const discount of discounts) { if (discount.conditionType !== "userType" || discount.condition.userType !== user.Type) continue; cartItems.forEach(cartItem => { cartTotal.items.push({ envolvedDiscounts: [], item: cartItem.item, totalPrice: cartItem.price, }); cartTotal.totalPrice += cartItem.price; }); return cartTotal; } // TODO layer 1 if (promocode) { for (const discount of discounts) { if (discount.conditionType !== "user" || discount.condition.user !== user.ID || discount.condition.coupon !== promocode.name) continue; for (const cartItem of cartItems) { const cartItemTotal = calcCartItemWithPromocode(cartItem, discount, cartTotal.priceByService); cartTotal.items.push(cartItemTotal); cartTotal.totalPrice += cartItemTotal.totalPrice; } return cartTotal; } } for (const cartItem of cartItems) { const cartItemTotal: Cart.CartItemTotal = { item: cartItem.item, envolvedDiscounts: [], totalPrice: cartItem.price, }; if (isPackage(cartItem.item)) { // TODO implement for package throw new Error("unimplemented"); } const tariff = cartItem.item; const maxPrivilegeDiscount = findMaxApplicablePrivilegeDiscount(discounts, tariff); if (maxPrivilegeDiscount) { maxPrivilegeDiscount.target.products.forEach(product => { if (product.productId === tariff.id) { // TODO productId - ид продукта(тариф или пакет тарифов) или привилегии? Если второе, то откуда берется привилегия? cartItemTotal.totalPrice *= product.factor; cartItemTotal.envolvedDiscounts.push(maxPrivilegeDiscount._id); } }); } cartTotal.items.push(cartItemTotal); cartTotal.priceByService[tariff.service] += cartItemTotal.totalPrice; } // layer 2 SERVICE_LIST.forEach(service => { const serviceDiscount = findMaxServiceDiscount(service, discounts, cartTotal); if (serviceDiscount) cartTotal.priceByService[service] *= serviceDiscount.target.factor; cartTotal.totalPrice += cartTotal.priceByService[service]; }); // layer 3 const cartPurchasesAmountDiscount = findMaxCartPurchasesAmountDiscount(discounts, cartTotal); if (cartPurchasesAmountDiscount) cartTotal.totalPrice *= cartPurchasesAmountDiscount.factor; // layer 4 const totalPurchasesAmountDiscount = findMaxPurchasesAmountDiscount(discounts, user); if (totalPurchasesAmountDiscount) cartTotal.totalPrice *= totalPurchasesAmountDiscount.factor; return cartTotal; } function findMaxApplicablePrivilegeDiscount(discounts: Cart.AnyDiscount[], tariff: Tariffs.Tariff): Cart.PrivilegeDiscount | null { const applicableDiscounts = discounts.filter((discount): discount is Cart.PrivilegeDiscount => { return discount.conditionType === "privilege" && tariff.amount >= discount.condition.privilege.value; }); if (!applicableDiscounts.length) return null; const maxValueDiscount = applicableDiscounts.reduce( (prev, current) => current.condition.privilege.value > prev.condition.privilege.value ? current : prev ); return maxValueDiscount; } function findMaxCartPurchasesAmountDiscount(discounts: Cart.AnyDiscount[], cartTotal: Cart.CartTotal): Cart.CartPurchasesAmountDiscount | null { const applicableDiscounts = discounts.filter((discount): discount is Cart.CartPurchasesAmountDiscount => { return discount.conditionType === "cartPurchasesAmount" && discount.condition.cartPurchasesAmount >= cartTotal.totalPrice; }); if (!applicableDiscounts.length) return null; const maxValueDiscount = applicableDiscounts.reduce( (prev, current) => current.condition.cartPurchasesAmount > prev.condition.cartPurchasesAmount ? current : prev ); return maxValueDiscount; } function findMaxPurchasesAmountDiscount(discounts: Cart.AnyDiscount[], user: User): Cart.PurchasesAmountDiscount | null { const applicableDiscounts = discounts.filter((discount): discount is Cart.PurchasesAmountDiscount => { return discount.conditionType === "purchasesAmount" && discount.condition.purchasesAmount >= user.PurchasesAmount; }); if (!applicableDiscounts.length) return null; const maxValueDiscount = applicableDiscounts.reduce( (prev, current) => current.condition.purchasesAmount > prev.condition.purchasesAmount ? current : prev ); return maxValueDiscount; } function findMaxServiceDiscount( service: Tariffs.ServiceType, discounts: Cart.AnyDiscount[], cartTotal: Cart.CartTotal ): Cart.ServiceDiscount | null { const discountsForTariffService = discounts.filter((discount): discount is Cart.ServiceDiscount => { return ( discount.conditionType === "service" && discount.condition.service.id === service && discount.condition.service.value >= cartTotal.priceByService[service] ); }); if (!discountsForTariffService.length) return null; const maxValueDiscount = discountsForTariffService.reduce((prev, current) => { return current.condition.service.value > prev.condition.service.value ? current : prev; }); return maxValueDiscount; } function calcCartItemWithPromocode( cartItem: Cart.CartItem, discount: Cart.UserDiscount, priceByService: { [Key in Tariffs.ServiceType]: number; }, ): Cart.CartItemTotal { const cartItemTotal: Cart.CartItemTotal = { item: cartItem.item, envolvedDiscounts: [], totalPrice: 0, }; if (isPackage(cartItem.item)) { // TODO implement for package throw new Error("unimplemented"); } const tariff = cartItem.item; discount.target.products.forEach(product => { if (product.productId === tariff.id) { // TODO productId - ид продукта(тариф или пакет тарифов) или привилегии? Если второе, то откуда берется привилегия? cartItemTotal.totalPrice *= product.factor; cartItemTotal.envolvedDiscounts.push(discount._id); } }); priceByService[tariff.service] = cartItemTotal.totalPrice; return cartItemTotal; } export function packTariffs(tariffs: Tariffs.Tariff[], id: string, name: string): Tariffs.Package { const services: Tariffs.ServiceType[] = []; tariffs.forEach(tariff => { if (!services.includes(tariff.service)) services.push(tariff.service); }); return { id, name, services, tariffs, }; } export function isPackage(item: Tariffs.Tariff | Tariffs.Package): item is Tariffs.Package { return "tariffs" in item; }