diff --git a/apps/super-admin/src/components/SettlementStatement/SettlementStatement.styles.ts b/apps/super-admin/src/components/SettlementStatement/SettlementStatement.styles.ts index 035d7081..7dac5488 100644 --- a/apps/super-admin/src/components/SettlementStatement/SettlementStatement.styles.ts +++ b/apps/super-admin/src/components/SettlementStatement/SettlementStatement.styles.ts @@ -226,6 +226,15 @@ const SettlementStatementPreviewContainer = styled.div` height: 600px; `; +const PreviewMessage = styled.div` + background-color: #FACBCF; + border-radius: 8px; + padding: 16px 20px; + ${({ theme }) => theme.typo.b3}; + color: ${({ theme }) => theme.palette.grey.g90}; + margin-bottom: 32px; +`; + const TextFieldRow = styled.div` display: flex; gap: 8px; @@ -267,6 +276,7 @@ export default { SettlementStatementForm, SettlementStatementFooter, SettlementStatementPreviewContainer, + PreviewMessage, TextFieldRow, TextField, Select, diff --git a/apps/super-admin/src/components/SettlementStatement/SettlementStatementFormDialog.tsx b/apps/super-admin/src/components/SettlementStatement/SettlementStatementFormDialog.tsx index fe5f8204..ab444e4b 100644 --- a/apps/super-admin/src/components/SettlementStatement/SettlementStatementFormDialog.tsx +++ b/apps/super-admin/src/components/SettlementStatement/SettlementStatementFormDialog.tsx @@ -354,6 +354,9 @@ const SettlementStatementFormDialog = ({ )} {step === 2 && ( + + 발송 전 내역서를 다시 한 번 확인해 주세요! + ` bottom: -36px; left: 12px; background-color: ${({ theme, active }) => - active ? theme.palette.primary.o1 : theme.palette.grey.g20}; + active ? theme.palette.primary.o1 : theme.palette.grey.g20}; width: 1px; height: 30px; } @@ -105,6 +105,20 @@ const ProgressItemDescription = styled.span` color: ${({ theme }) => theme.palette.grey.g70}; `; +const ProgressItemButton = styled.button` + font-size: 15px; + font-weight: 700; + line-height: 23px; + text-decoration: underline; + color: ${({ theme }) => theme.palette.grey.g70}; + cursor: pointer; + + &:hover, &:active { + text-decoration: underline; + color: ${({ theme }) => theme.palette.grey.g70}; + } +`; + const UserInfo = styled.div` display: flex; flex-direction: column; @@ -217,6 +231,7 @@ export default { ProgressItemNumber, ProgressItemTitle, ProgressItemDescription, + ProgressItemButton, UserInfo, UserInfoItem, UserInfoTitle, diff --git a/apps/super-admin/src/pages/SettlementPage/index.tsx b/apps/super-admin/src/pages/SettlementPage/index.tsx index b23845fd..7e888956 100644 --- a/apps/super-admin/src/pages/SettlementPage/index.tsx +++ b/apps/super-admin/src/pages/SettlementPage/index.tsx @@ -5,6 +5,7 @@ import { useAdminSettlementInfo, useAdminShowDetail, useAdminTicketSalesInfo, + useSuperAdminShowSettlementStatement, } from '@boolti/api'; import { PlusIcon } from '@boolti/icon'; import { Button, useConfirm, useDialog, useToast } from '@boolti/ui'; @@ -15,6 +16,7 @@ import SettlementStatementFormDialog from '~/components/SettlementStatement/Sett import Styled from './SettlementPage.styles'; import PageLayout from '~/components/PageLayout/PageLayout'; +import { BOOLTI_FEE_RATE } from '~/constants/settlement'; const SettlementPage = () => { const params = useParams<{ showId: string }>(); @@ -28,10 +30,82 @@ const SettlementPage = () => { useAdminSettlementEvent(Number(params!.showId)); const { data: adminSettlementInfo } = useAdminSettlementInfo(Number(params!.showId)); const { data: adminTicketSalesInfo } = useAdminTicketSalesInfo(Number(params!.showId)); + const { data: superAdminShowSettlementStatementBlob } = useSuperAdminShowSettlementStatement(Number(params!.showId)) const createSettlementStatementMutation = useAdminCreateSettlementStatement(); const settlementDoneMutation = useAdminSettlementDone(); + const dialogContent = ( + { + try { + if (createSettlementStatementMutation.isLoading) return; + + const body = { + showName: data.showName, + hostName: data.hostName, + settlementBankInfo: { + bankCode: data.bankCode, + bankAccountNumber: data.accountNumber, + bankAccountHolder: data.accountHolder, + }, + businessLicenseNumber: data.businessNumber, + salesAmount: parseInt(data.salesAmount.replace(/,/g, '')), + salesItems: data.salesItems.reduce< + { + salesTicketTypeId: number; + amount: number; + }[] + >((acc, item) => { + acc.push({ + salesTicketTypeId: parseInt(item.salesTicketId.replace(/,/g, '')), + amount: parseInt(item.amount.replace(/,/g, '')), + }); + + return acc; + }, []), + fee: parseInt(data.fee.replace(/,/g, '')), + feeItems: [ + { + feeType: 'BROKERAGE_FEE' as 'BROKERAGE_FEE' | 'PAYMENT_AGENCY_FEE', + amount: parseInt(data.brokerageFee.replace(/,/g, '')), + }, + { + feeType: 'PAYMENT_AGENCY_FEE' as + | 'BROKERAGE_FEE' + | 'PAYMENT_AGENCY_FEE', + amount: parseInt(data.paymentAgencyFee.replace(/,/g, '')), + }, + ], + vat: parseInt(data.vat.replace(/,/g, '')), + roundAmount: parseInt(data.adjustmentAmount.replace(/,/g, '')), + roundReason: data.adjustmentReason, + }; + + await createSettlementStatementMutation.mutateAsync({ + showId: Number(params.showId), + body, + }); + await refetchAdminSettlementEvent(); + + toast.success('정산 내역서를 발송했어요.'); + dialog.close(); + } catch (error) { + console.error(error); + toast.error('정산 내역서를 생성하지 못했어요. 개발자에게 문의해주세요.'); + } + }} + /> + ) + return ( { {format(adminSettlementEvent.SEND, 'yyyy-MM-dd HH:mm')} )} + {adminSettlementEvent?.SEND && superAdminShowSettlementStatementBlob && ( + { + if (!adminShowDetail) return; + + const downloadUrl = URL.createObjectURL(superAdminShowSettlementStatementBlob); + + const anchorElement = document.createElement('a'); + anchorElement.href = downloadUrl; + anchorElement.download = `불티 정산 내역서 - ${adminShowDetail.name}.pdf`; + anchorElement.click(); + + URL.revokeObjectURL(downloadUrl); + }}> + 전송한 내역서 보기 + + )} @@ -78,11 +168,11 @@ const SettlementPage = () => { {adminSettlementEvent?.SEND && - adminSettlementEvent?.REQUEST && - !adminSettlementEvent?.DONE ? ( + adminSettlementEvent?.REQUEST && + !adminSettlementEvent?.DONE ? ( - - ) : ( - - - )} - - 통장 사본 @@ -248,6 +308,18 @@ const SettlementPage = () => { + + 불티 수수료 + + + + + {((adminTicketSalesInfo ?? []).reduce((acc, cur) => acc + cur.amount, 0) * BOOLTI_FEE_RATE) + .toLocaleString()} + 원 + + + @@ -257,81 +329,12 @@ const SettlementPage = () => { )} + {adminSettlementEvent?.SEND && + !adminSettlementEvent?.REQUEST && + !adminSettlementEvent?.DONE && ( + + + + )} ); }; diff --git a/packages/api/src/queries/index.ts b/packages/api/src/queries/index.ts index 018fadcd..e819fbae 100644 --- a/packages/api/src/queries/index.ts +++ b/packages/api/src/queries/index.ts @@ -40,6 +40,7 @@ import useCastTeamList from './useCastTeamList'; import useAdminTicketList from './useAdminTicketList'; import useAdminSalesTicketList from './useAdminSalesTicketList'; import useAdminReservationSummaryV2 from './useAdminReservationSummaryV2'; +import useSuperAdminShowSettlementStatement from './useSuperAdminShowSettlementStatement'; export { useCastTeamList, @@ -84,4 +85,5 @@ export { useSuperAdminSalesTicketList, useSuperAdminInvitationTicketList, useSuperAdminInvitationCodeList, + useSuperAdminShowSettlementStatement, }; diff --git a/packages/api/src/queries/useSuperAdminShowSettlementStatement.ts b/packages/api/src/queries/useSuperAdminShowSettlementStatement.ts new file mode 100644 index 00000000..94187a5d --- /dev/null +++ b/packages/api/src/queries/useSuperAdminShowSettlementStatement.ts @@ -0,0 +1,11 @@ +import { useQuery } from '@tanstack/react-query'; + +import { queryKeys } from '../queryKey'; + +const useSuperAdminShowSettlementStatement = (showId: number, options?: { enabled?: boolean }) => + useQuery({ + ...queryKeys.adminShow.settlementStatement(showId), + enabled: options?.enabled, + }); + +export default useSuperAdminShowSettlementStatement; diff --git a/packages/api/src/queryKey.ts b/packages/api/src/queryKey.ts index c051d5fc..f3cd7897 100644 --- a/packages/api/src/queryKey.ts +++ b/packages/api/src/queryKey.ts @@ -130,6 +130,11 @@ export const adminShowQueryKeys = createQueryKeys('adminShow', { queryFn: () => fetcher.get(`sa-api/v1/shows/${showId}/settlement-events/each-last`), }), + settlementStatement: (showId: number) => ({ + queryKey: [showId], + queryFn: () => + instance.get(`sa-api/v1/shows/${showId}/settlement-statements/last/file`).blob(), + }), ticketSalesInfo: (showId: number) => ({ queryKey: [showId], queryFn: () =>