diff --git a/src/client/models/CancelCardBillRequest.ts b/src/client/models/CancelCardBillRequest.ts index b717454..dbdc509 100644 --- a/src/client/models/CancelCardBillRequest.ts +++ b/src/client/models/CancelCardBillRequest.ts @@ -4,6 +4,5 @@ /* eslint-disable */ export type CancelCardBillRequest = { cardId: number; - force?: (boolean | null); }; diff --git a/src/client/models/CardGroupSchema.ts b/src/client/models/CardGroupSchema.ts index f57295c..33f9ae7 100644 --- a/src/client/models/CardGroupSchema.ts +++ b/src/client/models/CardGroupSchema.ts @@ -7,6 +7,6 @@ export type CardGroupSchema = { id: number; name?: (string | null); lexorank: string; - billRequest?: (GroupBillRequestSchema | null); + billRequests?: Array; }; diff --git a/src/client/models/CardSchema.ts b/src/client/models/CardSchema.ts index f66884b..a69df73 100644 --- a/src/client/models/CardSchema.ts +++ b/src/client/models/CardSchema.ts @@ -35,7 +35,7 @@ export type CardSchema = { clientId: (number | null); client: (ClientSchema | null); shippingWarehouse?: (ShippingWarehouseSchema | string | null); - billRequest?: (CardBillRequestSchema | null); + billRequests?: Array; group?: (CardGroupSchema | null); manager?: (UserSchema | null); pallets?: Array; diff --git a/src/client/models/CardSummary.ts b/src/client/models/CardSummary.ts index 6b06a49..ee8e232 100644 --- a/src/client/models/CardSummary.ts +++ b/src/client/models/CardSummary.ts @@ -24,7 +24,7 @@ export type CardSummary = { attributes: Array; shipmentWarehouseId: (number | null); shipmentWarehouseName: (string | null); - billRequest?: (CardBillRequestSchema | null); + billRequests?: Array; group?: (CardGroupSchema | null); }; diff --git a/src/components/Dnd/Cards/CardSummaryItem/CardSummaryItem.tsx b/src/components/Dnd/Cards/CardSummaryItem/CardSummaryItem.tsx index 2055dac..bee074f 100644 --- a/src/components/Dnd/Cards/CardSummaryItem/CardSummaryItem.tsx +++ b/src/components/Dnd/Cards/CardSummaryItem/CardSummaryItem.tsx @@ -1,4 +1,4 @@ -import { FC } from "react"; +import { FC, useEffect, useState } from "react"; import { CardService, CardSummary } from "../../../../client"; import styles from "./CardSummaryItem.module.css"; @@ -14,6 +14,7 @@ import { useProjectsContext } from "../../../../contexts/ProjectsContext.tsx"; import CardTags from "../CardTags/CardTags.tsx"; import CardAttributesInSummaryItem from "../CardAttributesInSummaryItem/CardAttributesInSummaryItem.tsx"; import { ModuleNames } from "../../../../modules/modules.tsx"; +import isDealPaid from "../../../../pages/CardsPage/utils/isDealPaid.ts"; type Props = { cardSummary: CardSummary; @@ -25,6 +26,7 @@ const CardSummaryItem: FC = ({ cardSummary, color }) => { const { selectedProject } = useProjectsContext(); const { setSelectedCard } = useCardPageContext(); const { onDelete, onComplete, onDeleteFromGroup } = useCardSummaryState(); + const [isPaid, setIsPaid] = useState(false); const isServicesAndProductsIncluded = isModuleInProject(ModuleNames.SERVICES_AND_PRODUCTS, selectedProject); const isClientIncluded = isModuleInProject(ModuleNames.CLIENTS, selectedProject); @@ -34,13 +36,14 @@ const CardSummaryItem: FC = ({ cardSummary, color }) => { setSelectedCard(card); }); }; - const isPaid = () => { - return cardSummary.billRequest?.paid || cardSummary.group?.billRequest?.paid; - }; const isLockedInsideGroup = () => { - return cardSummary.group && !cardSummary.group.billRequest; + return cardSummary.group && !cardSummary.group.billRequests; }; + useEffect(() => { + setIsPaid(isDealPaid(cardSummary)); + }, []); + return (
= ({ cardSummary, color }) => { )} - {isPaid() && ( + {isPaid && ( diff --git a/src/modules/cardModules/cardEditorTabs/ProductAndServiceTab/ProductAndServiceTab.tsx b/src/modules/cardModules/cardEditorTabs/ProductAndServiceTab/ProductAndServiceTab.tsx index a92b22d..e9c3e7e 100644 --- a/src/modules/cardModules/cardEditorTabs/ProductAndServiceTab/ProductAndServiceTab.tsx +++ b/src/modules/cardModules/cardEditorTabs/ProductAndServiceTab/ProductAndServiceTab.tsx @@ -1,4 +1,4 @@ -import { FC } from "react"; +import { FC, useEffect, useState } from "react"; import styles from "./ProductAndServiceTab.module.css"; import ProductView from "./components/ProductView/ProductView.tsx"; import { Button, Checkbox, Divider, Flex, Group, rem, ScrollArea, Stack, Text, Title } from "@mantine/core"; @@ -20,10 +20,17 @@ import GeneralDataForm from "./components/GeneralDataForm/GeneralDataForm.tsx"; import PrintDealBarcodesButton from "./components/PrintDealBarcodesButton/PrintDealBarcodesButton.tsx"; import PaymentLinkButton from "./components/PaymentLinkButton/PaymentLinkButton.tsx"; import isValidInn from "../../../../pages/ClientsPage/utils/isValidInn.ts"; +import isDealPaid, { isDealLocked } from "../../../../pages/CardsPage/utils/isDealPaid.ts"; const ProductAndServiceTab: FC = () => { const { cardState, cardServicesState, cardProductsState } = useCardProductAndServiceTabState(); - const isLocked = Boolean(cardState.card?.billRequest || cardState.card?.group?.billRequest); + const isLocked = isDealLocked(cardState.card); + const [paid, setPaid] = useState(false); + + useEffect(() => { + setPaid(isDealPaid(cardState.card)); + }, []); + const onAddProductClick = () => { if (!cardProductsState.onCreate || !cardState.card || !cardState.card.clientId) return; const productIds = cardState.card.products.map( @@ -222,7 +229,7 @@ const ProductAndServiceTab: FC = () => {
@@ -252,7 +259,7 @@ const ProductAndServiceTab: FC = () => { diff --git a/src/modules/cardModules/cardEditorTabs/ProductAndServiceTab/components/CardServicesTable/CardServicesTable.tsx b/src/modules/cardModules/cardEditorTabs/ProductAndServiceTab/components/CardServicesTable/CardServicesTable.tsx index 38872d4..51a85ff 100644 --- a/src/modules/cardModules/cardEditorTabs/ProductAndServiceTab/components/CardServicesTable/CardServicesTable.tsx +++ b/src/modules/cardModules/cardEditorTabs/ProductAndServiceTab/components/CardServicesTable/CardServicesTable.tsx @@ -31,7 +31,7 @@ const CardServicesTable: FC = ({ const authState = useSelector((state: RootState) => state.auth); const { cardState } = useCardProductAndServiceTabState(); - const isLocked = Boolean(cardState.card?.billRequest); + const isLocked = Boolean(cardState.card?.billRequests) || Boolean(cardState.card?.group?.billRequests); const [currentService, setCurrentService] = useState< CardServiceSchema | undefined diff --git a/src/modules/cardModules/cardEditorTabs/ProductAndServiceTab/components/PaymentLinkButton/PaymentLinkButton.tsx b/src/modules/cardModules/cardEditorTabs/ProductAndServiceTab/components/PaymentLinkButton/PaymentLinkButton.tsx index 3fef6fc..87cec49 100644 --- a/src/modules/cardModules/cardEditorTabs/ProductAndServiceTab/components/PaymentLinkButton/PaymentLinkButton.tsx +++ b/src/modules/cardModules/cardEditorTabs/ProductAndServiceTab/components/PaymentLinkButton/PaymentLinkButton.tsx @@ -3,19 +3,40 @@ import ButtonCopy from "../../../../../../components/ButtonCopy/ButtonCopy.tsx"; import { ButtonCopyControlled } from "../../../../../../components/ButtonCopyControlled/ButtonCopyControlled.tsx"; import { getCurrentDateTimeForFilename } from "../../../../../../shared/lib/date.ts"; import FileSaver from "file-saver"; +import { Button, Popover, Stack } from "@mantine/core"; type Props = { card: CardSchema; } const PaymentLinkButton = ({ card }: Props) => { - const billRequestPdfUrl = card?.billRequest?.pdfUrl || card?.group?.billRequest?.pdfUrl; + if ((!card.billRequests || card.billRequests.length === 0) && (!card?.group?.billRequests || card?.group?.billRequests.length === 0)) { + return ( + { + const date = + getCurrentDateTimeForFilename(); + FileSaver.saveAs( + `${import.meta.env.VITE_API_URL}/card/billing-document/${card.id}`, + `bill_${card.id}_${date}.pdf`, + ); + }} + copied={false} + onCopiedLabel={"Ссылка скопирована в буфер обмена"} + > + Ссылка на оплату (PDF) + + ); + } - if (billRequestPdfUrl) { + const requests = (card?.group ? card?.group?.billRequests : card.billRequests) ?? []; + const urls = requests.map(request => request.pdfUrl).filter(url => url !== null); + + if (urls.length === 1) { return ( Ссылка на оплату @@ -23,21 +44,25 @@ const PaymentLinkButton = ({ card }: Props) => { } return ( - { - const date = - getCurrentDateTimeForFilename(); - FileSaver.saveAs( - `${import.meta.env.VITE_API_URL}/card/billing-document/${card.id}`, - `bill_${card.id}_${date}.pdf`, - ); - }} - copied={false} - onCopiedLabel={"Ссылка скопирована в буфер обмена"} - > - Ссылка на оплату (PDF) - + + + + + + + {urls.map((url, i) => ( + + {`Ссылка на оплату (часть ${String(i + 1)})`} + + ))} + + + ); -} +}; export default PaymentLinkButton; diff --git a/src/modules/cardModules/cardEditorTabs/ProductAndServiceTab/components/ProductServicesTable/ProductServicesTable.tsx b/src/modules/cardModules/cardEditorTabs/ProductAndServiceTab/components/ProductServicesTable/ProductServicesTable.tsx index d8c7d17..7d15af7 100644 --- a/src/modules/cardModules/cardEditorTabs/ProductAndServiceTab/components/ProductServicesTable/ProductServicesTable.tsx +++ b/src/modules/cardModules/cardEditorTabs/ProductAndServiceTab/components/ProductServicesTable/ProductServicesTable.tsx @@ -11,6 +11,7 @@ import SimpleUsersTable from "../../../../../../pages/CardsPage/components/Simpl import { useSelector } from "react-redux"; import { RootState } from "../../../../../../redux/store.ts"; import useCardProductAndServiceTabState from "../../hooks/useProductAndServiceTabState.tsx"; +import { isDealLocked } from "../../../../../../pages/CardsPage/utils/isDealPaid.ts"; type RestProps = { quantity: number; @@ -20,16 +21,16 @@ type RestProps = { type Props = CRUDTableProps & RestProps; const ProductServicesTable: FC = ({ - items, - quantity, - onCreate, - onDelete, - onChange, - onCopyServices, - onKitAdd, -}) => { + items, + quantity, + onCreate, + onDelete, + onChange, + onCopyServices, + onKitAdd, + }) => { const { cardState } = useCardProductAndServiceTabState(); - const isLocked = Boolean(cardState.card?.billRequest); + const isLocked = isDealLocked(cardState.card); const authState = useSelector((state: RootState) => state.auth); const columns = useProductServicesTableColumns({ data: items, quantity }); @@ -78,7 +79,7 @@ const ProductServicesTable: FC = ({ const getCurrentEmployees = (): UserSchema[] => { if (!currentService) return []; const item = items.find( - i => i.service.id === currentService.service.id + i => i.service.id === currentService.service.id, ); if (!item) return []; return item.employees; @@ -158,7 +159,7 @@ const ProductServicesTable: FC = ({ onEmployeeClick( - row.original + row.original, ) } variant={"default"}> diff --git a/src/modules/cardModules/cardEditorTabs/ProductAndServiceTab/components/ProductView/ProductView.tsx b/src/modules/cardModules/cardEditorTabs/ProductAndServiceTab/components/ProductView/ProductView.tsx index 3dc851a..1e7de67 100644 --- a/src/modules/cardModules/cardEditorTabs/ProductAndServiceTab/components/ProductView/ProductView.tsx +++ b/src/modules/cardModules/cardEditorTabs/ProductAndServiceTab/components/ProductView/ProductView.tsx @@ -47,7 +47,7 @@ const ProductView: FC = ({ if (!onChange) return; onChange(item); }, 200); - const isLocked = Boolean(cardState.card?.billRequest); + const isLocked = Boolean(cardState.card?.billRequests) || Boolean(cardState.card?.group?.billRequests); const onDeleteClick = () => { if (!onDelete) return; onDelete(product); diff --git a/src/pages/CardsPage/utils/isDealPaid.ts b/src/pages/CardsPage/utils/isDealPaid.ts new file mode 100644 index 0000000..a07225b --- /dev/null +++ b/src/pages/CardsPage/utils/isDealPaid.ts @@ -0,0 +1,32 @@ +import { CardSchema, CardSummary } from "../../../client"; + +const isDealPaid = (deal: CardSummary | CardSchema | undefined): boolean => { + if ((!deal?.billRequests || deal?.billRequests?.length === 0) && (!deal?.group?.billRequests || deal?.group?.billRequests?.length === 0)) { + return false; + } + + if (deal.billRequests && deal.billRequests?.length !== 0) { + for (let i = 0; i < deal.billRequests.length; i++) { + if (!deal.billRequests[i].paid) { + return false; + } + } + } + if (deal.group?.billRequests && deal.group?.billRequests.length !== 0) { + for (let i = 0; i < deal.group.billRequests.length; i++) { + if (!deal.group.billRequests[i].paid) { + return false; + } + } + } + return true; +}; + +export default isDealPaid; + +export const isDealLocked = (deal: CardSummary | CardSchema | undefined): boolean => { + return !!( + (deal?.billRequests && deal?.billRequests?.length !== 0) || + (deal?.group?.billRequests && deal?.group?.billRequests?.length !== 0) + ); +};