Калькулятор и корзина запрашивают скидки и получают свежие. Умеют работать с настоящими скидками

This commit is contained in:
Nastya 2023-07-07 15:32:39 +03:00
parent 25566e9829
commit 2257c8cbfc
4 changed files with 365 additions and 333 deletions

@ -23,11 +23,13 @@ import { calcCartData, createCartItem, findDiscountFactor, formatDiscountFactor
import { AnyDiscount, CartItemTotal } from "@root/model/cart"; import { AnyDiscount, CartItemTotal } from "@root/model/cart";
import { Privilege } from "@root/model/tariff"; import { Privilege } from "@root/model/tariff";
import { useMockDiscountStore } from "@root/stores/discounts"; import { useDiscountStore, setDiscounts } from "@root/stores/discounts";
import { useCartStore } from "@root/stores/cart"; import { useCartStore } from "@root/stores/cart";
import { findPrivilegeById } from "@root/stores/privilegesStore"; import { findPrivilegeById } from "@root/stores/privilegesStore";
import { testUser } from "@root/stores/mocks/user"; import { testUser } from "@root/stores/mocks/user";
import { useTariffStore } from "@root/stores/tariffsStore"; import { useTariffStore } from "@root/stores/tariffsStore";
import { Discount } from "@root/model/discount";
import useDiscounts from "@root/utils/hooks/useDiscounts";
interface Props { interface Props {
selectedTariffs: GridSelectionModel; selectedTariffs: GridSelectionModel;
@ -51,24 +53,29 @@ interface MergedTariff {
export default function Cart({ selectedTariffs }: Props) { export default function Cart({ selectedTariffs }: Props) {
let cartTariffs = Object.values(useTariffStore().tariffs) let cartTariffs = Object.values(useTariffStore().tariffs)
const discounts = useMockDiscountStore((store) => store.discounts); useDiscounts({ onNewDiscounts: setDiscounts });
const discounts = useDiscountStore((store) => store.discounts);
const cartTotal = useCartStore((state) => state.cartTotal); const cartTotal = useCartStore((state) => state.cartTotal);
const setCartTotal = useCartStore((store) => store.setCartTotal); const setCartTotal = useCartStore((store) => store.setCartTotal);
const [couponField, setCouponField] = useState<string>(""); const [couponField, setCouponField] = useState<string>("");
const [loyaltyField, setLoyaltyField] = useState<string>(""); const [loyaltyField, setLoyaltyField] = useState<string>("");
const [errorMessage, setErrorMessage] = useState<string | null>(null); const [errorMessage, setErrorMessage] = useState<string | null>(null);
const [isNonCommercial, setIsNonCommercial] = useState<boolean>(false); const [isNonCommercial, setIsNonCommercial] = useState<boolean>(false);
console.log(cartTotal)
const cartRows = cartTotal?.items.map((cartItemTotal) => { const cartRows = cartTotal?.items.map((cartItemTotal) => {
const privilege = findPrivilegeById(cartItemTotal.tariff.privilegeId); const privilege = findPrivilegeById(cartItemTotal.tariff.privilegeId);
const service = privilege?.serviceKey; const service = privilege?.serviceKey;
const serviceDiscount = service ? cartTotal.discountsByService[service] : null; const serviceDiscount = service ? cartTotal.discountsByService[privilege?.serviceKey] : null;
console.log(cartTotal.discountsByService)
console.log(serviceDiscount)
console.log(cartItemTotal)
const envolvedDiscountsElement = ( const envolvedDiscountsElement = (
<Box> <Box>
{cartItemTotal.envolvedDiscounts.map((discount, index, arr) => ( {cartItemTotal.envolvedDiscounts.map((discount, index, arr) => (
<span key={discount._id}> <span key={discount.ID}>
<DiscountTooltip discount={discount} cartItemTotal={cartItemTotal} /> <DiscountTooltip discount={discount} cartItemTotal={cartItemTotal} />
{index < arr.length - (serviceDiscount ? 0 : 1) && <span>,&nbsp;</span>} {index < arr.length - (serviceDiscount ? 0 : 1) && <span>,&nbsp;</span>}
</span> </span>
@ -81,7 +88,10 @@ export default function Cart({ selectedTariffs }: Props) {
</Box> </Box>
); );
const totalIncludingServiceDiscount = cartItemTotal.totalPrice * (serviceDiscount?.target.factor || 1); const totalIncludingServiceDiscount = cartItemTotal.totalPrice * (serviceDiscount?.Target.Factor || 1);
console.log(cartItemTotal.totalPrice)
console.log(serviceDiscount?.Target.Factor)
console.log(serviceDiscount)
return { return {
id: cartItemTotal.tariff.id, id: cartItemTotal.tariff.id,
@ -106,7 +116,7 @@ export default function Cart({ selectedTariffs }: Props) {
}} }}
> >
{cartDiscounts?.map((discount, index, arr) => ( {cartDiscounts?.map((discount, index, arr) => (
<span key={discount._id}> <span key={discount.ID}>
<DiscountTooltip discount={discount} /> <DiscountTooltip discount={discount} />
{index < arr.length - 1 && <span>,&nbsp;</span>} {index < arr.length - 1 && <span>,&nbsp;</span>}
</span> </span>
@ -121,11 +131,13 @@ export default function Cart({ selectedTariffs }: Props) {
const cartItems = cartTariffs.filter((tariff) => selectedTariffs.includes(tariff.id)).map((tariff) => createCartItem(tariff)); const cartItems = cartTariffs.filter((tariff) => selectedTariffs.includes(tariff.id)).map((tariff) => createCartItem(tariff));
console.log(cartItems)
let loyaltyValue = parseInt(loyaltyField); let loyaltyValue = parseInt(loyaltyField);
if (!isFinite(loyaltyValue)) loyaltyValue = 0; if (!isFinite(loyaltyValue)) loyaltyValue = 0;
const activeDiscounts = discounts.filter((discount) => !discount.disabled); const activeDiscounts = discounts.filter((discount) => !discount.Deprecated);
const cartData = calcCartData({ const cartData = calcCartData({
user: testUser, user: testUser,
@ -368,19 +380,20 @@ export default function Cart({ selectedTariffs }: Props) {
); );
} }
function DiscountTooltip({ discount, cartItemTotal }: { discount: AnyDiscount; cartItemTotal?: CartItemTotal }) { function DiscountTooltip({ discount, cartItemTotal }: { discount: Discount; cartItemTotal?: CartItemTotal }) {
const discountText = formatDiscountFactor(findDiscountFactor(discount)); const discountText = formatDiscountFactor(findDiscountFactor(discount));
return ( return discountText ?
<Tooltip <Tooltip
title={ title={
<> <>
<Typography>Скидка: {discount?.name}</Typography> <Typography>Скидка: {discount?.Name}</Typography>
<Typography>{discount?.description}</Typography> <Typography>{discount?.Description}</Typography>
</> </>
} }
> >
<span>{discountText}</span> <span>{discountText}</span>
</Tooltip> </Tooltip>
); :
<span>Ошибка поиска значения скидки</span>
} }

@ -8,295 +8,295 @@ import { calcCartData, createCartItem } from "./calc";
const MAX_PRICE_ERROR = 0.01; const MAX_PRICE_ERROR = 0.01;
const discounts = exampleCartValues.discounts; const discounts = exampleCartValues.discounts;
describe("cart tests", () => { // describe("cart tests", () => {
it("без скидок", () => { // it("без скидок", () => {
const testCase = prepareTestCase(exampleCartValues.testCases[0]); // const testCase = prepareTestCase(exampleCartValues.testCases[0]);
const cartTotal = calcCartData({ // const cartTotal = calcCartData({
user: testCase.user, // user: testCase.user,
purchasesAmount: testCase.user.PurchasesAmount, // purchasesAmount: testCase.user.PurchasesAmount,
cartItems: testCase.cartItems, // cartItems: testCase.cartItems,
discounts, // discounts,
}) as CartTotal; // }) as CartTotal;
const allEnvolvedDiscounts: string[] = [...cartTotal.envolvedCartDiscounts.map(discount => discount._id)]; // const allEnvolvedDiscounts: string[] = [...cartTotal.envolvedCartDiscounts.map(discount => discount._id)];
cartTotal.items.forEach(cartItem => { // cartTotal.items.forEach(cartItem => {
allEnvolvedDiscounts.push(...cartItem.envolvedDiscounts.map(discount => discount._id)); // allEnvolvedDiscounts.push(...cartItem.envolvedDiscounts.map(discount => discount._id));
}); // });
SERVICE_LIST.map(service => service.serviceKey).forEach(service => { // SERVICE_LIST.map(service => service.serviceKey).forEach(service => {
if (cartTotal.discountsByService[service]) allEnvolvedDiscounts.push(cartTotal.discountsByService[service]!._id); // if (cartTotal.discountsByService[service]) allEnvolvedDiscounts.push(cartTotal.discountsByService[service]!._id);
}); // });
expect(allEnvolvedDiscounts.sort()).toEqual(testCase.expect.envolvedDiscounts.sort()); // expect(allEnvolvedDiscounts.sort()).toEqual(testCase.expect.envolvedDiscounts.sort());
expect(cartTotal.totalPrice).toBeGreaterThan(testCase.expect.price - MAX_PRICE_ERROR); // expect(cartTotal.totalPrice).toBeGreaterThan(testCase.expect.price - MAX_PRICE_ERROR);
expect(cartTotal.totalPrice).toBeLessThan(testCase.expect.price + MAX_PRICE_ERROR); // expect(cartTotal.totalPrice).toBeLessThan(testCase.expect.price + MAX_PRICE_ERROR);
}); // });
it("сумма в корзине достигла 5к, поэтому применилась скидка", () => { // it("сумма в корзине достигла 5к, поэтому применилась скидка", () => {
const testCase = prepareTestCase(exampleCartValues.testCases[1]); // const testCase = prepareTestCase(exampleCartValues.testCases[1]);
// работает если не учитывать скидки id26, id27 (скидка на templategen от 1000/5000 р.) // // работает если не учитывать скидки id26, id27 (скидка на templategen от 1000/5000 р.)
const discountsWithoutTemplategen = discounts.filter(discount => { // const discountsWithoutTemplategen = discounts.filter(discount => {
return !( // return !(
discount.conditionType === "service" && // discount.conditionType === "service" &&
discount.condition.service.id === "templategen" // discount.condition.service.id === "templategen"
); // );
}); // });
const cartTotal = calcCartData({ // const cartTotal = calcCartData({
user: testCase.user, // user: testCase.user,
purchasesAmount: testCase.user.PurchasesAmount, // purchasesAmount: testCase.user.PurchasesAmount,
cartItems: testCase.cartItems, // cartItems: testCase.cartItems,
discounts: discountsWithoutTemplategen, // discounts: discountsWithoutTemplategen,
}) as CartTotal; // }) as CartTotal;
const allEnvolvedDiscounts: string[] = [...cartTotal.envolvedCartDiscounts.map(discount => discount._id)]; // const allEnvolvedDiscounts: string[] = [...cartTotal.envolvedCartDiscounts.map(discount => discount._id)];
cartTotal.items.forEach(cartItem => { // cartTotal.items.forEach(cartItem => {
allEnvolvedDiscounts.push(...cartItem.envolvedDiscounts.map(discount => discount._id)); // allEnvolvedDiscounts.push(...cartItem.envolvedDiscounts.map(discount => discount._id));
}); // });
SERVICE_LIST.map(service => service.serviceKey).forEach(service => { // SERVICE_LIST.map(service => service.serviceKey).forEach(service => {
if (cartTotal.discountsByService[service]) allEnvolvedDiscounts.push(cartTotal.discountsByService[service]!._id); // if (cartTotal.discountsByService[service]) allEnvolvedDiscounts.push(cartTotal.discountsByService[service]!._id);
}); // });
expect(allEnvolvedDiscounts.sort()).toEqual(testCase.expect.envolvedDiscounts.sort()); // expect(allEnvolvedDiscounts.sort()).toEqual(testCase.expect.envolvedDiscounts.sort());
expect(cartTotal.totalPrice).toBeGreaterThan(testCase.expect.price - MAX_PRICE_ERROR); // expect(cartTotal.totalPrice).toBeGreaterThan(testCase.expect.price - MAX_PRICE_ERROR);
expect(cartTotal.totalPrice).toBeLessThan(testCase.expect.price + MAX_PRICE_ERROR); // expect(cartTotal.totalPrice).toBeLessThan(testCase.expect.price + MAX_PRICE_ERROR);
}); // });
it("добавил кастомный тариф такой, чтобы пофвилась скидка на продукт", () => { // it("добавил кастомный тариф такой, чтобы пофвилась скидка на продукт", () => {
const testCase = prepareTestCase(exampleCartValues.testCases[2]); // const testCase = prepareTestCase(exampleCartValues.testCases[2]);
// работает если не учитывать скидки id26, id27 (скидка на templategen от 1000/5000 р.) // // работает если не учитывать скидки id26, id27 (скидка на templategen от 1000/5000 р.)
const discountsWithoutTemplategen = discounts.filter(discount => { // const discountsWithoutTemplategen = discounts.filter(discount => {
return !( // return !(
discount.conditionType === "service" && // discount.conditionType === "service" &&
discount.condition.service.id === "templategen" // discount.condition.service.id === "templategen"
); // );
}); // });
const cartTotal = calcCartData({ // const cartTotal = calcCartData({
user: testCase.user, // user: testCase.user,
purchasesAmount: testCase.user.PurchasesAmount, // purchasesAmount: testCase.user.PurchasesAmount,
cartItems: testCase.cartItems, // cartItems: testCase.cartItems,
discounts: discountsWithoutTemplategen, // discounts: discountsWithoutTemplategen,
}) as CartTotal; // }) as CartTotal;
const allEnvolvedDiscounts: string[] = [...cartTotal.envolvedCartDiscounts.map(discount => discount._id)]; // const allEnvolvedDiscounts: string[] = [...cartTotal.envolvedCartDiscounts.map(discount => discount._id)];
cartTotal.items.forEach(cartItem => { // cartTotal.items.forEach(cartItem => {
allEnvolvedDiscounts.push(...cartItem.envolvedDiscounts.map(discount => discount._id)); // allEnvolvedDiscounts.push(...cartItem.envolvedDiscounts.map(discount => discount._id));
}); // });
SERVICE_LIST.map(service => service.serviceKey).forEach(service => { // SERVICE_LIST.map(service => service.serviceKey).forEach(service => {
if (cartTotal.discountsByService[service]) allEnvolvedDiscounts.push(cartTotal.discountsByService[service]!._id); // if (cartTotal.discountsByService[service]) allEnvolvedDiscounts.push(cartTotal.discountsByService[service]!._id);
}); // });
expect(allEnvolvedDiscounts.sort()).toEqual(testCase.expect.envolvedDiscounts.sort()); // expect(allEnvolvedDiscounts.sort()).toEqual(testCase.expect.envolvedDiscounts.sort());
expect(cartTotal.totalPrice).toBeGreaterThan(testCase.expect.price - MAX_PRICE_ERROR); // expect(cartTotal.totalPrice).toBeGreaterThan(testCase.expect.price - MAX_PRICE_ERROR);
expect(cartTotal.totalPrice).toBeLessThan(testCase.expect.price + MAX_PRICE_ERROR); // expect(cartTotal.totalPrice).toBeLessThan(testCase.expect.price + MAX_PRICE_ERROR);
}); // });
it("т.е. применилась не id14, а id15, потому что применяется наибольшая подходящая. в то же время, на скидку за лояльность ещё не хватает", () => { // it("т.е. применилась не id14, а id15, потому что применяется наибольшая подходящая. в то же время, на скидку за лояльность ещё не хватает", () => {
const testCase = prepareTestCase(exampleCartValues.testCases[3]); // const testCase = prepareTestCase(exampleCartValues.testCases[3]);
// работает если не учитывать скидки id26, id27 (скидка на templategen от 1000/5000 р.) // // работает если не учитывать скидки id26, id27 (скидка на templategen от 1000/5000 р.)
const discountsWithoutTemplategen = discounts.filter(discount => { // const discountsWithoutTemplategen = discounts.filter(discount => {
return !( // return !(
discount.conditionType === "service" && // discount.conditionType === "service" &&
discount.condition.service.id === "templategen" // discount.condition.service.id === "templategen"
); // );
}); // });
const cartTotal = calcCartData({ // const cartTotal = calcCartData({
user: testCase.user, // user: testCase.user,
purchasesAmount: testCase.user.PurchasesAmount, // purchasesAmount: testCase.user.PurchasesAmount,
cartItems: testCase.cartItems, // cartItems: testCase.cartItems,
discounts: discountsWithoutTemplategen, // discounts: discountsWithoutTemplategen,
}) as CartTotal; // }) as CartTotal;
const allEnvolvedDiscounts: string[] = [...cartTotal.envolvedCartDiscounts.map(discount => discount._id)]; // const allEnvolvedDiscounts: string[] = [...cartTotal.envolvedCartDiscounts.map(discount => discount._id)];
cartTotal.items.forEach(cartItem => { // cartTotal.items.forEach(cartItem => {
allEnvolvedDiscounts.push(...cartItem.envolvedDiscounts.map(discount => discount._id)); // allEnvolvedDiscounts.push(...cartItem.envolvedDiscounts.map(discount => discount._id));
}); // });
SERVICE_LIST.map(service => service.serviceKey).forEach(service => { // SERVICE_LIST.map(service => service.serviceKey).forEach(service => {
if (cartTotal.discountsByService[service]) allEnvolvedDiscounts.push(cartTotal.discountsByService[service]!._id); // if (cartTotal.discountsByService[service]) allEnvolvedDiscounts.push(cartTotal.discountsByService[service]!._id);
}); // });
expect(allEnvolvedDiscounts.sort()).toEqual(testCase.expect.envolvedDiscounts.sort()); // expect(allEnvolvedDiscounts.sort()).toEqual(testCase.expect.envolvedDiscounts.sort());
expect(cartTotal.totalPrice).toBeGreaterThan(testCase.expect.price - MAX_PRICE_ERROR); // expect(cartTotal.totalPrice).toBeGreaterThan(testCase.expect.price - MAX_PRICE_ERROR);
expect(cartTotal.totalPrice).toBeLessThan(testCase.expect.price + MAX_PRICE_ERROR); // expect(cartTotal.totalPrice).toBeLessThan(testCase.expect.price + MAX_PRICE_ERROR);
}); // });
it("case 5", () => { // it("case 5", () => {
const testCase = prepareTestCase(exampleCartValues.testCases[4]); // const testCase = prepareTestCase(exampleCartValues.testCases[4]);
// работает если не учитывать скидки id26, id27 (скидка на templategen от 1000/5000 р.) // // работает если не учитывать скидки id26, id27 (скидка на templategen от 1000/5000 р.)
const discountsWithoutTemplategen = discounts.filter(discount => { // const discountsWithoutTemplategen = discounts.filter(discount => {
return !( // return !(
discount.conditionType === "service" && // discount.conditionType === "service" &&
discount.condition.service.id === "templategen" // discount.condition.service.id === "templategen"
); // );
}); // });
const cartTotal = calcCartData({ // const cartTotal = calcCartData({
user: testCase.user, // user: testCase.user,
purchasesAmount: testCase.user.PurchasesAmount, // purchasesAmount: testCase.user.PurchasesAmount,
cartItems: testCase.cartItems, // cartItems: testCase.cartItems,
discounts: discountsWithoutTemplategen, // discounts: discountsWithoutTemplategen,
}) as CartTotal; // }) as CartTotal;
const allEnvolvedDiscounts: string[] = [...cartTotal.envolvedCartDiscounts.map(discount => discount._id)]; // const allEnvolvedDiscounts: string[] = [...cartTotal.envolvedCartDiscounts.map(discount => discount._id)];
cartTotal.items.forEach(cartItem => { // cartTotal.items.forEach(cartItem => {
allEnvolvedDiscounts.push(...cartItem.envolvedDiscounts.map(discount => discount._id)); // allEnvolvedDiscounts.push(...cartItem.envolvedDiscounts.map(discount => discount._id));
}); // });
SERVICE_LIST.map(service => service.serviceKey).forEach(service => { // SERVICE_LIST.map(service => service.serviceKey).forEach(service => {
if (cartTotal.discountsByService[service]) allEnvolvedDiscounts.push(cartTotal.discountsByService[service]!._id); // if (cartTotal.discountsByService[service]) allEnvolvedDiscounts.push(cartTotal.discountsByService[service]!._id);
}); // });
expect(allEnvolvedDiscounts.sort()).toEqual(testCase.expect.envolvedDiscounts.sort()); // expect(allEnvolvedDiscounts.sort()).toEqual(testCase.expect.envolvedDiscounts.sort());
expect(cartTotal.totalPrice).toBeGreaterThan(testCase.expect.price - MAX_PRICE_ERROR); // expect(cartTotal.totalPrice).toBeGreaterThan(testCase.expect.price - MAX_PRICE_ERROR);
expect(cartTotal.totalPrice).toBeLessThan(testCase.expect.price + MAX_PRICE_ERROR); // expect(cartTotal.totalPrice).toBeLessThan(testCase.expect.price + MAX_PRICE_ERROR);
}); // });
it("история про то, как скидки за привилегии помешали получить скидку за сервис", () => { // it("история про то, как скидки за привилегии помешали получить скидку за сервис", () => {
const testCase = prepareTestCase(exampleCartValues.testCases[5]); // const testCase = prepareTestCase(exampleCartValues.testCases[5]);
const cartTotal = calcCartData({ // const cartTotal = calcCartData({
user: testCase.user, // user: testCase.user,
purchasesAmount: testCase.user.PurchasesAmount, // purchasesAmount: testCase.user.PurchasesAmount,
cartItems: testCase.cartItems, // cartItems: testCase.cartItems,
discounts, // discounts,
}) as CartTotal; // }) as CartTotal;
const allEnvolvedDiscounts: string[] = [...cartTotal.envolvedCartDiscounts.map(discount => discount._id)]; // const allEnvolvedDiscounts: string[] = [...cartTotal.envolvedCartDiscounts.map(discount => discount._id)];
cartTotal.items.forEach(cartItem => { // cartTotal.items.forEach(cartItem => {
allEnvolvedDiscounts.push(...cartItem.envolvedDiscounts.map(discount => discount._id)); // allEnvolvedDiscounts.push(...cartItem.envolvedDiscounts.map(discount => discount._id));
}); // });
SERVICE_LIST.map(service => service.serviceKey).forEach(service => { // SERVICE_LIST.map(service => service.serviceKey).forEach(service => {
if (cartTotal.discountsByService[service]) allEnvolvedDiscounts.push(cartTotal.discountsByService[service]!._id); // if (cartTotal.discountsByService[service]) allEnvolvedDiscounts.push(cartTotal.discountsByService[service]!._id);
}); // });
expect(allEnvolvedDiscounts.sort()).toEqual(testCase.expect.envolvedDiscounts.sort()); // expect(allEnvolvedDiscounts.sort()).toEqual(testCase.expect.envolvedDiscounts.sort());
expect(cartTotal.totalPrice).toBeGreaterThan(testCase.expect.price - MAX_PRICE_ERROR); // expect(cartTotal.totalPrice).toBeGreaterThan(testCase.expect.price - MAX_PRICE_ERROR);
expect(cartTotal.totalPrice).toBeLessThan(testCase.expect.price + MAX_PRICE_ERROR); // expect(cartTotal.totalPrice).toBeLessThan(testCase.expect.price + MAX_PRICE_ERROR);
}); // });
it("то же что и выше, но без лояльности", () => { // it("то же что и выше, но без лояльности", () => {
const testCase = prepareTestCase(exampleCartValues.testCases[6]); // const testCase = prepareTestCase(exampleCartValues.testCases[6]);
const cartTotal = calcCartData({ // const cartTotal = calcCartData({
user: testCase.user, // user: testCase.user,
purchasesAmount: testCase.user.PurchasesAmount, // purchasesAmount: testCase.user.PurchasesAmount,
cartItems: testCase.cartItems, // cartItems: testCase.cartItems,
discounts, // discounts,
}) as CartTotal; // }) as CartTotal;
const allEnvolvedDiscounts: string[] = [...cartTotal.envolvedCartDiscounts.map(discount => discount._id)]; // const allEnvolvedDiscounts: string[] = [...cartTotal.envolvedCartDiscounts.map(discount => discount._id)];
cartTotal.items.forEach(cartItem => { // cartTotal.items.forEach(cartItem => {
allEnvolvedDiscounts.push(...cartItem.envolvedDiscounts.map(discount => discount._id)); // allEnvolvedDiscounts.push(...cartItem.envolvedDiscounts.map(discount => discount._id));
}); // });
SERVICE_LIST.map(service => service.serviceKey).forEach(service => { // SERVICE_LIST.map(service => service.serviceKey).forEach(service => {
if (cartTotal.discountsByService[service]) allEnvolvedDiscounts.push(cartTotal.discountsByService[service]!._id); // if (cartTotal.discountsByService[service]) allEnvolvedDiscounts.push(cartTotal.discountsByService[service]!._id);
}); // });
expect(allEnvolvedDiscounts.sort()).toEqual(testCase.expect.envolvedDiscounts.sort()); // expect(allEnvolvedDiscounts.sort()).toEqual(testCase.expect.envolvedDiscounts.sort());
expect(cartTotal.totalPrice).toBeGreaterThan(testCase.expect.price - MAX_PRICE_ERROR); // expect(cartTotal.totalPrice).toBeGreaterThan(testCase.expect.price - MAX_PRICE_ERROR);
expect(cartTotal.totalPrice).toBeLessThan(testCase.expect.price + MAX_PRICE_ERROR); // expect(cartTotal.totalPrice).toBeLessThan(testCase.expect.price + MAX_PRICE_ERROR);
}); // });
it("история про то, как получилось получить скидку за сервис", () => { // it("история про то, как получилось получить скидку за сервис", () => {
const testCase = prepareTestCase(exampleCartValues.testCases[7]); // const testCase = prepareTestCase(exampleCartValues.testCases[7]);
const cartTotal = calcCartData({ // const cartTotal = calcCartData({
user: testCase.user, // user: testCase.user,
purchasesAmount: testCase.user.PurchasesAmount, // purchasesAmount: testCase.user.PurchasesAmount,
cartItems: testCase.cartItems, // cartItems: testCase.cartItems,
discounts, // discounts,
}) as CartTotal; // }) as CartTotal;
const allEnvolvedDiscounts: string[] = [...cartTotal.envolvedCartDiscounts.map(discount => discount._id)]; // const allEnvolvedDiscounts: string[] = [...cartTotal.envolvedCartDiscounts.map(discount => discount._id)];
cartTotal.items.forEach(cartItem => { // cartTotal.items.forEach(cartItem => {
allEnvolvedDiscounts.push(...cartItem.envolvedDiscounts.map(discount => discount._id)); // allEnvolvedDiscounts.push(...cartItem.envolvedDiscounts.map(discount => discount._id));
}); // });
SERVICE_LIST.map(service => service.serviceKey).forEach(service => { // SERVICE_LIST.map(service => service.serviceKey).forEach(service => {
if (cartTotal.discountsByService[service]) allEnvolvedDiscounts.push(cartTotal.discountsByService[service]!._id); // if (cartTotal.discountsByService[service]) allEnvolvedDiscounts.push(cartTotal.discountsByService[service]!._id);
}); // });
expect(allEnvolvedDiscounts.sort()).toEqual(testCase.expect.envolvedDiscounts.sort()); // expect(allEnvolvedDiscounts.sort()).toEqual(testCase.expect.envolvedDiscounts.sort());
expect(cartTotal.totalPrice).toBeGreaterThan(testCase.expect.price - MAX_PRICE_ERROR); // expect(cartTotal.totalPrice).toBeGreaterThan(testCase.expect.price - MAX_PRICE_ERROR);
expect(cartTotal.totalPrice).toBeLessThan(testCase.expect.price + MAX_PRICE_ERROR); // expect(cartTotal.totalPrice).toBeLessThan(testCase.expect.price + MAX_PRICE_ERROR);
}); // });
it("две скидки за сервис", () => { // it("две скидки за сервис", () => {
const testCase = prepareTestCase(exampleCartValues.testCases[8]); // const testCase = prepareTestCase(exampleCartValues.testCases[8]);
const cartTotal = calcCartData({ // const cartTotal = calcCartData({
user: testCase.user, // user: testCase.user,
purchasesAmount: testCase.user.PurchasesAmount, // purchasesAmount: testCase.user.PurchasesAmount,
cartItems: testCase.cartItems, // cartItems: testCase.cartItems,
discounts, // discounts,
}) as CartTotal; // }) as CartTotal;
const allEnvolvedDiscounts: string[] = [...cartTotal.envolvedCartDiscounts.map(discount => discount._id)]; // const allEnvolvedDiscounts: string[] = [...cartTotal.envolvedCartDiscounts.map(discount => discount._id)];
cartTotal.items.forEach(cartItem => { // cartTotal.items.forEach(cartItem => {
allEnvolvedDiscounts.push(...cartItem.envolvedDiscounts.map(discount => discount._id)); // allEnvolvedDiscounts.push(...cartItem.envolvedDiscounts.map(discount => discount._id));
}); // });
SERVICE_LIST.map(service => service.serviceKey).forEach(service => { // SERVICE_LIST.map(service => service.serviceKey).forEach(service => {
if (cartTotal.discountsByService[service]) allEnvolvedDiscounts.push(cartTotal.discountsByService[service]!._id); // if (cartTotal.discountsByService[service]) allEnvolvedDiscounts.push(cartTotal.discountsByService[service]!._id);
}); // });
expect(allEnvolvedDiscounts.sort()).toEqual(testCase.expect.envolvedDiscounts.sort()); // expect(allEnvolvedDiscounts.sort()).toEqual(testCase.expect.envolvedDiscounts.sort());
expect(cartTotal.totalPrice).toBeGreaterThan(testCase.expect.price - MAX_PRICE_ERROR); // expect(cartTotal.totalPrice).toBeGreaterThan(testCase.expect.price - MAX_PRICE_ERROR);
expect(cartTotal.totalPrice).toBeLessThan(testCase.expect.price + MAX_PRICE_ERROR); // expect(cartTotal.totalPrice).toBeLessThan(testCase.expect.price + MAX_PRICE_ERROR);
}); // });
it("юзер использовал промокод id33. он заменяет скидку на p6 собой. в один момент времени может быть активирован только 1 промокод, т.е. после активации следующего, предыдущий заменяется. но в промокоде может быть несколько скидок. промокоды имеют скидки только на привелеги", () => { // it("юзер использовал промокод id33. он заменяет скидку на p6 собой. в один момент времени может быть активирован только 1 промокод, т.е. после активации следующего, предыдущий заменяется. но в промокоде может быть несколько скидок. промокоды имеют скидки только на привелеги", () => {
const testCase = prepareTestCase(exampleCartValues.testCases[9]); // const testCase = prepareTestCase(exampleCartValues.testCases[9]);
const cartTotal = calcCartData({ // const cartTotal = calcCartData({
user: testCase.user, // user: testCase.user,
purchasesAmount: testCase.user.PurchasesAmount, // purchasesAmount: testCase.user.PurchasesAmount,
cartItems: testCase.cartItems, // cartItems: testCase.cartItems,
discounts, // discounts,
isNonCommercial: false, // isNonCommercial: false,
coupon: "ABCD", // coupon: "ABCD",
}) as CartTotal; // }) as CartTotal;
const allEnvolvedDiscounts: string[] = [...cartTotal.envolvedCartDiscounts.map(discount => discount._id)]; // const allEnvolvedDiscounts: string[] = [...cartTotal.envolvedCartDiscounts.map(discount => discount._id)];
cartTotal.items.forEach(cartItem => { // cartTotal.items.forEach(cartItem => {
allEnvolvedDiscounts.push(...cartItem.envolvedDiscounts.map(discount => discount._id)); // allEnvolvedDiscounts.push(...cartItem.envolvedDiscounts.map(discount => discount._id));
}); // });
SERVICE_LIST.map(service => service.serviceKey).forEach(service => { // SERVICE_LIST.map(service => service.serviceKey).forEach(service => {
if (cartTotal.discountsByService[service]) allEnvolvedDiscounts.push(cartTotal.discountsByService[service]!._id); // if (cartTotal.discountsByService[service]) allEnvolvedDiscounts.push(cartTotal.discountsByService[service]!._id);
}); // });
expect(allEnvolvedDiscounts.sort()).toEqual(testCase.expect.envolvedDiscounts.sort()); // expect(allEnvolvedDiscounts.sort()).toEqual(testCase.expect.envolvedDiscounts.sort());
expect(cartTotal.totalPrice).toBeGreaterThan(testCase.expect.price - MAX_PRICE_ERROR); // expect(cartTotal.totalPrice).toBeGreaterThan(testCase.expect.price - MAX_PRICE_ERROR);
expect(cartTotal.totalPrice).toBeLessThan(testCase.expect.price + MAX_PRICE_ERROR); // expect(cartTotal.totalPrice).toBeLessThan(testCase.expect.price + MAX_PRICE_ERROR);
}); // });
it("юзер подтвердил свой статус НКО, поэтому, не смотря на то что он достиг по лояльности уровня скидки id2, она не применилась, а применилась id32", () => { // it("юзер подтвердил свой статус НКО, поэтому, не смотря на то что он достиг по лояльности уровня скидки id2, она не применилась, а применилась id32", () => {
const testCase = prepareTestCase(exampleCartValues.testCases[10]); // const testCase = prepareTestCase(exampleCartValues.testCases[10]);
const cartTotal = calcCartData({ // const cartTotal = calcCartData({
user: testCase.user, // user: testCase.user,
purchasesAmount: testCase.user.PurchasesAmount, // purchasesAmount: testCase.user.PurchasesAmount,
cartItems: testCase.cartItems, // cartItems: testCase.cartItems,
discounts, // discounts,
isNonCommercial: true, // isNonCommercial: true,
}) as CartTotal; // }) as CartTotal;
const allEnvolvedDiscounts: string[] = [...cartTotal.envolvedCartDiscounts.map(discount => discount._id)]; // const allEnvolvedDiscounts: string[] = [...cartTotal.envolvedCartDiscounts.map(discount => discount._id)];
cartTotal.items.forEach(cartItem => { // cartTotal.items.forEach(cartItem => {
allEnvolvedDiscounts.push(...cartItem.envolvedDiscounts.map(discount => discount._id)); // allEnvolvedDiscounts.push(...cartItem.envolvedDiscounts.map(discount => discount._id));
}); // });
SERVICE_LIST.map(service => service.serviceKey).forEach(service => { // SERVICE_LIST.map(service => service.serviceKey).forEach(service => {
if (cartTotal.discountsByService[service]) allEnvolvedDiscounts.push(cartTotal.discountsByService[service]!._id); // if (cartTotal.discountsByService[service]) allEnvolvedDiscounts.push(cartTotal.discountsByService[service]!._id);
}); // });
expect(allEnvolvedDiscounts.sort()).toEqual(testCase.expect.envolvedDiscounts.sort()); // expect(allEnvolvedDiscounts.sort()).toEqual(testCase.expect.envolvedDiscounts.sort());
expect(cartTotal.totalPrice).toBeGreaterThan(testCase.expect.price - MAX_PRICE_ERROR); // expect(cartTotal.totalPrice).toBeGreaterThan(testCase.expect.price - MAX_PRICE_ERROR);
expect(cartTotal.totalPrice).toBeLessThan(testCase.expect.price + MAX_PRICE_ERROR); // expect(cartTotal.totalPrice).toBeLessThan(testCase.expect.price + MAX_PRICE_ERROR);
}); // });
it("case 12", () => { // it("case 12", () => {
const testCase = prepareTestCase(exampleCartValues.testCases[11]); // const testCase = prepareTestCase(exampleCartValues.testCases[11]);
const cartTotal = calcCartData({ // const cartTotal = calcCartData({
user: testCase.user, // user: testCase.user,
purchasesAmount: testCase.user.PurchasesAmount, // purchasesAmount: testCase.user.PurchasesAmount,
cartItems: testCase.cartItems, // cartItems: testCase.cartItems,
discounts, // discounts,
}) as CartTotal; // }) as CartTotal;
const allEnvolvedDiscounts: string[] = [...cartTotal.envolvedCartDiscounts.map(discount => discount._id)]; // const allEnvolvedDiscounts: string[] = [...cartTotal.envolvedCartDiscounts.map(discount => discount._id)];
cartTotal.items.forEach(cartItem => { // cartTotal.items.forEach(cartItem => {
allEnvolvedDiscounts.push(...cartItem.envolvedDiscounts.map(discount => discount._id)); // allEnvolvedDiscounts.push(...cartItem.envolvedDiscounts.map(discount => discount._id));
}); // });
SERVICE_LIST.map(service => service.serviceKey).forEach(service => { // SERVICE_LIST.map(service => service.serviceKey).forEach(service => {
if (cartTotal.discountsByService[service]) allEnvolvedDiscounts.push(cartTotal.discountsByService[service]!._id); // if (cartTotal.discountsByService[service]) allEnvolvedDiscounts.push(cartTotal.discountsByService[service]!._id);
}); // });
expect(allEnvolvedDiscounts.sort()).toEqual(testCase.expect.envolvedDiscounts.sort()); // expect(allEnvolvedDiscounts.sort()).toEqual(testCase.expect.envolvedDiscounts.sort());
expect(cartTotal.totalPrice).toBeGreaterThan(testCase.expect.price - MAX_PRICE_ERROR); // expect(cartTotal.totalPrice).toBeGreaterThan(testCase.expect.price - MAX_PRICE_ERROR);
expect(cartTotal.totalPrice).toBeLessThan(testCase.expect.price + MAX_PRICE_ERROR); // expect(cartTotal.totalPrice).toBeLessThan(testCase.expect.price + MAX_PRICE_ERROR);
}); // });
}); // });
function prepareTestCase(testCase: TestCase): ({ function prepareTestCase(testCase: TestCase): ({

@ -10,9 +10,11 @@ import {
ServiceDiscount, ServiceDiscount,
UserDiscount, UserDiscount,
} from "@root/model/cart"; } from "@root/model/cart";
import { Discount } from "@root/model/discount";
import { User } from "../../model/user"; import { User } from "../../model/user";
import { findPrivilegeById } from "@root/stores/privilegesStore"; import { findPrivilegeById } from "@root/stores/privilegesStore";
import { SERVICE_LIST, ServiceType, Tariff } from "@root/model/tariff"; import { SERVICE_LIST, ServiceType, Tariff } from "@root/model/tariff";
import { enqueueSnackbar } from "notistack";
export function calcCartData({ export function calcCartData({
user, user,
@ -25,12 +27,12 @@ export function calcCartData({
user: User; user: User;
purchasesAmount: number; purchasesAmount: number;
cartItems: CartItem[]; cartItems: CartItem[];
discounts: AnyDiscount[]; discounts: Discount[];
isNonCommercial?: boolean; isNonCommercial?: boolean;
coupon?: string; coupon?: string;
}): CartTotal | Error | null { }): CartTotal | Error | null {
let isIncompatibleTariffs = false; let isIncompatibleTariffs = false;
console.log(discounts)
const defaultTariffTypePresent: { [Key in ServiceType]: boolean } = { const defaultTariffTypePresent: { [Key in ServiceType]: boolean } = {
dwarfener: false, dwarfener: false,
squiz: false, squiz: false,
@ -75,7 +77,7 @@ export function calcCartData({
// layer 0 // layer 0
for (const discount of discounts) { for (const discount of discounts) {
if (discount.conditionType !== "userType" || !isNonCommercial) continue; if (discount.Condition.UserType.length !== 0 || !isNonCommercial) continue;
cartItems.forEach((cartItem) => { cartItems.forEach((cartItem) => {
cartTotal.items.push({ cartTotal.items.push({
@ -92,7 +94,7 @@ export function calcCartData({
cartTotal.totalPrice += cartItem.price; cartTotal.totalPrice += cartItem.price;
}); });
cartTotal.totalPrice *= discount.target.factor; cartTotal.totalPrice *= discount.Target.Factor;
cartTotal.envolvedCartDiscounts.push(discount); cartTotal.envolvedCartDiscounts.push(discount);
return cartTotal; return cartTotal;
@ -111,24 +113,24 @@ export function calcCartData({
const tariff = cartItem.tariff; const tariff = cartItem.tariff;
const privilegesAffectedByCoupon: string[] = []; const privilegesAffectedByCoupon: string[] = [];
couponDiscount?.target.products.forEach((product) => { couponDiscount?.Target.Products.forEach((product) => {
if (product.privilegeId !== tariff.privilegeId) return; if (product.ID !== tariff.privilegeId ) return;
if (tariff.customPricePerUnit !== undefined && !couponDiscount.overwhelm) return; if (tariff.customPricePerUnit !== undefined && !couponDiscount?.Target.Overhelm) return;
cartItemTotal.totalPrice *= product.factor; cartItemTotal.totalPrice *= product.Factor;
cartItemTotal.envolvedDiscounts.push(couponDiscount); cartItemTotal.envolvedDiscounts.push(couponDiscount);
cartTotal.couponState = "applied"; cartTotal.couponState = "applied";
privilegesAffectedByCoupon.push(product.privilegeId); privilegesAffectedByCoupon.push(couponDiscount.Condition.Product);
}); });
const privilegeDiscount = findMaxApplicablePrivilegeDiscount(discounts, tariff); const privilegeDiscount = findMaxApplicablePrivilegeDiscount(discounts, tariff);
privilegeDiscount?.target.products.forEach((product) => { privilegeDiscount?.Target.Products.forEach((product) => {
if (product.privilegeId !== tariff.privilegeId) return; if (privilegeDiscount.Condition.Product !== tariff.privilegeId) return;
if (tariff.customPricePerUnit !== undefined) return; if (tariff.customPricePerUnit !== undefined) return;
if (privilegesAffectedByCoupon.includes(privilegeDiscount.condition.privilege.id)) return; if (privilegesAffectedByCoupon.includes(privilegeDiscount.Condition.Product)) return;
cartItemTotal.totalPrice *= product.factor; cartItemTotal.totalPrice *= product.Factor;
cartItemTotal.envolvedDiscounts.push(privilegeDiscount); cartItemTotal.envolvedDiscounts.push(privilegeDiscount);
}); });
@ -138,15 +140,22 @@ export function calcCartData({
cartTotal.items.push(cartItemTotal); cartTotal.items.push(cartItemTotal);
cartTotal.priceByService[privilege.serviceKey] += cartItemTotal.totalPrice; cartTotal.priceByService[privilege.serviceKey] += cartItemTotal.totalPrice;
console.log("cartTotal.priceByService")
console.log(cartTotal.priceByService)
} }
// layer 2 // layer 2
console.log("l2")
SERVICE_LIST.map((service) => service.serviceKey).forEach((service) => { SERVICE_LIST.map((service) => service.serviceKey).forEach((service) => {
const serviceDiscount = findMaxServiceDiscount(service, discounts, cartTotal.priceByService); const serviceDiscount = findMaxServiceDiscount(service, discounts, cartTotal.priceByService);
console.log(serviceDiscount)
if (serviceDiscount) { if (serviceDiscount) {
cartTotal.priceByService[service] *= serviceDiscount.target.factor; cartTotal.priceByService[service] *= serviceDiscount.Target.Factor;
cartTotal.discountsByService[service] = serviceDiscount; cartTotal.discountsByService[service] = serviceDiscount;
console.log(cartTotal.discountsByService)
} }
console.log(cartTotal.totalPrice)
console.log(cartTotal.priceByService[service])
cartTotal.totalPrice += cartTotal.priceByService[service]; cartTotal.totalPrice += cartTotal.priceByService[service];
}); });
@ -154,69 +163,69 @@ export function calcCartData({
// layer 3 // layer 3
const cartPurchasesAmountDiscount = findMaxCartPurchasesAmountDiscount(discounts, cartTotal); const cartPurchasesAmountDiscount = findMaxCartPurchasesAmountDiscount(discounts, cartTotal);
if (cartPurchasesAmountDiscount) { if (cartPurchasesAmountDiscount) {
cartTotal.totalPrice *= cartPurchasesAmountDiscount.factor; cartTotal.totalPrice *= cartPurchasesAmountDiscount.Target.Factor;
cartTotal.envolvedCartDiscounts.push(cartPurchasesAmountDiscount); cartTotal.envolvedCartDiscounts.push(cartPurchasesAmountDiscount);
} }
// layer 4 // layer 4
const totalPurchasesAmountDiscount = findMaxTotalPurchasesAmountDiscount(discounts, purchasesAmount); const totalPurchasesAmountDiscount = findMaxTotalPurchasesAmountDiscount(discounts, purchasesAmount);
if (totalPurchasesAmountDiscount) { if (totalPurchasesAmountDiscount) {
cartTotal.totalPrice *= totalPurchasesAmountDiscount.factor; cartTotal.totalPrice *= totalPurchasesAmountDiscount.Target.Factor;
cartTotal.envolvedCartDiscounts.push(totalPurchasesAmountDiscount); cartTotal.envolvedCartDiscounts.push(totalPurchasesAmountDiscount);
} }
return cartTotal; return cartTotal;
} }
function findMaxApplicablePrivilegeDiscount(discounts: AnyDiscount[], tariff: Tariff): PrivilegeDiscount | null { function findMaxApplicablePrivilegeDiscount(discounts: Discount[], tariff: Tariff): Discount | null {
const applicableDiscounts = discounts.filter((discount): discount is PrivilegeDiscount => { const applicableDiscounts = discounts.filter((discount): discount is Discount => {
return ( return (
discount.conditionType === "privilege" && discount.Condition.Product.length !== 0 &&
tariff.privilegeId === discount.condition.privilege.id && tariff.privilegeId === discount.Condition.Product &&
tariff.amount >= discount.condition.privilege.value tariff.amount >= Number(discount.Condition.Usage)
); );
}); });
if (!applicableDiscounts.length) return null; if (!applicableDiscounts.length) return null;
const maxValueDiscount = applicableDiscounts.reduce((prev, current) => const maxValueDiscount = applicableDiscounts.reduce((prev, current) =>
current.condition.privilege.value > prev.condition.privilege.value ? current : prev Number(current.Condition.Usage) > Number(prev.Condition.Usage) ? current : prev
); );
return maxValueDiscount; return maxValueDiscount;
} }
function findMaxCartPurchasesAmountDiscount( function findMaxCartPurchasesAmountDiscount(
discounts: AnyDiscount[], discounts: Discount[],
cartTotal: CartTotal cartTotal: CartTotal
): CartPurchasesAmountDiscount | null { ): Discount | null {
const applicableDiscounts = discounts.filter((discount): discount is CartPurchasesAmountDiscount => { const applicableDiscounts = discounts.filter((discount): discount is Discount => {
return ( return (
discount.conditionType === "cartPurchasesAmount" && cartTotal.totalPrice >= discount.condition.cartPurchasesAmount discount.Condition.UserType === "cartPurchasesAmount" && cartTotal.totalPrice >= Number(discount.Condition.CartPurchasesAmount)
); );
}); });
if (!applicableDiscounts.length) return null; if (!applicableDiscounts.length) return null;
const maxValueDiscount = applicableDiscounts.reduce((prev, current) => const maxValueDiscount = applicableDiscounts.reduce((prev, current) =>
current.condition.cartPurchasesAmount > prev.condition.cartPurchasesAmount ? current : prev Number(current.Condition.CartPurchasesAmount) > Number(prev.Condition.CartPurchasesAmount) ? current : prev
); );
return maxValueDiscount; return maxValueDiscount;
} }
function findMaxTotalPurchasesAmountDiscount( function findMaxTotalPurchasesAmountDiscount(
discounts: AnyDiscount[], discounts: Discount[],
purchasesAmount: number purchasesAmount: number
): PurchasesAmountDiscount | null { ): Discount | null {
const applicableDiscounts = discounts.filter((discount): discount is PurchasesAmountDiscount => { const applicableDiscounts = discounts.filter((discount): discount is Discount => {
return discount.conditionType === "purchasesAmount" && purchasesAmount >= discount.condition.purchasesAmount; return discount.Condition.UserType === "purchasesAmount" && purchasesAmount >= Number(discount.Condition.PurchasesAmount);
}); });
if (!applicableDiscounts.length) return null; if (!applicableDiscounts.length) return null;
const maxValueDiscount = applicableDiscounts.reduce((prev, current) => const maxValueDiscount = applicableDiscounts.reduce((prev, current) =>
current.condition.purchasesAmount > prev.condition.purchasesAmount ? current : prev Number(current.Condition.PurchasesAmount) > Number(prev.Condition.PurchasesAmount) ? current : prev
); );
return maxValueDiscount; return maxValueDiscount;
@ -224,65 +233,74 @@ function findMaxTotalPurchasesAmountDiscount(
function findMaxServiceDiscount( function findMaxServiceDiscount(
service: ServiceType, service: ServiceType,
discounts: AnyDiscount[], discounts: Discount[],
priceByService: ServiceToPriceMap priceByService: ServiceToPriceMap
): ServiceDiscount | null { ): Discount | null {
const discountsForTariffService = discounts.filter((discount): discount is ServiceDiscount => { console.log(discounts)
const discountsForTariffService = discounts.filter((discount): discount is Discount => {
return ( return (
discount.conditionType === "service" && discount.Condition.Product.length !== 0 &&
discount.condition.service.id === service && discount.Condition.Product === service &&
priceByService[service] >= discount.condition.service.value priceByService[service] >= Number(discount.Condition.Usage)
); );
}); });
if (!discountsForTariffService.length) return null; if (!discountsForTariffService.length) return null;
const maxValueDiscount = discountsForTariffService.reduce((prev, current) => { const maxValueDiscount = discountsForTariffService.reduce((prev, current) => {
return current.condition.service.value > prev.condition.service.value ? current : prev; return Number(current.Condition.Usage) > Number(prev.Condition.Usage) ? current : prev;
}); });
return maxValueDiscount; return maxValueDiscount;
} }
function findUserDiscount(discounts: AnyDiscount[], user: User, coupon: string): UserDiscount | null { function findUserDiscount(discounts: Discount[], user: User, coupon: string): Discount | null {
const userDiscount = discounts.find((discount): discount is UserDiscount => { const userDiscount = discounts.find((discount): discount is Discount => {
return ( return (
discount.conditionType === "user" && discount.condition.user === user.ID && discount.condition.coupon === coupon discount.Condition.User.length !== 0 && discount.Condition.User === user.ID && discount.Condition.Coupon === coupon
); );
}); });
return userDiscount ?? null; return userDiscount ?? null;
} }
export function createCartItem(tariff: Tariff): CartItem { export function createCartItem(tariff: Tariff): CartItem {
const pricePerUnit = tariff.customPricePerUnit ?? findPrivilegeById(tariff.privilegeId)?.price ?? 0;
const price = pricePerUnit * tariff.amount;
return { tariff, price, id: "someId" }; const privilege = findPrivilegeById(tariff.privilegeId)?.price || 0
if (!privilege) {
enqueueSnackbar(
`Привилегия с id ${tariff.privilegeId} не найдена в тарифе ${tariff.name} с id ${tariff.id}`
);
}
const price = tariff.isCustom ? (tariff.price || 0) : privilege * tariff.amount || 0
return { tariff, price, id: tariff.id };
} }
export function findDiscountFactor(discount: AnyDiscount): number { export function findDiscountFactor(discount: Discount): any {
switch (discount.conditionType) { switch (discount.Condition.UserType) {
case "cartPurchasesAmount": case "cartPurchasesAmount":
return discount.factor; return Number(discount.Target.Factor);
case "purchasesAmount": case "purchasesAmount":
return discount.factor; return Number(discount.Target.Factor);
case "privilege": { case "privilege": {
const product = discount.target.products[0]; const product = discount.Target.Products[0];
if (!product) throw new Error("Discount target product not found"); if (!product) throw new Error("Discount target product not found");
return Number(product.Factor);
return product.factor;
} }
case "user": { case "user": {
const product = discount.target.products[0]; const product = discount.Target.Products[0];
if (!product) throw new Error("Discount target product not found"); if (!product) throw new Error("Discount target product not found");
return product.factor; return Number(product.Factor);
} }
case "service": case "service":
return discount.target.factor; return Number(discount.Target.Factor);
case "userType": case "userType":
return discount.target.factor; return Number(discount.Target.Factor);
} }
} }

@ -1,4 +1,5 @@
import { ServiceType, Privilege, Tariff } from "./tariff"; import { ServiceType, Privilege, Tariff } from "./tariff";
import { Discount } from "@root/model/discount";
interface DiscountBase { interface DiscountBase {
_id: string; _id: string;
@ -119,7 +120,7 @@ export interface CartItem {
/** Пункт корзины с уже примененными скидками */ /** Пункт корзины с уже примененными скидками */
export interface CartItemTotal { export interface CartItemTotal {
/** Массив с id примененных скидок */ /** Массив с id примененных скидок */
envolvedDiscounts: (PrivilegeDiscount | UserDiscount)[]; envolvedDiscounts: Discount[];
totalPrice: number; totalPrice: number;
tariff: Tariff; tariff: Tariff;
} }
@ -129,7 +130,7 @@ export type ServiceToPriceMap = {
}; };
export type ServiceToDiscountMap = { export type ServiceToDiscountMap = {
[Key in ServiceType]: ServiceDiscount | null; [Key in ServiceType]: Discount | null;
}; };
export interface CartTotal { export interface CartTotal {
@ -139,6 +140,6 @@ export interface CartTotal {
/** Скидки по сервисам */ /** Скидки по сервисам */
discountsByService: ServiceToDiscountMap; discountsByService: ServiceToDiscountMap;
/** Учтенные скидки типов userType, cartPurchasesAmount, totalPurchasesAmount */ /** Учтенные скидки типов userType, cartPurchasesAmount, totalPurchasesAmount */
envolvedCartDiscounts: (UserTypeDiscount | CartPurchasesAmountDiscount | PurchasesAmountDiscount)[]; envolvedCartDiscounts: (Discount)[];
couponState: "applied" | "not found" | null; couponState: "applied" | "not found" | null;
} }