669 lines
34 KiB
TypeScript
669 lines
34 KiB
TypeScript
import moment from 'moment';
|
|
import { IMAGE_ROOT } from '@/shared/constants/common';
|
|
import { motion } from 'framer-motion';
|
|
import { snackBar } from '@/shared/lib';
|
|
import { toPng } from 'html-to-image';
|
|
import { useTranslation } from 'react-i18next';
|
|
import { useEffect, useState } from 'react';
|
|
import { NumericFormat } from 'react-number-format';
|
|
import { FilterMotionDuration, FilterMotionVariants } from '../model/constant';
|
|
import { RecipientInfo, SupplierInfo, TransactionDetails } from '@/entities/vat-return/model/types';
|
|
import '@/shared/ui/assets/css/style-tax-invoice.css';
|
|
import { useAppBridge } from '@/hooks/useAppBridge';
|
|
|
|
export interface TaxInvoiceSampleProps {
|
|
taxInvoiceSampleOn: boolean;
|
|
setTaxInvoiceSampleOn: (taxInvoiceSampleOn: boolean) => void;
|
|
supplierInfo?: SupplierInfo;
|
|
recipientInfo?: RecipientInfo;
|
|
issueDate?: string;
|
|
supplyAmount?: number;
|
|
taxAmount?: number
|
|
totalAmount?: number;
|
|
transactionDetails?: TransactionDetails;
|
|
};
|
|
|
|
export const TaxInvoiceSample = ({
|
|
taxInvoiceSampleOn,
|
|
setTaxInvoiceSampleOn,
|
|
supplierInfo,
|
|
recipientInfo,
|
|
issueDate,
|
|
supplyAmount,
|
|
taxAmount,
|
|
totalAmount,
|
|
transactionDetails
|
|
}: TaxInvoiceSampleProps) => {
|
|
const { t } = useTranslation();
|
|
const { isIOS, saveImage } = useAppBridge();
|
|
|
|
const [newSupplyAmount, setNewSupplyAmount] = useState<Array<string>>([]);
|
|
const [newTaxAmount, setNewTaxAmount] = useState<Array<string>>([]);
|
|
|
|
const downloadImage = async () => {
|
|
const section = document.getElementById('image-section') as HTMLElement;
|
|
|
|
try {
|
|
const imageDataUrl = await toPng(section);
|
|
const fileName = 'tax-invoice-' + moment().format('YYMMDDHHmmss');
|
|
|
|
// iOS 네이티브 환경인 경우 네이티브 브릿지 사용
|
|
if (isIOS) {
|
|
try {
|
|
// data:image/png;base64, 부분 제거하고 순수 base64 데이터만 추출
|
|
const base64Data = imageDataUrl.split(',')[1];
|
|
|
|
if (!base64Data) {
|
|
throw new Error('Failed to extract base64 data');
|
|
}
|
|
|
|
const result = await saveImage({
|
|
imageData: base64Data,
|
|
fileName: fileName + '.png',
|
|
mimeType: 'image/png'
|
|
});
|
|
|
|
if (result?.filePath) {
|
|
snackBar(t('common.imageSaved'), function(){
|
|
onClickToClose();
|
|
});
|
|
} else {
|
|
throw new Error('Failed to save image');
|
|
}
|
|
} catch (error) {
|
|
console.error('Native image save failed:', error);
|
|
snackBar(t('common.imageSaveFailed'));
|
|
}
|
|
} else {
|
|
// Android 또는 웹 환경인 경우 기존 방식 사용 (다운로드 링크)
|
|
const link = document.createElement('a');
|
|
link.download = fileName + '.png';
|
|
link.href = imageDataUrl + '#' + fileName + '.png';
|
|
link.click();
|
|
snackBar(t('common.imageRequested'), function(){
|
|
onClickToClose();
|
|
});
|
|
}
|
|
} catch (error) {
|
|
console.error('Image generation failed:', error);
|
|
snackBar(t('common.imageGenerationFailed'));
|
|
}
|
|
};
|
|
const onClickToClose = () => {
|
|
setTaxInvoiceSampleOn(false);
|
|
};
|
|
|
|
const showNewSupplyAmount = () => {
|
|
let rs = [];
|
|
let emptyCnt = 11 - newSupplyAmount.length;
|
|
for(let i=0;i<emptyCnt;i++){
|
|
rs.push(
|
|
<td className="inner-table10-td2"> </td>
|
|
);
|
|
}
|
|
for(let i=0;i<newSupplyAmount.length;i++){
|
|
let str = newSupplyAmount[i];
|
|
rs.push(
|
|
<td className="inner-table10-td2">{ str }</td>
|
|
);
|
|
}
|
|
return rs;
|
|
};
|
|
const showNewTaxAmount = () => {
|
|
let rs = [];
|
|
let emptyCnt = 10 - newTaxAmount.length;
|
|
for(let i=0;i<emptyCnt;i++){
|
|
rs.push(
|
|
<td className="inner-table10-td2"> </td>
|
|
);
|
|
}
|
|
for(let i=0;i<newTaxAmount.length;i++){
|
|
let str = newTaxAmount[i];
|
|
rs.push(
|
|
<td className="inner-table10-td2">{ str }</td>
|
|
);
|
|
}
|
|
return rs;
|
|
};
|
|
|
|
const refactSupplyAmount = () => {
|
|
let supplyAmountArr: Array<string> = [];
|
|
if(supplyAmount){
|
|
let newSupplyAmt = ''+supplyAmount;
|
|
supplyAmountArr = newSupplyAmt.split('');
|
|
}
|
|
setNewSupplyAmount(supplyAmountArr);
|
|
};
|
|
const refactTaxAmount = () => {
|
|
let taxAmountArr: Array<string> = [];
|
|
if(taxAmount){
|
|
let newTaxAmt = ''+taxAmount;
|
|
taxAmountArr = newTaxAmt.split('');
|
|
}
|
|
setNewTaxAmount(taxAmountArr);
|
|
};
|
|
|
|
useEffect(() => {
|
|
if(!!taxInvoiceSampleOn){
|
|
setTimeout(() => {
|
|
downloadImage();
|
|
}, 500);
|
|
}
|
|
}, [taxInvoiceSampleOn]);
|
|
|
|
useEffect(() => {
|
|
refactSupplyAmount();
|
|
refactTaxAmount();
|
|
}, []);
|
|
|
|
return (
|
|
<>
|
|
<div className="tax-invoice">
|
|
<div id="image-section">
|
|
<center className="wrap-center">
|
|
<table
|
|
className="outer-table"
|
|
role="presentation"
|
|
>
|
|
<tr>
|
|
<td
|
|
className="outer-table-td"
|
|
align="center"
|
|
>
|
|
<table
|
|
className="inner-table"
|
|
role="presentation"
|
|
>
|
|
<tr>
|
|
<td className="inner-table-td1">
|
|
<img
|
|
className="nicepay-logo"
|
|
src={ IMAGE_ROOT + '/mail_nicepay_logo.svg' }
|
|
alt="NICEPAY"
|
|
style={{ paddingLeft: '20px' }}
|
|
/>
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td style={{ padding: 0 }}>
|
|
<table
|
|
className="inner-table3"
|
|
role="presentation"
|
|
>
|
|
<tr>
|
|
<td className="inner-table3-td1">
|
|
<table
|
|
className="inner-table4"
|
|
role="presentation"
|
|
>
|
|
<tr>
|
|
<td className="inner-table4-td1">세금계산서</td>
|
|
</tr>
|
|
</table>
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td className="inner-table4-td2">
|
|
<table
|
|
className="inner-table5"
|
|
role="presentation"
|
|
>
|
|
<tr>
|
|
<td className="inner-table5-td1">세금계산서</td>
|
|
<td className="inner-table5-td2">
|
|
<table
|
|
className="inner-table6"
|
|
role="presentation"
|
|
>
|
|
<tr>
|
|
<td className="inner-table6-td1">승인번호</td>
|
|
<td className="inner-table6-td2"> </td>
|
|
</tr>
|
|
<tr>
|
|
<td className="inner-table6-td3">관리번호</td>
|
|
<td className="inner-table6-td4"> </td>
|
|
</tr>
|
|
</table>
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td className="inner-table4-td2">
|
|
<table
|
|
className="inner-table7"
|
|
role="presentation"
|
|
>
|
|
<tr>
|
|
<td className="inner-table7-td1">
|
|
<table
|
|
className="inner-table6"
|
|
role="presentation"
|
|
>
|
|
<tr>
|
|
<td className="inner-table6-td5">
|
|
공<br />급<br />자
|
|
</td>
|
|
<td className="inner-table6-td6">
|
|
<table
|
|
className="inner-table6"
|
|
role="presentation"
|
|
>
|
|
<tr>
|
|
<td className="inner-table6-td7">등록번호</td>
|
|
<td
|
|
className="inner-table6-td8"
|
|
colSpan={ 3 }
|
|
>{ supplierInfo?.businessRegistrationNumber }</td>
|
|
</tr>
|
|
<tr>
|
|
<td className="inner-table6-td7">상호(법인명)</td>
|
|
<td className="inner-table6-td9">{ supplierInfo?.companyName }</td>
|
|
<td className="inner-table6-td10">성명</td>
|
|
<td className="inner-table6-td8">{ supplierInfo?.ceoName }</td>
|
|
</tr>
|
|
<tr>
|
|
<td className="inner-table6-td7">사업장 주소</td>
|
|
<td
|
|
className="inner-table6-td8"
|
|
colSpan={ 3 }
|
|
>{ supplierInfo?.address }</td>
|
|
</tr>
|
|
<tr>
|
|
<td className="inner-table6-td7-1">업태</td>
|
|
<td className="inner-table6-td9-1">{ supplierInfo?.businessType }</td>
|
|
<td className="inner-table6-td10-1">종목</td>
|
|
<td className="inner-table6-td8-1">{ supplierInfo?.businessItem }</td>
|
|
</tr>
|
|
</table>
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
</td>
|
|
<td className="inner-table7-td2">
|
|
<table
|
|
className="inner-table6"
|
|
role="presentation"
|
|
>
|
|
<tr>
|
|
<td className="inner-table6-td11">
|
|
공<br />급<br />받<br />는<br />자
|
|
</td>
|
|
<td className="inner-table6-td12">
|
|
<table
|
|
className="inner-table6"
|
|
>
|
|
<tr>
|
|
<td className="inner-table6-td7">등록번호</td>
|
|
<td
|
|
className="inner-table6-td8"
|
|
colSpan={ 3 }
|
|
>{ recipientInfo?.businessRegistrationNumber }</td>
|
|
</tr>
|
|
<tr>
|
|
<td className="inner-table6-td7">상호(법인명)</td>
|
|
<td className="inner-table6-td9">{ recipientInfo?.companyName }</td>
|
|
<td className="inner-table6-td10">성명</td>
|
|
<td className="inner-table6-td8">{ recipientInfo?.ceoName }</td>
|
|
</tr>
|
|
<tr>
|
|
<td className="inner-table6-td7">사업장 주소</td>
|
|
<td
|
|
className="inner-table6-td8"
|
|
colSpan={ 3 }
|
|
>{ recipientInfo?.address }</td>
|
|
</tr>
|
|
<tr>
|
|
<td className="inner-table6-td7-1">업태</td>
|
|
<td className="inner-table6-td9-1">{ recipientInfo?.businessType }</td>
|
|
<td className="inner-table6-td10-1">종목</td>
|
|
<td className="inner-table6-td8-1">{ recipientInfo?.businessItem }</td>
|
|
</tr>
|
|
</table>
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td className="inner-table4-td2">
|
|
<table
|
|
className="inner-table8"
|
|
role="presentation"
|
|
>
|
|
<tr>
|
|
<td className="inner-table8-td1">
|
|
<table
|
|
className="inner-table9"
|
|
role="presentation"
|
|
>
|
|
<tr>
|
|
<td className="inner-table9-td1">작성</td>
|
|
</tr>
|
|
<tr>
|
|
<td style={{ padding: 0 }}>
|
|
<table
|
|
className="inner-table9"
|
|
role="presentation"
|
|
>
|
|
<tr>
|
|
<td className="inner-table9-td2">년</td>
|
|
<td className="inner-table9-td2">월</td>
|
|
<td className="inner-table9-td2">일</td>
|
|
</tr>
|
|
<tr>
|
|
<td className="inner-table9-td2-1">{ (!!issueDate)? moment(issueDate).format('YYYY'): '' }</td>
|
|
<td className="inner-table9-td2-1">{ (!!issueDate)? moment(issueDate).format('MM'): '' }</td>
|
|
<td className="inner-table9-td2-1">{ (!!issueDate)? moment(issueDate).format('DD'): '' }</td>
|
|
</tr>
|
|
</table>
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
</td>
|
|
<td className="inner-table9-td3">
|
|
<table
|
|
className="inner-table10"
|
|
role="presentation"
|
|
>
|
|
<tr>
|
|
<td className="inner-table9-td1">공급가액</td>
|
|
</tr>
|
|
<tr>
|
|
<td style={{ padding: 0 }}>
|
|
<table
|
|
className="inner-table10"
|
|
role="presentation"
|
|
>
|
|
<tr>
|
|
<td className="inner-table10-td1">백</td>
|
|
<td className="inner-table10-td1">십</td>
|
|
<td className="inner-table10-td1">억</td>
|
|
<td className="inner-table10-td1">천</td>
|
|
<td className="inner-table10-td1">백</td>
|
|
<td className="inner-table10-td1">십</td>
|
|
<td className="inner-table10-td1">만</td>
|
|
<td className="inner-table10-td1">천</td>
|
|
<td className="inner-table10-td1">백</td>
|
|
<td className="inner-table10-td1">십</td>
|
|
<td className="inner-table10-td1">일</td>
|
|
</tr>
|
|
<tr>
|
|
{ showNewSupplyAmount() }
|
|
</tr>
|
|
</table>
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
</td>
|
|
<td className="inner-table9-td3">
|
|
<table
|
|
className="inner-table10"
|
|
role="presentation"
|
|
>
|
|
<tr>
|
|
<td className="inner-table9-td1">세액</td>
|
|
</tr>
|
|
<tr>
|
|
<td style={{ padding:0 }}>
|
|
<table
|
|
className="inner-table10"
|
|
role="presentation"
|
|
>
|
|
<tr>
|
|
<td className="inner-table10-td1">십</td>
|
|
<td className="inner-table10-td1">억</td>
|
|
<td className="inner-table10-td1">천</td>
|
|
<td className="inner-table10-td1">백</td>
|
|
<td className="inner-table10-td1">십</td>
|
|
<td className="inner-table10-td1">만</td>
|
|
<td className="inner-table10-td1">천</td>
|
|
<td className="inner-table10-td1">백</td>
|
|
<td className="inner-table10-td1">십</td>
|
|
<td className="inner-table10-td1">일</td>
|
|
</tr>
|
|
<tr>
|
|
{ showNewTaxAmount() }
|
|
</tr>
|
|
</table>
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
</td>
|
|
<td className="inner-table9-td4">
|
|
<table
|
|
role="presentation"
|
|
className="inner-table11"
|
|
>
|
|
<tr>
|
|
<td className="inner-table11-td1">수정사유</td>
|
|
</tr>
|
|
<tr>
|
|
<td className="inner-table11-td2"> </td>
|
|
</tr>
|
|
</table>
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td className="inner-table4-td2">
|
|
<table
|
|
role="presentation"
|
|
className="inner-table12"
|
|
>
|
|
<tr>
|
|
<td className="inner-table12-td1">
|
|
<table className="inner-table13">
|
|
<tr>
|
|
<td className="inner-table13-td1">비고</td>
|
|
</tr>
|
|
<tr>
|
|
<td className="inner-table13-td1">월/일</td>
|
|
</tr>
|
|
<tr>
|
|
<td className="inner-table13-td2">{ (!!transactionDetails?.transactionPeriod)? moment(transactionDetails.transactionPeriod).format('MM/DD'): '' }</td>
|
|
</tr>
|
|
<tr>
|
|
<td className="inner-table13-td2"> </td>
|
|
</tr>
|
|
<tr>
|
|
<td className="inner-table13-td3"> </td>
|
|
</tr>
|
|
</table>
|
|
</td>
|
|
<td className="inner-table12-td2">
|
|
<table
|
|
role="presentation"
|
|
className="inner-table6"
|
|
>
|
|
<tr>
|
|
<td
|
|
colSpan={ 7 }
|
|
className="inner-table11-td1"
|
|
> 비고 </td>
|
|
</tr>
|
|
<tr>
|
|
<td className="inner-table9-td1">품목</td>
|
|
<td className="inner-table9-td1">규격</td>
|
|
<td className="inner-table9-td1">수량</td>
|
|
<td className="inner-table9-td1">단가</td>
|
|
<td className="inner-table9-td1">공급가액</td>
|
|
<td className="inner-table9-td1">세액</td>
|
|
<td className="inner-table11-td1">비고</td>
|
|
</tr>
|
|
<tr>
|
|
<td className="inner-table6-td9">{ transactionDetails?.itemName }</td>
|
|
<td className="inner-table6-td9">{ transactionDetails?.specification }</td>
|
|
<td className="inner-table6-td13">
|
|
<NumericFormat
|
|
value={ transactionDetails?.quantity }
|
|
thousandSeparator
|
|
displayType="text"
|
|
></NumericFormat>
|
|
</td>
|
|
<td className="inner-table6-td14">
|
|
<NumericFormat
|
|
value={ transactionDetails?.unitPrice }
|
|
thousandSeparator
|
|
displayType="text"
|
|
></NumericFormat>
|
|
</td>
|
|
<td className="inner-table6-td14">
|
|
<NumericFormat
|
|
value={ transactionDetails?.supplyAmount }
|
|
thousandSeparator
|
|
displayType="text"
|
|
></NumericFormat>
|
|
</td>
|
|
<td className="inner-table6-td14">
|
|
<NumericFormat
|
|
value={ transactionDetails?.taxAmount }
|
|
thousandSeparator
|
|
displayType="text"
|
|
></NumericFormat>
|
|
</td>
|
|
<td className="inner-table6-td15">{ transactionDetails?.remarks }</td>
|
|
</tr>
|
|
<tr>
|
|
<td className="inner-table6-td9"> </td>
|
|
<td className="inner-table6-td9"> </td>
|
|
<td className="inner-table6-td13"> </td>
|
|
<td className="inner-table6-td14"> </td>
|
|
<td className="inner-table6-td14"> </td>
|
|
<td className="inner-table6-td14"> </td>
|
|
<td className="inner-table6-td15"> </td>
|
|
</tr>
|
|
<tr>
|
|
<td className="inner-table6-td9-1"> </td>
|
|
<td className="inner-table6-td9-1"> </td>
|
|
<td className="inner-table6-td13-1"> </td>
|
|
<td className="inner-table6-td14-1"> </td>
|
|
<td className="inner-table6-td14-1"> </td>
|
|
<td className="inner-table6-td14-1"> </td>
|
|
<td className="inner-table6-td15-1"> </td>
|
|
</tr>
|
|
</table>
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td className="table_wrap">
|
|
<table
|
|
className="inner-table6"
|
|
role="presentation"
|
|
>
|
|
<tr>
|
|
<td className="inner-table4-td2">
|
|
<table
|
|
className="inner-table15"
|
|
role="presentation"
|
|
>
|
|
<tr>
|
|
<td className="inner-table15-td1">
|
|
<table
|
|
className="inner-table6"
|
|
role="presentation"
|
|
>
|
|
<tr>
|
|
<td className="inner-table15-td2">합계금액</td>
|
|
<td className="inner-table15-td2">현금</td>
|
|
<td className="inner-table15-td2">수표</td>
|
|
<td className="inner-table15-td2">어음</td>
|
|
<td className="inner-table15-td4">외상미수금</td>
|
|
</tr>
|
|
<tr>
|
|
<td className="inner-table15-td3">
|
|
<NumericFormat
|
|
value={ totalAmount }
|
|
thousandSeparator
|
|
displayType="text"
|
|
></NumericFormat>
|
|
</td>
|
|
<td className="inner-table15-td3">
|
|
<NumericFormat
|
|
value={ 0 }
|
|
thousandSeparator
|
|
displayType="text"
|
|
></NumericFormat>
|
|
</td>
|
|
<td className="inner-table15-td3">
|
|
<NumericFormat
|
|
value={ 0 }
|
|
thousandSeparator
|
|
displayType="text"
|
|
></NumericFormat>
|
|
</td>
|
|
<td className="inner-table15-td3">
|
|
<NumericFormat
|
|
value={ 0 }
|
|
thousandSeparator
|
|
displayType="text"
|
|
></NumericFormat>
|
|
</td>
|
|
<td className="inner-table15-td5"><NumericFormat
|
|
value={ 0 }
|
|
thousandSeparator
|
|
displayType="text"
|
|
></NumericFormat></td>
|
|
</tr>
|
|
</table>
|
|
</td>
|
|
<td className="inner-table15-td6">
|
|
<span className="inner-table15-td7">이금액을 청구함</span>
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td className="inner-table4-td4">
|
|
<table
|
|
className="inner-table14"
|
|
role="presentation"
|
|
>
|
|
<tr>
|
|
<td
|
|
className="inner-table4-td2"
|
|
style={{ verticalAlign: 'middle'}}
|
|
>
|
|
<img
|
|
className="nicepay-gray-logo"
|
|
src={ IMAGE_ROOT + '/mail_nicepay_logo_gray.svg' }
|
|
alt="NICEPAY"
|
|
/>
|
|
</td>
|
|
<td className="tax-invoice-footer">
|
|
사업자 등록번호 : 815-81-00527 | 결제대금예치업 등록번호 : 02-006-00041
|
|
<br />
|
|
주소 : 서울특별시 영등포구 문래로28길 25 (문래동3가) 세미콜론문래 N타워 9층 나이스페이먼츠(주)
|
|
<br />
|
|
우편번호 : 03456 | www.nicepay.co.kr
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
</center>
|
|
</div>
|
|
</div>
|
|
</>
|
|
);
|
|
}; |