add error on incompatible tariffs

This commit is contained in:
nflnkr 2023-03-09 11:51:51 +03:00
parent 4f807eb3a5
commit 4a5f4f64ff
4 changed files with 138 additions and 96 deletions

@ -1,5 +1,5 @@
import theme from "@theme"; import theme from "@theme";
import { Button, Paper, Box, Typography, TableHead, TableRow, TableCell, TableBody, Table, Tooltip } from "@mui/material"; import { Button, Paper, Box, Typography, TableHead, TableRow, TableCell, TableBody, Table, Tooltip, Alert } from "@mui/material";
import Input from "@kitUI/input"; import Input from "@kitUI/input";
import { useCartStore } from "@root/stores/cart"; import { useCartStore } from "@root/stores/cart";
import { useState } from "react"; import { useState } from "react";
@ -10,17 +10,18 @@ import { calcCartData, createCartItem, findDiscountById, findDiscountFactor, for
import { useTariffStore } from "@root/stores/tariffs"; import { useTariffStore } from "@root/stores/tariffs";
import { AnyDiscount, CartItemTotal } from "@root/model/cart"; import { AnyDiscount, CartItemTotal } from "@root/model/cart";
interface Props { interface Props {
selectedTariffs: GridSelectionModel; selectedTariffs: GridSelectionModel;
} }
// TODO реализовать правило "если взят готовый тариф, то кастомный на этот сервис сделать уже нельзя"
export default function Cart({ selectedTariffs }: Props) { export default function Cart({ selectedTariffs }: Props) {
const tariffs = useTariffStore(store => store.tariffs); const tariffs = useTariffStore(store => store.tariffs);
const discounts = useDiscountStore(store => store.discounts); 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 [errorMessage, setErrorMessage] = useState<string | null>(null);
// const [coupon, setCoupon] = useState<string | undefined>(); // const [coupon, setCoupon] = useState<string | undefined>();
const cartRows = cartTotal?.items.map(cartItemTotal => { const cartRows = cartTotal?.items.map(cartItemTotal => {
@ -38,7 +39,7 @@ export default function Cart({ selectedTariffs }: Props) {
discount={discount} discount={discount}
cartItemTotal={cartItemTotal} cartItemTotal={cartItemTotal}
/> />
{index < arr.length - (discount ? 0 : 1) && {index < arr.length - (serviceDiscount ? 0 : 1) &&
<span>,&nbsp;</span> <span>,&nbsp;</span>
} }
</span> </span>
@ -92,7 +93,15 @@ export default function Cart({ selectedTariffs }: Props) {
function handleCalcCartClick() { function handleCalcCartClick() {
const cartTariffs = tariffs.filter(tariff => selectedTariffs.includes(tariff.id)); const cartTariffs = tariffs.filter(tariff => selectedTariffs.includes(tariff.id));
const cartItems = cartTariffs.map(tariff => createCartItem(tariff)); const cartItems = cartTariffs.map(tariff => createCartItem(tariff));
setCartTotal(calcCartData(testUser, cartItems, discounts, couponField)); const cartData = calcCartData(testUser, cartItems, discounts, couponField);
if (cartData instanceof Error) {
setErrorMessage(cartData.message);
return setCartTotal(null);
}
setErrorMessage(null);
setCartTotal(cartData);
} }
return ( return (
@ -103,7 +112,9 @@ export default function Cart({ selectedTariffs }: Props) {
display: "flex", display: "flex",
flexDirection: "column", flexDirection: "column",
alignItems: "center", alignItems: "center",
width: "100%" width: "100%",
pb: "20px",
borderRadius: "4px",
}} }}
> >
<Typography variant="caption"> <Typography variant="caption">
@ -146,6 +157,8 @@ export default function Cart({ selectedTariffs }: Props) {
<Button onClick={handleCalcCartClick}>рассчитать</Button> <Button onClick={handleCalcCartClick}>рассчитать</Button>
</Paper> </Paper>
{cartTotal?.items && cartTotal.items.length > 0 &&
<>
<Table sx={{ <Table sx={{
width: "90%", width: "90%",
margin: "5px", margin: "5px",
@ -226,6 +239,14 @@ export default function Cart({ selectedTariffs }: Props) {
}}> }}>
ИТОГО: <span>{cartTotal?.totalPrice.toFixed(2)} </span> ИТОГО: <span>{cartTotal?.totalPrice.toFixed(2)} </span>
</Typography> </Typography>
</>
}
{errorMessage !== null &&
<Alert variant="filled" severity="error" sx={{ mt: "20px" }}>
{errorMessage}
</Alert>
}
</Box> </Box>
); );

@ -1,4 +1,4 @@
import { CartItem } from "../../model/cart"; import { CartItem, CartTotal } from "../../model/cart";
import { SERVICE_LIST, Tariff } from "../../model/tariff"; import { SERVICE_LIST, Tariff } from "../../model/tariff";
import { User } from "../../model/user"; import { User } from "../../model/user";
import { exampleCartValues, TestCase } from "../../stores/mocks/exampleCartValues"; import { exampleCartValues, TestCase } from "../../stores/mocks/exampleCartValues";
@ -12,7 +12,7 @@ describe("cart tests", () => {
it("без скидок", () => { it("без скидок", () => {
const testCase = prepareTestCase(exampleCartValues.testCases[0]); const testCase = prepareTestCase(exampleCartValues.testCases[0]);
const cartTotal = calcCartData(testCase.user, testCase.cartItems, discounts); const cartTotal = calcCartData(testCase.user, testCase.cartItems, discounts) as CartTotal;
const allEnvolvedDiscounts: string[] = [...cartTotal.envolvedCartDiscountIds]; const allEnvolvedDiscounts: string[] = [...cartTotal.envolvedCartDiscountIds];
cartTotal.items.forEach(cartItem => { cartTotal.items.forEach(cartItem => {
allEnvolvedDiscounts.push(...cartItem.envolvedDiscountIds); allEnvolvedDiscounts.push(...cartItem.envolvedDiscountIds);
@ -36,7 +36,7 @@ describe("cart tests", () => {
); );
}); });
const cartTotal = calcCartData(testCase.user, testCase.cartItems, discountsWithoutTemplategen); const cartTotal = calcCartData(testCase.user, testCase.cartItems, discountsWithoutTemplategen) as CartTotal;
const allEnvolvedDiscounts: string[] = [...cartTotal.envolvedCartDiscountIds]; const allEnvolvedDiscounts: string[] = [...cartTotal.envolvedCartDiscountIds];
cartTotal.items.forEach(cartItem => { cartTotal.items.forEach(cartItem => {
allEnvolvedDiscounts.push(...cartItem.envolvedDiscountIds); allEnvolvedDiscounts.push(...cartItem.envolvedDiscountIds);
@ -60,7 +60,7 @@ describe("cart tests", () => {
); );
}); });
const cartTotal = calcCartData(testCase.user, testCase.cartItems, discountsWithoutTemplategen); const cartTotal = calcCartData(testCase.user, testCase.cartItems, discountsWithoutTemplategen) as CartTotal;
const allEnvolvedDiscounts: string[] = [...cartTotal.envolvedCartDiscountIds]; const allEnvolvedDiscounts: string[] = [...cartTotal.envolvedCartDiscountIds];
cartTotal.items.forEach(cartItem => { cartTotal.items.forEach(cartItem => {
allEnvolvedDiscounts.push(...cartItem.envolvedDiscountIds); allEnvolvedDiscounts.push(...cartItem.envolvedDiscountIds);
@ -84,7 +84,7 @@ describe("cart tests", () => {
); );
}); });
const cartTotal = calcCartData(testCase.user, testCase.cartItems, discountsWithoutTemplategen); const cartTotal = calcCartData(testCase.user, testCase.cartItems, discountsWithoutTemplategen) as CartTotal;
const allEnvolvedDiscounts: string[] = [...cartTotal.envolvedCartDiscountIds]; const allEnvolvedDiscounts: string[] = [...cartTotal.envolvedCartDiscountIds];
cartTotal.items.forEach(cartItem => { cartTotal.items.forEach(cartItem => {
allEnvolvedDiscounts.push(...cartItem.envolvedDiscountIds); allEnvolvedDiscounts.push(...cartItem.envolvedDiscountIds);
@ -108,7 +108,7 @@ describe("cart tests", () => {
); );
}); });
const cartTotal = calcCartData(testCase.user, testCase.cartItems, discountsWithoutTemplategen); const cartTotal = calcCartData(testCase.user, testCase.cartItems, discountsWithoutTemplategen) as CartTotal;
const allEnvolvedDiscounts: string[] = [...cartTotal.envolvedCartDiscountIds]; const allEnvolvedDiscounts: string[] = [...cartTotal.envolvedCartDiscountIds];
cartTotal.items.forEach(cartItem => { cartTotal.items.forEach(cartItem => {
allEnvolvedDiscounts.push(...cartItem.envolvedDiscountIds); allEnvolvedDiscounts.push(...cartItem.envolvedDiscountIds);
@ -124,7 +124,7 @@ describe("cart tests", () => {
it("история про то, как скидки за привилегии помешали получить скидку за сервис", () => { it("история про то, как скидки за привилегии помешали получить скидку за сервис", () => {
const testCase = prepareTestCase(exampleCartValues.testCases[5]); const testCase = prepareTestCase(exampleCartValues.testCases[5]);
const cartTotal = calcCartData(testCase.user, testCase.cartItems, discounts); const cartTotal = calcCartData(testCase.user, testCase.cartItems, discounts) as CartTotal;
const allEnvolvedDiscounts: string[] = [...cartTotal.envolvedCartDiscountIds]; const allEnvolvedDiscounts: string[] = [...cartTotal.envolvedCartDiscountIds];
cartTotal.items.forEach(cartItem => { cartTotal.items.forEach(cartItem => {
allEnvolvedDiscounts.push(...cartItem.envolvedDiscountIds); allEnvolvedDiscounts.push(...cartItem.envolvedDiscountIds);
@ -140,7 +140,7 @@ describe("cart tests", () => {
it("то же что и выше, но без лояльности", () => { it("то же что и выше, но без лояльности", () => {
const testCase = prepareTestCase(exampleCartValues.testCases[6]); const testCase = prepareTestCase(exampleCartValues.testCases[6]);
const cartTotal = calcCartData(testCase.user, testCase.cartItems, discounts); const cartTotal = calcCartData(testCase.user, testCase.cartItems, discounts) as CartTotal;
const allEnvolvedDiscounts: string[] = [...cartTotal.envolvedCartDiscountIds]; const allEnvolvedDiscounts: string[] = [...cartTotal.envolvedCartDiscountIds];
cartTotal.items.forEach(cartItem => { cartTotal.items.forEach(cartItem => {
allEnvolvedDiscounts.push(...cartItem.envolvedDiscountIds); allEnvolvedDiscounts.push(...cartItem.envolvedDiscountIds);
@ -156,7 +156,7 @@ describe("cart tests", () => {
it("история про то, как получилось получить скидку за сервис", () => { it("история про то, как получилось получить скидку за сервис", () => {
const testCase = prepareTestCase(exampleCartValues.testCases[7]); const testCase = prepareTestCase(exampleCartValues.testCases[7]);
const cartTotal = calcCartData(testCase.user, testCase.cartItems, discounts); const cartTotal = calcCartData(testCase.user, testCase.cartItems, discounts) as CartTotal;
const allEnvolvedDiscounts: string[] = [...cartTotal.envolvedCartDiscountIds]; const allEnvolvedDiscounts: string[] = [...cartTotal.envolvedCartDiscountIds];
cartTotal.items.forEach(cartItem => { cartTotal.items.forEach(cartItem => {
allEnvolvedDiscounts.push(...cartItem.envolvedDiscountIds); allEnvolvedDiscounts.push(...cartItem.envolvedDiscountIds);
@ -172,7 +172,7 @@ describe("cart tests", () => {
it("две скидки за сервис", () => { it("две скидки за сервис", () => {
const testCase = prepareTestCase(exampleCartValues.testCases[8]); const testCase = prepareTestCase(exampleCartValues.testCases[8]);
const cartTotal = calcCartData(testCase.user, testCase.cartItems, discounts); const cartTotal = calcCartData(testCase.user, testCase.cartItems, discounts) as CartTotal;
const allEnvolvedDiscounts: string[] = [...cartTotal.envolvedCartDiscountIds]; const allEnvolvedDiscounts: string[] = [...cartTotal.envolvedCartDiscountIds];
cartTotal.items.forEach(cartItem => { cartTotal.items.forEach(cartItem => {
allEnvolvedDiscounts.push(...cartItem.envolvedDiscountIds); allEnvolvedDiscounts.push(...cartItem.envolvedDiscountIds);
@ -188,7 +188,7 @@ describe("cart tests", () => {
it("юзер использовал промокод id33. он заменяет скидку на p6 собой. в один момент времени может быть активирован только 1 промокод, т.е. после активации следующего, предыдущий заменяется. но в промокоде может быть несколько скидок. промокоды имеют скидки только на привелеги", () => { it("юзер использовал промокод id33. он заменяет скидку на p6 собой. в один момент времени может быть активирован только 1 промокод, т.е. после активации следующего, предыдущий заменяется. но в промокоде может быть несколько скидок. промокоды имеют скидки только на привелеги", () => {
const testCase = prepareTestCase(exampleCartValues.testCases[9]); const testCase = prepareTestCase(exampleCartValues.testCases[9]);
const cartTotal = calcCartData(testCase.user, testCase.cartItems, discounts, "ABCD"); const cartTotal = calcCartData(testCase.user, testCase.cartItems, discounts, "ABCD") as CartTotal;
const allEnvolvedDiscounts: string[] = [...cartTotal.envolvedCartDiscountIds]; const allEnvolvedDiscounts: string[] = [...cartTotal.envolvedCartDiscountIds];
cartTotal.items.forEach(cartItem => { cartTotal.items.forEach(cartItem => {
allEnvolvedDiscounts.push(...cartItem.envolvedDiscountIds); allEnvolvedDiscounts.push(...cartItem.envolvedDiscountIds);
@ -204,7 +204,7 @@ describe("cart tests", () => {
it("юзер подтвердил свой статус НКО, поэтому, не смотря на то что он достиг по лояльности уровня скидки id2, она не применилась, а применилась id32", () => { it("юзер подтвердил свой статус НКО, поэтому, не смотря на то что он достиг по лояльности уровня скидки id2, она не применилась, а применилась id32", () => {
const testCase = prepareTestCase(exampleCartValues.testCases[10]); const testCase = prepareTestCase(exampleCartValues.testCases[10]);
const cartTotal = calcCartData(testCase.user, testCase.cartItems, discounts); const cartTotal = calcCartData(testCase.user, testCase.cartItems, discounts) as CartTotal;
const allEnvolvedDiscounts: string[] = [...cartTotal.envolvedCartDiscountIds]; const allEnvolvedDiscounts: string[] = [...cartTotal.envolvedCartDiscountIds];
cartTotal.items.forEach(cartItem => { cartTotal.items.forEach(cartItem => {
allEnvolvedDiscounts.push(...cartItem.envolvedDiscountIds); allEnvolvedDiscounts.push(...cartItem.envolvedDiscountIds);
@ -220,7 +220,7 @@ describe("cart tests", () => {
it("case 12", () => { it("case 12", () => {
const testCase = prepareTestCase(exampleCartValues.testCases[11]); const testCase = prepareTestCase(exampleCartValues.testCases[11]);
const cartTotal = calcCartData(testCase.user, testCase.cartItems, discounts); const cartTotal = calcCartData(testCase.user, testCase.cartItems, discounts) as CartTotal;
const allEnvolvedDiscounts: string[] = [...cartTotal.envolvedCartDiscountIds]; const allEnvolvedDiscounts: string[] = [...cartTotal.envolvedCartDiscountIds];
cartTotal.items.forEach(cartItem => { cartTotal.items.forEach(cartItem => {
allEnvolvedDiscounts.push(...cartItem.envolvedDiscountIds); allEnvolvedDiscounts.push(...cartItem.envolvedDiscountIds);

@ -8,7 +8,28 @@ export function calcCartData(
cartItems: CartItem[], cartItems: CartItem[],
discounts: AnyDiscount[], discounts: AnyDiscount[],
coupon?: string, coupon?: string,
): CartTotal { ): CartTotal | Error | null {
let isIncompatibleTariffs = false;
const defaultTariffTypePresent: { [Key in ServiceType]: boolean } = {
dwarfener: false,
squiz: false,
templategen: false,
};
cartItems.forEach(cartItem => {
if (cartItem.tariff.customPricePerUnit === undefined) return defaultTariffTypePresent[cartItem.tariff.privilege.serviceKey] = true;
if (
defaultTariffTypePresent[cartItem.tariff.privilege.serviceKey] &&
cartItem.tariff.customPricePerUnit !== undefined
) isIncompatibleTariffs = true;
});
if (isIncompatibleTariffs) return new Error("Если взят готовый тариф, то кастомный на этот сервис сделать уже нельзя");
if (!cartItems.length) return null;
const cartTotal: CartTotal = { const cartTotal: CartTotal = {
items: [], items: [],
totalPrice: 0, totalPrice: 0,

@ -5,7 +5,7 @@ import { CartTotal } from "@root/model/cart";
interface CartStore { interface CartStore {
cartTotal: CartTotal | null; cartTotal: CartTotal | null;
setCartTotal: (newCartTotal: CartTotal) => void; setCartTotal: (newCartTotal: CartTotal | null) => void;
} }
export const useCartStore = create<CartStore>()( export const useCartStore = create<CartStore>()(