feat:bill manual payment completed
This commit is contained in:
parent
895c032532
commit
21ec84f68d
@ -132,7 +132,7 @@ body #root{
|
|||||||
}
|
}
|
||||||
|
|
||||||
// input
|
// input
|
||||||
.semi-input-wrapper, .semi-select,.semi-datepicker-range-input {
|
.semi-input-wrapper, .semi-select,.semi-datepicker-range-input,.semi-input-textarea-wrapper {
|
||||||
background-color: transparent;
|
background-color: transparent;
|
||||||
border: 1px var(--semi-color-fill-2) solid;
|
border: 1px var(--semi-color-fill-2) solid;
|
||||||
border-radius: var(--semi-border-radius-small);
|
border-radius: var(--semi-border-radius-small);
|
||||||
|
@ -41,6 +41,7 @@
|
|||||||
"reconciliation_status_pending": "UNCHECKED",
|
"reconciliation_status_pending": "UNCHECKED",
|
||||||
"reconciliation_status_submitted": "CHECKED",
|
"reconciliation_status_submitted": "CHECKED",
|
||||||
"require_student_number": "Search Student Number",
|
"require_student_number": "Search Student Number",
|
||||||
|
"set_bill_paid": "Set Bill Paid",
|
||||||
"sort_asc": "ASC",
|
"sort_asc": "ASC",
|
||||||
"sort_desc": "DESC",
|
"sort_desc": "DESC",
|
||||||
"title_actual_payment_amount": "Actually Paid",
|
"title_actual_payment_amount": "Actually Paid",
|
||||||
@ -53,11 +54,13 @@
|
|||||||
"title_operate": "Operation",
|
"title_operate": "Operation",
|
||||||
"title_paid_at": "Transaction Date",
|
"title_paid_at": "Transaction Date",
|
||||||
"title_pay_amount": "Pay Amount",
|
"title_pay_amount": "Pay Amount",
|
||||||
|
"title_pay_channel": "Payment Channel",
|
||||||
"title_pay_method": "Pay Method",
|
"title_pay_method": "Pay Method",
|
||||||
"title_pay_sort": "Sort By",
|
"title_pay_sort": "Sort By",
|
||||||
"title_program_id": "Program ID",
|
"title_program_id": "Program ID",
|
||||||
"title_program_name": "Program",
|
"title_program_name": "Program",
|
||||||
"title_reconciliation_status": "Reconciliation",
|
"title_reconciliation_status": "Reconciliation",
|
||||||
|
"title_remark": "Remark",
|
||||||
"title_semester": "Semester",
|
"title_semester": "Semester",
|
||||||
"title_service_charge": "Service Charge",
|
"title_service_charge": "Service Charge",
|
||||||
"title_student_name": "Student Name",
|
"title_student_name": "Student Name",
|
||||||
|
@ -41,6 +41,7 @@
|
|||||||
"reconciliation_status_pending": "未对账",
|
"reconciliation_status_pending": "未对账",
|
||||||
"reconciliation_status_submitted": "已对账",
|
"reconciliation_status_submitted": "已对账",
|
||||||
"require_student_number": "请输入查询学号",
|
"require_student_number": "请输入查询学号",
|
||||||
|
"set_bill_paid": "设置账单支付完成",
|
||||||
"sort_asc": "升序",
|
"sort_asc": "升序",
|
||||||
"sort_desc": "降序",
|
"sort_desc": "降序",
|
||||||
"title_actual_payment_amount": "实付金额",
|
"title_actual_payment_amount": "实付金额",
|
||||||
@ -53,11 +54,13 @@
|
|||||||
"title_operate": "操作",
|
"title_operate": "操作",
|
||||||
"title_paid_at": "支付时间",
|
"title_paid_at": "支付时间",
|
||||||
"title_pay_amount": "应付金额",
|
"title_pay_amount": "应付金额",
|
||||||
|
"title_pay_channel": "支付渠道",
|
||||||
"title_pay_method": "支付方式",
|
"title_pay_method": "支付方式",
|
||||||
"title_pay_sort": "排序方式",
|
"title_pay_sort": "排序方式",
|
||||||
"title_program_id": "专业ID",
|
"title_program_id": "专业ID",
|
||||||
"title_program_name": "就读专业",
|
"title_program_name": "就读专业",
|
||||||
"title_reconciliation_status": "对账状态",
|
"title_reconciliation_status": "对账状态",
|
||||||
|
"title_remark": "备注",
|
||||||
"title_semester": "学期",
|
"title_semester": "学期",
|
||||||
"title_service_charge": "手续费",
|
"title_service_charge": "手续费",
|
||||||
"title_student_name": "学生姓名",
|
"title_student_name": "学生姓名",
|
||||||
|
@ -41,6 +41,7 @@
|
|||||||
"reconciliation_status_pending": "未對帳",
|
"reconciliation_status_pending": "未對帳",
|
||||||
"reconciliation_status_submitted": "已對帳",
|
"reconciliation_status_submitted": "已對帳",
|
||||||
"require_student_number": "請輸入查詢學號",
|
"require_student_number": "請輸入查詢學號",
|
||||||
|
"set_bill_paid": "設定帳單支付完成",
|
||||||
"sort_asc": "升序",
|
"sort_asc": "升序",
|
||||||
"sort_desc": "降序",
|
"sort_desc": "降序",
|
||||||
"title_actual_payment_amount": "實付金額",
|
"title_actual_payment_amount": "實付金額",
|
||||||
@ -53,11 +54,13 @@
|
|||||||
"title_operate": "操作",
|
"title_operate": "操作",
|
||||||
"title_paid_at": "付款時間",
|
"title_paid_at": "付款時間",
|
||||||
"title_pay_amount": "應付金額",
|
"title_pay_amount": "應付金額",
|
||||||
|
"title_pay_channel": "支付渠道",
|
||||||
"title_pay_method": "付款方式",
|
"title_pay_method": "付款方式",
|
||||||
"title_pay_sort": "排序方式",
|
"title_pay_sort": "排序方式",
|
||||||
"title_program_id": "專業ID",
|
"title_program_id": "專業ID",
|
||||||
"title_program_name": "就讀專業",
|
"title_program_name": "就讀專業",
|
||||||
"title_reconciliation_status": "對帳狀態",
|
"title_reconciliation_status": "對帳狀態",
|
||||||
|
"title_remark": "備註",
|
||||||
"title_semester": "學期",
|
"title_semester": "學期",
|
||||||
"title_service_charge": "手續費",
|
"title_service_charge": "手續費",
|
||||||
"title_student_name": "學生姓名",
|
"title_student_name": "學生姓名",
|
||||||
|
147
src/pages/bill/components/bill_paid_modal.tsx
Normal file
147
src/pages/bill/components/bill_paid_modal.tsx
Normal file
@ -0,0 +1,147 @@
|
|||||||
|
import {BillDetailItems} from "@/components/bill";
|
||||||
|
import {Button, Col, Form, Modal, Notification, Row, Space, Toast} from "@douyinfe/semi-ui";
|
||||||
|
import React from "react";
|
||||||
|
import {useTranslation} from "react-i18next";
|
||||||
|
import {finishBill, modifyBillStatus} from "@/service/api/bill.ts";
|
||||||
|
import {BizError} from "@/service/types.ts";
|
||||||
|
import {useSetState} from "ahooks";
|
||||||
|
|
||||||
|
type BillPaidModalProps = {
|
||||||
|
bill: BillModel;
|
||||||
|
open?: boolean;
|
||||||
|
onConfirm: () => void
|
||||||
|
onCancel: () => void
|
||||||
|
}
|
||||||
|
export const BillPaidModal: React.FC<BillPaidModalProps> = (props) => {
|
||||||
|
const {t} = useTranslation()
|
||||||
|
|
||||||
|
const [state, setState] = useSetState<{
|
||||||
|
loading?: boolean
|
||||||
|
}>({})
|
||||||
|
const onConfirmPaid = () => {
|
||||||
|
if (!props.bill) return;
|
||||||
|
setState({
|
||||||
|
loading: true
|
||||||
|
})
|
||||||
|
modifyBillStatus(props.bill.id, 'PAID').then(() => {
|
||||||
|
setState({loading: false})
|
||||||
|
Notification.success({title: 'Notice', content: t('base.operate_success')})
|
||||||
|
props.onConfirm()
|
||||||
|
}).catch((e: BizError) => {
|
||||||
|
setState({loading: false})
|
||||||
|
Toast.error({
|
||||||
|
content: `${t('base.operate_fail')}:${e.message}`,
|
||||||
|
duration: 3
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
const onSubmit = (values: BillUpdateParams) => {
|
||||||
|
if (!props.bill) return;
|
||||||
|
finishBill({bill:props.bill,param:values}).then(props.onConfirm)
|
||||||
|
// setState({
|
||||||
|
// loading: true
|
||||||
|
// })
|
||||||
|
// modifyBillStatus(props.bill.id, 'PAID', values).then(() => {
|
||||||
|
// setState({loading: false})
|
||||||
|
// Notification.success({title: 'Notice', content: t('base.operate_success')})
|
||||||
|
// props.onConfirm()
|
||||||
|
// }).catch((e: BizError) => {
|
||||||
|
// setState({loading: false})
|
||||||
|
// Toast.error({
|
||||||
|
// content: `${t('base.operate_fail')}:${e.message}`,
|
||||||
|
// duration: 3
|
||||||
|
// })
|
||||||
|
// })
|
||||||
|
}
|
||||||
|
return <Modal
|
||||||
|
title={t('bill.set_bill_paid') + ` - ${props.bill?.id}`}
|
||||||
|
visible={props.open}
|
||||||
|
closeOnEsc={true}
|
||||||
|
onCancel={props.onCancel}
|
||||||
|
confirmLoading={state.loading}
|
||||||
|
onOk={onConfirmPaid}
|
||||||
|
footer={null}
|
||||||
|
width={600}
|
||||||
|
okText={t('base.confirm_paid')}
|
||||||
|
maskClosable={false}
|
||||||
|
>
|
||||||
|
{props.bill && <div><BillDetailItems bill={props.bill}/></div>}
|
||||||
|
|
||||||
|
<Form<BillUpdateParams> onSubmit={onSubmit} initValues={{
|
||||||
|
payment_channel: 'FLYWIRE',
|
||||||
|
payment_method: 'card',
|
||||||
|
merchant_ref: props.bill?.merchant_ref,
|
||||||
|
payment_amount: props.bill?.amount,
|
||||||
|
actual_payment_amount: props.bill?.amount
|
||||||
|
}}>
|
||||||
|
<Row gutter={20}>
|
||||||
|
<Col span={12}>
|
||||||
|
<Form.Select
|
||||||
|
rules={[
|
||||||
|
{required: true, message: 'required error'},
|
||||||
|
]}
|
||||||
|
showClear field="payment_channel" label={t('bill.title_pay_channel')}
|
||||||
|
placeholder={t('base.please_select')} style={{width: '100%'}}>
|
||||||
|
<Form.Select.Option value="FLYWIRE">FLYWIRE</Form.Select.Option>
|
||||||
|
{/*<Form.Select.Option value="ASIAPAY">ASIAPAY</Form.Select.Option>*/}
|
||||||
|
{/*<Form.Select.Option value="PPS">PPS</Form.Select.Option>*/}
|
||||||
|
</Form.Select>
|
||||||
|
</Col>
|
||||||
|
<Col span={12}>
|
||||||
|
<Form.Select
|
||||||
|
rules={[
|
||||||
|
{required: true, message: 'required error'},
|
||||||
|
]}
|
||||||
|
showClear field="payment_method" label={t('bill.title_pay_method')}
|
||||||
|
placeholder={t('base.please_select')} style={{width: '100%'}}>
|
||||||
|
<Form.Select.Option value="card">Card(VISA,MasterCard,UnionPay,JCB...)</Form.Select.Option>
|
||||||
|
<Form.Select.Option value="wechat">Wechat</Form.Select.Option>
|
||||||
|
<Form.Select.Option value="alipay">Alipay</Form.Select.Option>
|
||||||
|
<Form.Select.Option value="other">Other</Form.Select.Option>
|
||||||
|
{/*<Form.Select.Option value="ASIAPAY">ASIAPAY</Form.Select.Option>*/}
|
||||||
|
{/*<Form.Select.Option value="PPS">PPS</Form.Select.Option>*/}
|
||||||
|
</Form.Select>
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
<Row gutter={20}>
|
||||||
|
<Col span={12}>
|
||||||
|
<Form.Input
|
||||||
|
rules={[
|
||||||
|
{required: true, message: 'required error'},
|
||||||
|
]}
|
||||||
|
showClear field="merchant_ref" label="Merchant Ref"
|
||||||
|
placeholder={t('base.please_enter')} style={{width: '100%'}}/>
|
||||||
|
</Col>
|
||||||
|
<Col span={6}>
|
||||||
|
<Form.Input
|
||||||
|
rules={[
|
||||||
|
{required: true, message: 'required error'},
|
||||||
|
]} type={'number'} showClear
|
||||||
|
field="payment_amount" label={t('bill.title_pay_amount')}
|
||||||
|
placeholder={t('base.please_enter')} style={{width: '100%'}}/>
|
||||||
|
</Col>
|
||||||
|
<Col span={6}>
|
||||||
|
<Form.Input
|
||||||
|
type={'number'}
|
||||||
|
showClear field="actual_payment_amount" label={t('bill.title_actual_payment_amount')}
|
||||||
|
placeholder={t('base.please_enter')} style={{width: '100%'}}/>
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
<Row gutter={20}>
|
||||||
|
<Col span={24}>
|
||||||
|
<Form.TextArea
|
||||||
|
rules={[{required: true, message: 'required error'}]}
|
||||||
|
showClear field="remark" label={t('bill.title_remark')} placeholder={t('base.please_enter')}
|
||||||
|
style={{width: '100%'}}/>
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
{/*<p style={{marginTop: 10}}>{t('bill.paid_confirm')}</p>*/}
|
||||||
|
<div className={'text-right'} style={{margin: '10px 0 20px'}}>
|
||||||
|
<Space spacing={12}>
|
||||||
|
<Button onClick={props.onCancel} type={'tertiary'}>{t('base.cancel')}</Button>
|
||||||
|
<Button loading={state.loading} htmlType={'submit'} theme={'solid'} type={'primary'}>{t('base.confirm_paid')}</Button>
|
||||||
|
</Space>
|
||||||
|
</div>
|
||||||
|
</Form>
|
||||||
|
</Modal>
|
||||||
|
}
|
@ -9,9 +9,9 @@ import BillDetail from "@/components/bill/detail.tsx";
|
|||||||
import {billList, BillQueryParams, modifyBillStatus} from "@/service/api/bill.ts";
|
import {billList, BillQueryParams, modifyBillStatus} from "@/service/api/bill.ts";
|
||||||
import {BillStatus, BizError} from "@/service/types.ts";
|
import {BillStatus, BizError} from "@/service/types.ts";
|
||||||
import {useDownloadReceiptPDF} from "@/service/generate-pdf.ts";
|
import {useDownloadReceiptPDF} from "@/service/generate-pdf.ts";
|
||||||
import useAuth from "@/hooks/useAuth.ts";
|
|
||||||
import {BillDetailItems} from "@/components/bill";
|
import {BillDetailItems} from "@/components/bill";
|
||||||
import MoneyFormat from "@/components/money-format.tsx";
|
import MoneyFormat from "@/components/money-format.tsx";
|
||||||
|
import {BillPaidModal} from "@/pages/bill/components/bill_paid_modal.tsx";
|
||||||
|
|
||||||
|
|
||||||
const DownloadButton = ({bill, text}: { bill: BillModel; text: string }) => {
|
const DownloadButton = ({bill, text}: { bill: BillModel; text: string }) => {
|
||||||
@ -54,27 +54,6 @@ const BillQuery = () => {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const onConfirmPaid = () => {
|
|
||||||
if (!state.updateBill) return;
|
|
||||||
setState({
|
|
||||||
updateLoading: true
|
|
||||||
})
|
|
||||||
modifyBillStatus(state.updateBill.id, 'PAID').then(() => {
|
|
||||||
setState({
|
|
||||||
updateBill: undefined, updateLoading: false
|
|
||||||
})
|
|
||||||
Notification.success({title: 'Notice', content: t('base.operate_success')})
|
|
||||||
refresh()
|
|
||||||
}).catch((e: BizError) => {
|
|
||||||
setState({
|
|
||||||
updateLoading: false
|
|
||||||
})
|
|
||||||
Toast.error({
|
|
||||||
content: `${t('base.operate_fail')}:${e.message}`,
|
|
||||||
duration: 3
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
const operation = (bill: BillModel) => {
|
const operation = (bill: BillModel) => {
|
||||||
|
|
||||||
return (<div className={'table-operation-render'}>
|
return (<div className={'table-operation-render'}>
|
||||||
@ -128,21 +107,15 @@ const BillQuery = () => {
|
|||||||
>
|
>
|
||||||
{showBill && <BillDetail bill={showBill} onCancel={() => setShowBill(undefined)}/>}
|
{showBill && <BillDetail bill={showBill} onCancel={() => setShowBill(undefined)}/>}
|
||||||
</Modal>
|
</Modal>
|
||||||
<Modal
|
<BillPaidModal
|
||||||
title="Notice"
|
open={!!state.updateBill}
|
||||||
visible={!!state.updateBill}
|
onCancel={()=>setState({updateBill:undefined})}
|
||||||
closeOnEsc={true}
|
bill={state.updateBill!}
|
||||||
onCancel={() => {
|
onConfirm={()=>{
|
||||||
setState({updateBill: undefined, updateLoading: false})
|
setState({updateBill:undefined})
|
||||||
|
refresh()
|
||||||
}}
|
}}
|
||||||
confirmLoading={state.updateLoading}
|
/>
|
||||||
onOk={onConfirmPaid}
|
|
||||||
okText={t('base.confirm_paid')}
|
|
||||||
maskClosable={false}
|
|
||||||
>
|
|
||||||
{state.updateBill && <div><BillDetailItems bill={state.updateBill}/></div>}
|
|
||||||
<p style={{marginTop: 10}}>{t('bill.paid_confirm')}</p>
|
|
||||||
</Modal>
|
|
||||||
<Modal
|
<Modal
|
||||||
title="Confirm Bill Type"
|
title="Confirm Bill Type"
|
||||||
visible={!!state.confirmBill}
|
visible={!!state.confirmBill}
|
||||||
@ -166,9 +139,8 @@ const BillQuery = () => {
|
|||||||
</div>
|
</div>
|
||||||
</Space>
|
</Space>
|
||||||
<div className="confirm-item-btn">
|
<div className="confirm-item-btn">
|
||||||
{!!it.confirm_status ? <Tag color='light-blue'>CONFIRMED</Tag> :
|
{it.confirm_status == 'CONFIRMED' ? <Tag color='light-blue'>CONFIRMED</Tag> :
|
||||||
<Button>{t('base.confirm')}</Button>}
|
<Button>{t('base.confirm')}</Button>}
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>))
|
</div>))
|
||||||
}
|
}
|
||||||
|
@ -10,98 +10,102 @@ import useAuth from "@/hooks/useAuth.ts";
|
|||||||
import {BizError} from "@/service/types.ts";
|
import {BizError} from "@/service/types.ts";
|
||||||
|
|
||||||
const BillReconciliation = () => {
|
const BillReconciliation = () => {
|
||||||
const {t} = useTranslation()
|
const {t} = useTranslation()
|
||||||
const {user} = useAuth();
|
const {user} = useAuth();
|
||||||
const [queryParams, setBillQueryParams] = useState<BillQueryParams>({
|
const [queryParams, setBillQueryParams] = useState<BillQueryParams>({
|
||||||
apply_status:'UNCHECKED'
|
apply_status: 'UNCHECKED'
|
||||||
});
|
});
|
||||||
const {data, loading, refresh} = useRequest(() => billList({
|
const {data, loading, refresh} = useRequest(() => billList({
|
||||||
...queryParams,
|
...queryParams,
|
||||||
status: 'PAID',
|
status: 'PAID',
|
||||||
department: user?.department == 'RO' ? 'RO' : 'FO',
|
confirm_status: 'CONFIRMED',
|
||||||
}), {
|
department: user?.department == 'RO' ? 'RO' : 'FO',
|
||||||
refreshDeps: [queryParams],
|
}), {
|
||||||
onError: (e:Error) => {
|
refreshDeps: [queryParams],
|
||||||
Toast.error({
|
onError: (e: Error) => {
|
||||||
content: `${t('base.query_bill')}:${e.message}`,
|
Toast.error({
|
||||||
duration: 3
|
content: `${t('base.query_bill')}:${e.message}`,
|
||||||
})
|
duration: 3
|
||||||
}
|
})
|
||||||
})
|
}
|
||||||
|
})
|
||||||
|
|
||||||
const [selectKeys, setSelectedKeys] = useState<(string | number)[]>([])
|
const [selectKeys, setSelectedKeys] = useState<(string | number)[]>([])
|
||||||
const [state,setState] = useSetState({
|
const [state, setState] = useSetState({
|
||||||
checkingId: -1
|
checkingId: -1
|
||||||
})
|
})
|
||||||
const confirmBill = (records: number[]) => {
|
const confirmBill = (records: number[]) => {
|
||||||
if (records.length == 0) {
|
if (records.length == 0) {
|
||||||
Notification.error({title: 'Notice', content: t('bill.confirm_select_empty')})
|
Notification.error({title: 'Notice', content: t('bill.confirm_select_empty')})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
setState({checkingId: records.length > 1 ? 0 : records[0] })
|
setState({checkingId: records.length > 1 ? 0 : records[0]})
|
||||||
confirmBills(records).then(() => {
|
confirmBills(records).then(() => {
|
||||||
Notification.success({title: 'Notice', content: t('bill.confirm_success')})
|
Notification.success({title: 'Notice', content: t('bill.confirm_success')})
|
||||||
refresh()
|
refresh()
|
||||||
}).catch((e:BizError) => {
|
}).catch((e: BizError) => {
|
||||||
Toast.error({
|
Toast.error({
|
||||||
content: `${t('base.operate_fail')}:${e.message}`,
|
content: `${t('base.operate_fail')}:${e.message}`,
|
||||||
duration: 3
|
duration: 3
|
||||||
})
|
})
|
||||||
}).finally(() => {setState({checkingId: -1})})
|
}).finally(() => {
|
||||||
}
|
setState({checkingId: -1})
|
||||||
const operation = (_record: BillModel) => {
|
})
|
||||||
return (<Space>
|
}
|
||||||
<Popconfirm
|
const operation = (_record: BillModel) => {
|
||||||
title={'Notice'}
|
return (<Space>
|
||||||
content={t('bill.confirm_confirm_title')}
|
<Popconfirm
|
||||||
onConfirm={() => confirmBill([_record.id])}
|
title={'Notice'}
|
||||||
>
|
content={t('bill.confirm_confirm_title')}
|
||||||
<Button loading={state.checkingId == _record.id} size={'small'} theme={'solid'}
|
onConfirm={() => confirmBill([_record.id])}
|
||||||
type={'primary'}>{t('bill.confirm')}</Button>
|
>
|
||||||
</Popconfirm>
|
<Button
|
||||||
</Space>)
|
loading={state.checkingId == _record.id} size={'small'} theme={'solid'}
|
||||||
}
|
type={'primary'}>{t('bill.confirm')}</Button>
|
||||||
|
</Popconfirm>
|
||||||
|
</Space>)
|
||||||
|
}
|
||||||
|
|
||||||
return (<div>
|
return (<div>
|
||||||
|
|
||||||
<SearchForm
|
<SearchForm
|
||||||
searchHeader={(
|
searchHeader={(
|
||||||
<Tabs className={'no-border'} onChange={(apply_status) => setBillQueryParams({
|
<Tabs className={'no-border'} onChange={(apply_status) => setBillQueryParams({
|
||||||
apply_status,
|
apply_status,
|
||||||
status: 'PAID'
|
status: 'PAID'
|
||||||
})}>
|
})}>
|
||||||
<TabPane tab={<span>{t('bill.reconciliation_status_pending')}</span>} itemKey="UNCHECKED"/>
|
<TabPane tab={<span>{t('bill.reconciliation_status_pending')}</span>} itemKey="UNCHECKED"/>
|
||||||
<TabPane tab={<span>{t('bill.reconciliation_status_submitted')}</span>} itemKey="CHECKED"/>
|
<TabPane tab={<span>{t('bill.reconciliation_status_submitted')}</span>} itemKey="CHECKED"/>
|
||||||
</Tabs>
|
</Tabs>
|
||||||
)}
|
)}
|
||||||
loading={loading}
|
loading={loading}
|
||||||
onSearch={(params) => {
|
onSearch={(params) => {
|
||||||
setBillQueryParams({...params, apply_status: queryParams.apply_status})
|
setBillQueryParams({...params, apply_status: queryParams.apply_status})
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<BillList
|
<BillList
|
||||||
source={data} type={'reconciliation'}
|
source={data} type={'reconciliation'}
|
||||||
operationRender={queryParams.apply_status == 'CHECKED' ? undefined : operation}
|
operationRender={queryParams.apply_status == 'CHECKED' ? undefined : operation}
|
||||||
onRowSelection={queryParams.apply_status == 'CHECKED' ? undefined : (keys: (number | string)[]) => {
|
onRowSelection={queryParams.apply_status == 'CHECKED' ? undefined : (keys: (number | string)[]) => {
|
||||||
setSelectedKeys(keys);
|
setSelectedKeys(keys);
|
||||||
}}
|
}}
|
||||||
loading={loading}
|
loading={loading}
|
||||||
onPageChange={(page_number) => setBillQueryParams({
|
onPageChange={(page_number) => setBillQueryParams({
|
||||||
...queryParams,
|
...queryParams,
|
||||||
page_number
|
page_number
|
||||||
})}
|
})}
|
||||||
tableFooter={queryParams.apply_status != 'CHECKED' && selectKeys?.length > 0 && (
|
tableFooter={queryParams.apply_status != 'CHECKED' && selectKeys?.length > 0 && (
|
||||||
<Popconfirm
|
<Popconfirm
|
||||||
title={'Notice'}
|
title={'Notice'}
|
||||||
content={`${t('bill.cancel_confirm_bills')}?`}
|
content={`${t('bill.cancel_confirm_bills')}?`}
|
||||||
onConfirm={() => confirmBill(selectKeys as number[])}
|
onConfirm={() => confirmBill(selectKeys as number[])}
|
||||||
>
|
>
|
||||||
<Button style={{marginRight: 10}}>
|
<Button style={{marginRight: 10}}>
|
||||||
{t('bill.confirm_batch')}
|
{t('bill.confirm_batch')}
|
||||||
</Button>
|
</Button>
|
||||||
</Popconfirm>
|
</Popconfirm>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
</div>)
|
</div>)
|
||||||
}
|
}
|
||||||
export default BillReconciliation
|
export default BillReconciliation
|
@ -1,4 +1,5 @@
|
|||||||
import {get, post, put} from "@/service/request.ts";
|
import {get, post, put} from "@/service/request.ts";
|
||||||
|
import dayjs from "dayjs";
|
||||||
|
|
||||||
export type BillQueryResult = {
|
export type BillQueryResult = {
|
||||||
result: BillModel[];
|
result: BillModel[];
|
||||||
@ -63,3 +64,57 @@ export function updateBillPaymentSuccess(bill_id: number, merchant_ref: string,
|
|||||||
export function createExternalBill(params: ExternalCreateParamsType) {
|
export function createExternalBill(params: ExternalCreateParamsType) {
|
||||||
return post<BillModel>('/bill', params)
|
return post<BillModel>('/bill', params)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type BillUpdateFormParams = {
|
||||||
|
bill:BillModel;
|
||||||
|
param:BillUpdateParams
|
||||||
|
}
|
||||||
|
export async function finishAsiapay({bill,param}: BillUpdateFormParams){
|
||||||
|
const paramUrl = `?prc=0&src=0&Ord=12345678&Ref=${param.merchant_ref}&PayRef=123456&successcode=0&Amt=10.00&Cur=344&Holder=Test Card&AuthId=123456&AlertCode=&remark=
|
||||||
|
&eci=07&payerAuth=U&sourceIp=192.1.1.1&ipCountry=HK&payMethod=VISA
|
||||||
|
x&cardIssuingCountry=HK&channelType=SPC&`
|
||||||
|
const ret = await post<string>(`/flywire/feedback?${paramUrl}`, {},true)
|
||||||
|
|
||||||
|
return ret?.toLowerCase() == 'ok'
|
||||||
|
}
|
||||||
|
export async function finishFlywire({bill,param}: BillUpdateFormParams){
|
||||||
|
const eventData = {
|
||||||
|
"event_type": "guaranteed",
|
||||||
|
"event_date": dayjs().format('YYYY-MM-DDTHH:mm:ss[Z]'),
|
||||||
|
"event_resource": "payments",
|
||||||
|
"data": {
|
||||||
|
"remark": param.remark,
|
||||||
|
"payment_id": param.merchant_ref,
|
||||||
|
"amount_from": param.actual_payment_amount,
|
||||||
|
"currency_from": "HKD",
|
||||||
|
"amount_to": param.payment_amount,
|
||||||
|
"currency_to": "HKD",
|
||||||
|
"status": "guaranteed",
|
||||||
|
"expiration_date": dayjs().format('YYYY-MM-DDTHH:mm:ss[Z]'),
|
||||||
|
"external_reference": bill.id,
|
||||||
|
"country": "CN",
|
||||||
|
"payment_method": {
|
||||||
|
"type": param.payment_channel
|
||||||
|
},
|
||||||
|
"fields": {
|
||||||
|
"student_email": bill.student_email,
|
||||||
|
"student_last_name": bill.student_last_name || bill.student_english_name,
|
||||||
|
"student_id": bill.student_number,
|
||||||
|
"resident_no": null,
|
||||||
|
"contact_no": "",
|
||||||
|
"payment_type_other": null,
|
||||||
|
"payment_type": null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const ret = await post<string>('/flywire/feedback', eventData,true)
|
||||||
|
|
||||||
|
return ret?.toLowerCase() == 'ok'
|
||||||
|
}
|
||||||
|
|
||||||
|
export function finishBill(params: BillUpdateFormParams) {
|
||||||
|
if(params.param.payment_channel === 'flywire'){
|
||||||
|
return finishAsiapay(params)
|
||||||
|
}
|
||||||
|
return finishFlywire(params)
|
||||||
|
}
|
@ -27,7 +27,7 @@ export function GeneratePdf(bill: BillModel) {
|
|||||||
|
|
||||||
doc.setFont('Helvetica', 'normal', 'normal');
|
doc.setFont('Helvetica', 'normal', 'normal');
|
||||||
drawItem(doc, {title: 'Student Name:', content: bill.student_english_name || bill.student_chinese_name}, 40)
|
drawItem(doc, {title: 'Student Name:', content: bill.student_english_name || bill.student_chinese_name}, 40)
|
||||||
drawItem(doc, {title: 'Reference Number:', content: `${bill.application_number}`}, 40, "right")
|
drawItem(doc, {title: 'Reference Number:', content: `${bill.id}`}, 40, "right")
|
||||||
drawItem(doc, {title: 'Student Number:', content: `${bill.student_number || bill.application_number}`}, 48)
|
drawItem(doc, {title: 'Student Number:', content: `${bill.student_number || bill.application_number}`}, 48)
|
||||||
drawItem(doc, {title: 'Print Date:', content: dayjs().format('YYYY-MM-DD')}, 48, "right")
|
drawItem(doc, {title: 'Print Date:', content: dayjs().format('YYYY-MM-DD')}, 48, "right")
|
||||||
|
|
||||||
@ -58,10 +58,10 @@ export function GeneratePdf(bill: BillModel) {
|
|||||||
body: [
|
body: [
|
||||||
...(bill.details.map(it=>{
|
...(bill.details.map(it=>{
|
||||||
return [
|
return [
|
||||||
`#${bill.id}${it.id?'-' + it.id:''}`,
|
`#${it.id}`,
|
||||||
dayjs(bill.paid_at).format('YYYY-MM-DD'),
|
dayjs(bill.paid_at).format('YYYY-MM-DD'),
|
||||||
it.bill_type,
|
it.bill_type,
|
||||||
`${bill.payment_channel}(${bill.payment_method})`,
|
`${bill.payment_channel}` + bill.payment_channel != bill.payment_method ? `(${bill.payment_method})` : '',
|
||||||
`${it.amount}`
|
`${it.amount}`
|
||||||
];
|
];
|
||||||
})),
|
})),
|
||||||
|
@ -38,13 +38,13 @@ export function request<T>(url: string, method: RequestMethod, data: AllType = n
|
|||||||
reject(new BizError("Service Internal Exception,Please Try Later!", res.status))
|
reject(new BizError("Service Internal Exception,Please Try Later!", res.status))
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (getOriginResult) {
|
||||||
|
resolve(res.data as unknown as T)
|
||||||
|
return;
|
||||||
|
}
|
||||||
// const
|
// const
|
||||||
const {code, message, data,request_id} = res.data
|
const {code, message, data,request_id} = res.data
|
||||||
if (code == 0) {
|
if (code == 0) {
|
||||||
if (getOriginResult) {
|
|
||||||
resolve(res.data as unknown as T)
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
resolve(data as unknown as T)
|
resolve(data as unknown as T)
|
||||||
} else {
|
} else {
|
||||||
reject(new BizError(message, code,request_id, data as unknown as AllType))
|
reject(new BizError(message, code,request_id, data as unknown as AllType))
|
||||||
|
26
src/types/bill.d.ts
vendored
26
src/types/bill.d.ts
vendored
@ -1,6 +1,8 @@
|
|||||||
|
|
||||||
declare type BaseDate = number | Date | string | null;
|
declare type BaseDate = number | Date | string | null;
|
||||||
declare type BillStatus = 'PAID' | 'CANCELLED' | 'PENDING'
|
declare type BillStatus = 'PAID' | 'CANCELLED' | 'PENDING'
|
||||||
|
declare type ConfirmStatus = 'UNCONFIRMED' | 'CONFIRMED'
|
||||||
|
declare type SortOrderType = 'ASC'|'DESC' | string;
|
||||||
|
|
||||||
// 现场支付账单数据
|
// 现场支付账单数据
|
||||||
declare type ManualCreateBillParam = {
|
declare type ManualCreateBillParam = {
|
||||||
@ -12,10 +14,9 @@ declare type BillDetail = {
|
|||||||
id: string | number;
|
id: string | number;
|
||||||
bill_id: string | number;
|
bill_id: string | number;
|
||||||
bill_type: string;
|
bill_type: string;
|
||||||
confirm_status?: number;
|
confirm_status: ConfirmStatus;
|
||||||
amount: decimal;
|
amount: decimal;
|
||||||
}
|
}
|
||||||
declare type SortOrderType = 'ASC'|'DESC' | string;
|
|
||||||
/**
|
/**
|
||||||
* 账单查询参数
|
* 账单查询参数
|
||||||
*/
|
*/
|
||||||
@ -31,6 +32,7 @@ declare type BillQueryParam = {
|
|||||||
start_date:string;
|
start_date:string;
|
||||||
end_date:string;
|
end_date:string;
|
||||||
department:string;
|
department:string;
|
||||||
|
confirm_status: ConfirmStatus;
|
||||||
sort_field:string;
|
sort_field:string;
|
||||||
sort_order:SortOrderType;
|
sort_order:SortOrderType;
|
||||||
}
|
}
|
||||||
@ -57,19 +59,22 @@ declare type BillModel = {
|
|||||||
service_charge?: number;
|
service_charge?: number;
|
||||||
payment_amount?: number;
|
payment_amount?: number;
|
||||||
actual_payment_amount?: null | number;
|
actual_payment_amount?: null | number;
|
||||||
payment_method?: null | string | number;
|
payment_method?: null | string;
|
||||||
currency?: string;
|
currency?: string;
|
||||||
payment_channel?: null | string | number;
|
payment_channel?: null | string ;
|
||||||
expiration_time?: BaseDate;
|
expiration_time?: BaseDate;
|
||||||
status: string;
|
status: string;
|
||||||
apply_status: string;
|
apply_status: string;
|
||||||
paid_area?: null | string | number;
|
paid_area?: null | string | number;
|
||||||
paid_at?:BaseDate;
|
paid_at?:BaseDate;
|
||||||
merchant_ref: null | string;
|
merchant_ref?: string;
|
||||||
payment_id?: null | string | number;
|
payment_id?: null | string | number;
|
||||||
create_at: BaseDate;
|
create_at: BaseDate;
|
||||||
update_at: BaseDate;
|
update_at: BaseDate;
|
||||||
|
student_first_name: string;
|
||||||
|
student_last_name: string;
|
||||||
|
remark: string;
|
||||||
|
confirm_status: ConfirmStatus;
|
||||||
details: BillDetail[]
|
details: BillDetail[]
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -91,3 +96,12 @@ declare type AsiaPayModel = {
|
|||||||
type ExternalCreateParamsType = {
|
type ExternalCreateParamsType = {
|
||||||
[key: string]: string | null | BillDetail[];
|
[key: string]: string | null | BillDetail[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type BillUpdateParams = {
|
||||||
|
payment_channel: string;
|
||||||
|
payment_method: string;
|
||||||
|
actual_payment_amount?: number | string;
|
||||||
|
remark?: string;
|
||||||
|
merchant_ref?: string;
|
||||||
|
payment_amount?: number | string;
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user