현금영수증 완료

This commit is contained in:
focp212@naver.com
2025-10-25 21:48:10 +09:00
parent 2f13c29d1b
commit 9cffa264e7
12 changed files with 167 additions and 51 deletions

View File

@@ -3,7 +3,7 @@ import { SortTypeKeys } from "./types";
export const DEFAULT_PAGE_PARAM = {
cursor: null,
size: 0,
size: 20,
sortType: SortTypeKeys.LATEST,
limit: 0
};

View File

@@ -176,6 +176,7 @@ export interface CashReceiptListItem {
transactionTime?: string;
customerName?: string;
issueNumber?: string;
tid?: string;
approvalNumber?: string;
amount?: number;
processResult?: string;
@@ -310,10 +311,10 @@ export interface AllTransactionDetailParams {
tid?: string;
};
export interface CashReceiptDetailParams {
approvalNumber?: string;
tid?: string;
};
export interface EscrowDetailParams {
issueNumber?: number;
tid?: string;
};
export interface BillingDetailParams {
billKey?: string;
@@ -333,6 +334,12 @@ export interface AmountInfo {
multiCouponAmount?: number;
receiptAmount?: number;
cupDepositAmount?: number;
amount?: number;
supplyAmount?: number;
vat?: number;
serviceAmount?: number;
taxFreeAmount?: number;
};
export interface ImportantInfo {
moid?: string;
@@ -478,6 +485,7 @@ export interface MerchantInfo {
}
export interface DetailResponse {
amountDetail?: AmountInfo;
amountInfo?: AmountInfo;
importantInfo?: ImportantInfo;
paymentInfo?: PaymentInfo;
@@ -501,6 +509,7 @@ export interface InfoSectionProps extends DetailResponse {
serviceCode?: string;
purposeType?: CashReceiptPurposeType | string;
onClickToOpenInfo?: (info: InfoSectionKeys) => void;
canDownloadReceipt?: boolean;
}
@@ -675,7 +684,7 @@ export interface BillingFilterProps extends FilterProps {
};
export interface CashReceiptPurposeUpdateParams {
approvalNumber: string;
tid: string;
newPurpose: string;
};
export interface CashReceiptPurposeUpdateResponse {

View File

@@ -9,16 +9,11 @@ import { FilterButtonGroups } from '@/shared/ui/filter/button-groups';
import { FilterRangeAmount } from '@/shared/ui/filter/range-amount';
import {
AllTransactionMoidTidOptionsGroup,
AllTransactionStatusCodeBtnGroup,
AllTransactionServiceCodeOptionsGroup,
AllTransactionCardBankCodeOptionsGroup,
AllTracsactionStatusCode,
} from '@/entities/transaction/model/contant';
import {
AllTransactionFilterProps,
AllTransactionSearchCl,
AllTransactionStatusCode,
AllTransactionServiceCode,
AllTransactionMoidTid
} from '../../model/types';
import {

View File

@@ -58,14 +58,14 @@ export const ListItem = ({
else if(transactionCategory === TransactionCategory.CashReceipt){
navigate(PATHS.transaction.cashReceipt.detail, {
state: {
approvalNumber: approvalNumber
tid: tid
}
});
}
else if(transactionCategory === TransactionCategory.Escrow){
navigate(PATHS.transaction.escrow.detail, {
state: {
issueNumber: issueNumber
tid: tid
}
});
}

View File

@@ -12,7 +12,8 @@ export const AmountInfoSection = ({
isOpen,
tid,
serviceCode,
onClickToOpenInfo
onClickToOpenInfo,
canDownloadReceipt
}: InfoSectionProps) => {
const { mutateAsync: downloadConfirmation } = useDownloadConfirmationMutation();
let newAmountInfo: Record<string, any> | undefined = amountInfo;
@@ -186,7 +187,7 @@ export const AmountInfoSection = ({
<div className="txn-num-group">
<div className="txn-amount">
<div className="value">
{
{ (transactionCategory === TransactionCategory.AllTransaction) &&
(serviceCode === '01' || serviceCode === '02' || serviceCode === '03' || serviceCode === '26') &&
<NumericFormat
value={ amountInfo?.transactionRequestAmount }
@@ -194,11 +195,18 @@ export const AmountInfoSection = ({
displayType="text"
></NumericFormat>
}
{
{ (transactionCategory === TransactionCategory.AllTransaction) &&
(serviceCode === '05' || serviceCode === '14' || serviceCode === '21'
|| serviceCode === '24' || serviceCode === '31') &&
<NumericFormat
value={ amountInfo?.transactionAmount }
value={ amountInfo?.transactionAmount}
thousandSeparator
displayType="text"
></NumericFormat>
}
{ (transactionCategory === TransactionCategory.CashReceipt) &&
<NumericFormat
value={ amountInfo?.amount}
thousandSeparator
displayType="text"
></NumericFormat>
@@ -222,7 +230,48 @@ export const AmountInfoSection = ({
subLi()
}
{ (transactionCategory === TransactionCategory.CashReceipt) &&
<></>
<>
<li className="amount-item">
<span className="label">·&nbsp;&nbsp;</span>
<span className="value">
<NumericFormat
value={ amountInfo?.supplyAmount }
thousandSeparator
displayType="text"
></NumericFormat>
</span>
</li>
<li className="amount-item">
<span className="label">·&nbsp;&nbsp;VAT</span>
<span className="value">
<NumericFormat
value={ amountInfo?.vat }
thousandSeparator
displayType="text"
></NumericFormat>
</span>
</li>
<li className="amount-item">
<span className="label">·&nbsp;&nbsp;</span>
<span className="value">
<NumericFormat
value={ amountInfo?.serviceAmount }
thousandSeparator
displayType="text"
></NumericFormat>
</span>
</li>
<li className="amount-item">
<span className="label">·&nbsp;&nbsp;</span>
<span className="value">
<NumericFormat
value={ amountInfo?.taxFreeAmount }
thousandSeparator
displayType="text"
></NumericFormat>
</span>
</li>
</>
}
{ (transactionCategory === TransactionCategory.Escrow) &&
<></>
@@ -231,22 +280,25 @@ export const AmountInfoSection = ({
</div>
}
</SlideDown>
{ (transactionCategory === TransactionCategory.AllTransaction) &&
<div className="txn-mid">
<span className="value">{ amountInfo?.mid }</span>
</div>
}
<div className="txn-doc">
{
((transactionCategory === TransactionCategory.CashReceipt) ||
(transactionCategory === TransactionCategory.Escrow) ||
(transactionCategory === TransactionCategory.Billing)) &&
<div className="txn-doc">
!!canDownloadReceipt &&
<button
className="doc-btn"
type="button"
onClick={ () => onClickToDownloadConfirmation() }
> </button>
</div>
}
</div>
</div>
</>
);
};

View File

@@ -84,7 +84,11 @@ export const AmountSection = ({
<span className="value">{ detail.mid }</span>
</div>
<div className="txn-mid">
<span className="value">{ moment(detail.issueDate).format('YYYY.MM.DD') }</span>
<span className="value">
{ !!detail.issueDate &&
moment(detail.issueDate).format('YYYY.MM.DD')
}
</span>
</div>
<div className="txn-doc">
<button

View File

@@ -20,11 +20,23 @@ export const IssueSection = ({
</li>
<li className="kv-row">
<span className="k"></span>
<span className="v">{ moment(detail.targetBusinessStartDate).format('YYYY.MM.DD') } ~ { moment(detail.targetBusinessEndDate).format('YYYY.MM.DD') }</span>
<span className="v">
{ !!detail.targetBusinessStartDate && !!detail.targetBusinessEndDate &&
moment(detail.targetBusinessStartDate).format('YYYY.MM.DD')
+
' ~ '
+
moment(detail.targetBusinessEndDate).format('YYYY.MM.DD')
}
</span>
</li>
<li className="kv-row">
<span className="k"></span>
<span className="v">{ moment(detail.issueDate).format('YYYY.MM.DD') }</span>
<span className="v">
{ !!detail.issueDate &&
moment(detail.issueDate).format('YYYY.MM.DD')
}
</span>
</li>
<li className="kv-row">
<span className="k"></span>

View File

@@ -94,6 +94,7 @@ export const AllTransactionListPage = () => {
});
const callList = (type?: string) => {
setOnActionIntersect(false);
let listSummaryParams: AllTransactionListSummaryParams = {
moid: moid,
tid: tid,

View File

@@ -14,7 +14,9 @@ import {
DetailInfo,
InfoSectionKeys,
CashReceiptPurposeType,
AmountInfo
AmountInfo,
CashReceiptPurposeUpdateParams,
CashReceiptTransactionType
} from '@/entities/transaction/model/types';
import {
useSetOnBack,
@@ -25,17 +27,21 @@ import {
import { CashReceitPurposeUpdateBottomSheet } from '@/entities/transaction/ui/cash-receit-purpose-update-bottom-sheet';
import { useCashReceiptPurposeUpdateMutation } from '@/entities/transaction/api/use-cash-receipt-purpose-update-mutation';
import { AmountInfoSection } from '@/entities/transaction/ui/section/amount-info-section';
import { snackBar } from '@/shared/lib';
export const CashReceiptDetailPage = () => {
const { navigate } = useNavigate();
const { navigate, reload } = useNavigate();
const location = useLocation();
const [amountInfo, setAmountInfo] = useState<AmountInfo>();
const [issueInfo, setIssueInfo] = useState<IssueInfo>();
const [detailInfo, setDetailInfo] = useState<DetailInfo>();
const [showAmountInfo, setShowAmountInfo] = useState<boolean>(false);
const [showDetailInfo, setShowDetailInfo] = useState<boolean>(false);
const [bottomSheetOn, setBottomSheetOn] = useState<boolean>(false);
const [purposeType, setPurposeType] = useState<string>();
const [canDownloadReceipt, setCanDownloadReceipt] = useState<boolean>(false);
useSetHeaderTitle('현금영수증 상세');
useSetHeaderType(HeaderType.RightClose);
@@ -44,7 +50,7 @@ export const CashReceiptDetailPage = () => {
});
useSetFooterMode(false);
const approvalNumber = location?.state.approvalNumber
const tid = location?.state.tid
const { mutateAsync: cashReceiptDetail } = useCashReceiptDetailMutation();
const { mutateAsync: cashReceiptPurposeUpdate } = useCashReceiptPurposeUpdateMutation();
@@ -52,25 +58,28 @@ export const CashReceiptDetailPage = () => {
const callPurposeUpdate = () => {
let newPurpose = (purposeType === CashReceiptPurposeType.EXPENSE_PROOF)
? CashReceiptPurposeType.INCOME_DEDUCTION: CashReceiptPurposeType.EXPENSE_PROOF;
let params = {
approvalNumber: approvalNumber,
let params: CashReceiptPurposeUpdateParams = {
tid: tid,
newPurpose: newPurpose
};
cashReceiptPurposeUpdate(params).then((rs) => {
setPurposeType(rs.afterPurposeType);
setBottomSheetOn(false);
alert('toast : 용도 변경을 성공하였습니다.')
snackBar('용도 변경을 성공하였습니다.', function(){
reload();
}, 2000);
});
};
const callDetail = () => {
let cashReceitDetailParams: CashReceiptDetailParams = {
approvalNumber: approvalNumber
tid: tid
};
cashReceiptDetail(cashReceitDetailParams).then((rs: DetailResponse) => {
setAmountInfo(rs.amountInfo || {});
setAmountInfo(rs.amountDetail || {});
setIssueInfo(rs.issueInfo || {});
setDetailInfo(rs.detailInfo || {});
setCanDownloadReceipt(rs.detailInfo?.canDownloadReceipt || false);
if(rs.issueInfo){
setPurposeType(rs.issueInfo.purpose);
}
@@ -81,7 +90,10 @@ export const CashReceiptDetailPage = () => {
}, []);
const onClickToOpenInfo = (infoSectionKey: InfoSectionKeys) => {
if(infoSectionKey === InfoSectionKeys.Detail){
if(infoSectionKey === InfoSectionKeys.Amount){
setShowAmountInfo(!showAmountInfo);
}
else if(infoSectionKey === InfoSectionKeys.Detail){
setShowDetailInfo(!showDetailInfo);
}
};
@@ -100,7 +112,10 @@ export const CashReceiptDetailPage = () => {
<AmountInfoSection
transactionCategory={ TransactionCategory.CashReceipt }
amountInfo={ amountInfo }
isOpen={ showAmountInfo }
onClickToOpenInfo={ (infoSectionKey) => onClickToOpenInfo(infoSectionKey) }
purposeType={ purposeType }
canDownloadReceipt={ canDownloadReceipt }
></AmountInfoSection>
<div className="txn-divider"></div>
<IssueInfoSection
@@ -117,7 +132,8 @@ export const CashReceiptDetailPage = () => {
></DetailInfoSection>
</div>
</div>
{ !!detailInfo?.canDownloadReceipt &&
{ (issueInfo?.transactionType === CashReceiptTransactionType.APPROVAL) &&
(issueInfo?.processResult === '발급완료') &&
<div className="apply-row">
<button
className="btn-50 btn-blue flex-1"

View File

@@ -34,6 +34,7 @@ import { MerchantInfoSection } from '@/entities/transaction/ui/section/merchant-
export const EscrowDetailPage = () => {
const { navigate } = useNavigate();
const location = useLocation();
const paramTid = location?.state.tid;
const [amountInfo, setAmountInfo] = useState<ImportantInfo>();
const [importantInfo, setImportantInfo] = useState<ImportantInfo>();
@@ -54,7 +55,7 @@ export const EscrowDetailPage = () => {
const [bottomSheetOn, setBottomSheetOn] = useState<boolean>(false);
const [orderNumber, setOrderNumber] = useState<string>();
const [tid, setTid] = useState<string>();
const [tid, setTid] = useState<string | undefined>(paramTid);
useSetHeaderTitle('에스크로 상세');
useSetHeaderType(HeaderType.RightClose);
@@ -68,7 +69,7 @@ export const EscrowDetailPage = () => {
const callDetail = () => {
let escroDetailParams: EscrowDetailParams = {
issueNumber: location?.state.issueNumber,
tid: tid || paramTid,
};
escrowDetail(escroDetailParams).then((rs: DetailResponse) => {
setImportantInfo(rs.importantInfo || {});

View File

@@ -64,7 +64,7 @@ export const DetailPage = () => {
return (
<>
<main className="full-height">
<div className="tab-content">
<div className="tab-content pb-86">
<div className="tab-pane sub active">
<div className="option-list">
<div className="txn-detail">

View File

@@ -29,6 +29,7 @@ import { useShortcutDefaultMutation } from '@/entities/user/api/use-shortcut-det
import { useBusinessPropertyMutation } from '@/entities/user/api/use-business-property-mutation';
import { useUserFindAuthMethodMutation } from '@/entities/user/api/use-user-find-authmethod-mutation';
import { useCodesSelectMutation } from '@/entities/common/api/use-codes-select-mutation';
import { MenuItems } from '@/entities/common/model/constant';
export interface ContextType {
setOnBack: (onBack: () => void) => void;
@@ -127,18 +128,41 @@ export const SubLayout = () => {
};
shortcutUser(params).then((rs: ShortcutUserResponse) => {
// Modify iconFilePath to use menu_icon_{menuId}.svg format
console.log("============================rs", rs)
const modifiedShortcuts = rs.shortcuts.map(shortcut => ({
...shortcut,
iconFilePath: `menu_icon_${shortcut.menuId}.svg`
}));
console.log("============================modifiedShortcuts", modifiedShortcuts)
useStore.getState().UserStore.setUserFavorite(modifiedShortcuts);
});
}
};
// 맵 형태로 상수로 만들어 놓을 필요가 있다. 무의미한 반복문 너무 많이 사용
const getProgramPath = (menuId: number) => {
let programPath: string = '';
Loop1:
for(let i=0;i<MenuItems.length;i++){
let menuItem = MenuItems[i];
if(menuItem){
let subMenu = menuItem.subMenu;
if(subMenu){
Loop2:
for(let j=0;j<subMenu.length;j++){
let subMenuItem = subMenu[j];
if(subMenuItem){
if(subMenuItem.menuId === menuId){
programPath = subMenuItem.programPath;
break Loop1;
}
}
}
}
}
}
return programPath;
};
const callShortcutUser = () => {
console.log("============================callShortcutUser")
let userInfo = useStore.getState().UserStore.userInfo;
@@ -152,8 +176,10 @@ export const SubLayout = () => {
if(rs.shortcuts.length > 0){
const modifiedShortcuts = rs.shortcuts.map(shortcut => ({
...shortcut,
iconFilePath: `/images/menu_icon_${shortcut.menuId}.svg`
iconFilePath: `/images/menu_icon_${shortcut.menuId}.svg`,
programPath: getProgramPath(shortcut.menuId)
}));
console.log(modifiedShortcuts)
console.log("============================modifiedShortcuts", modifiedShortcuts)
useStore.getState().UserStore.setUserFavorite(modifiedShortcuts);