feat:bill manual payment completed
This commit is contained in:
parent
895c032532
commit
21ec84f68d
@ -132,7 +132,7 @@ body #root{
|
||||
}
|
||||
|
||||
// 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;
|
||||
border: 1px var(--semi-color-fill-2) solid;
|
||||
border-radius: var(--semi-border-radius-small);
|
||||
|
@ -41,6 +41,7 @@
|
||||
"reconciliation_status_pending": "UNCHECKED",
|
||||
"reconciliation_status_submitted": "CHECKED",
|
||||
"require_student_number": "Search Student Number",
|
||||
"set_bill_paid": "Set Bill Paid",
|
||||
"sort_asc": "ASC",
|
||||
"sort_desc": "DESC",
|
||||
"title_actual_payment_amount": "Actually Paid",
|
||||
@ -53,11 +54,13 @@
|
||||
"title_operate": "Operation",
|
||||
"title_paid_at": "Transaction Date",
|
||||
"title_pay_amount": "Pay Amount",
|
||||
"title_pay_channel": "Payment Channel",
|
||||
"title_pay_method": "Pay Method",
|
||||
"title_pay_sort": "Sort By",
|
||||
"title_program_id": "Program ID",
|
||||
"title_program_name": "Program",
|
||||
"title_reconciliation_status": "Reconciliation",
|
||||
"title_remark": "Remark",
|
||||
"title_semester": "Semester",
|
||||
"title_service_charge": "Service Charge",
|
||||
"title_student_name": "Student Name",
|
||||
|
@ -41,6 +41,7 @@
|
||||
"reconciliation_status_pending": "未对账",
|
||||
"reconciliation_status_submitted": "已对账",
|
||||
"require_student_number": "请输入查询学号",
|
||||
"set_bill_paid": "设置账单支付完成",
|
||||
"sort_asc": "升序",
|
||||
"sort_desc": "降序",
|
||||
"title_actual_payment_amount": "实付金额",
|
||||
@ -53,11 +54,13 @@
|
||||
"title_operate": "操作",
|
||||
"title_paid_at": "支付时间",
|
||||
"title_pay_amount": "应付金额",
|
||||
"title_pay_channel": "支付渠道",
|
||||
"title_pay_method": "支付方式",
|
||||
"title_pay_sort": "排序方式",
|
||||
"title_program_id": "专业ID",
|
||||
"title_program_name": "就读专业",
|
||||
"title_reconciliation_status": "对账状态",
|
||||
"title_remark": "备注",
|
||||
"title_semester": "学期",
|
||||
"title_service_charge": "手续费",
|
||||
"title_student_name": "学生姓名",
|
||||
|
@ -41,6 +41,7 @@
|
||||
"reconciliation_status_pending": "未對帳",
|
||||
"reconciliation_status_submitted": "已對帳",
|
||||
"require_student_number": "請輸入查詢學號",
|
||||
"set_bill_paid": "設定帳單支付完成",
|
||||
"sort_asc": "升序",
|
||||
"sort_desc": "降序",
|
||||
"title_actual_payment_amount": "實付金額",
|
||||
@ -53,11 +54,13 @@
|
||||
"title_operate": "操作",
|
||||
"title_paid_at": "付款時間",
|
||||
"title_pay_amount": "應付金額",
|
||||
"title_pay_channel": "支付渠道",
|
||||
"title_pay_method": "付款方式",
|
||||
"title_pay_sort": "排序方式",
|
||||
"title_program_id": "專業ID",
|
||||
"title_program_name": "就讀專業",
|
||||
"title_reconciliation_status": "對帳狀態",
|
||||
"title_remark": "備註",
|
||||
"title_semester": "學期",
|
||||
"title_service_charge": "手續費",
|
||||
"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 {BillStatus, BizError} from "@/service/types.ts";
|
||||
import {useDownloadReceiptPDF} from "@/service/generate-pdf.ts";
|
||||
import useAuth from "@/hooks/useAuth.ts";
|
||||
import {BillDetailItems} from "@/components/bill";
|
||||
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 }) => {
|
||||
@ -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) => {
|
||||
|
||||
return (<div className={'table-operation-render'}>
|
||||
@ -128,21 +107,15 @@ const BillQuery = () => {
|
||||
>
|
||||
{showBill && <BillDetail bill={showBill} onCancel={() => setShowBill(undefined)}/>}
|
||||
</Modal>
|
||||
<Modal
|
||||
title="Notice"
|
||||
visible={!!state.updateBill}
|
||||
closeOnEsc={true}
|
||||
onCancel={() => {
|
||||
setState({updateBill: undefined, updateLoading: false})
|
||||
<BillPaidModal
|
||||
open={!!state.updateBill}
|
||||
onCancel={()=>setState({updateBill:undefined})}
|
||||
bill={state.updateBill!}
|
||||
onConfirm={()=>{
|
||||
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
|
||||
title="Confirm Bill Type"
|
||||
visible={!!state.confirmBill}
|
||||
@ -166,9 +139,8 @@ const BillQuery = () => {
|
||||
</div>
|
||||
</Space>
|
||||
<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>}
|
||||
|
||||
</div>
|
||||
</div>))
|
||||
}
|
||||
|
@ -10,98 +10,102 @@ import useAuth from "@/hooks/useAuth.ts";
|
||||
import {BizError} from "@/service/types.ts";
|
||||
|
||||
const BillReconciliation = () => {
|
||||
const {t} = useTranslation()
|
||||
const {user} = useAuth();
|
||||
const [queryParams, setBillQueryParams] = useState<BillQueryParams>({
|
||||
apply_status:'UNCHECKED'
|
||||
});
|
||||
const {data, loading, refresh} = useRequest(() => billList({
|
||||
...queryParams,
|
||||
status: 'PAID',
|
||||
department: user?.department == 'RO' ? 'RO' : 'FO',
|
||||
}), {
|
||||
refreshDeps: [queryParams],
|
||||
onError: (e:Error) => {
|
||||
Toast.error({
|
||||
content: `${t('base.query_bill')}:${e.message}`,
|
||||
duration: 3
|
||||
})
|
||||
}
|
||||
})
|
||||
const {t} = useTranslation()
|
||||
const {user} = useAuth();
|
||||
const [queryParams, setBillQueryParams] = useState<BillQueryParams>({
|
||||
apply_status: 'UNCHECKED'
|
||||
});
|
||||
const {data, loading, refresh} = useRequest(() => billList({
|
||||
...queryParams,
|
||||
status: 'PAID',
|
||||
confirm_status: 'CONFIRMED',
|
||||
department: user?.department == 'RO' ? 'RO' : 'FO',
|
||||
}), {
|
||||
refreshDeps: [queryParams],
|
||||
onError: (e: Error) => {
|
||||
Toast.error({
|
||||
content: `${t('base.query_bill')}:${e.message}`,
|
||||
duration: 3
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
const [selectKeys, setSelectedKeys] = useState<(string | number)[]>([])
|
||||
const [state,setState] = useSetState({
|
||||
checkingId: -1
|
||||
})
|
||||
const confirmBill = (records: number[]) => {
|
||||
if (records.length == 0) {
|
||||
Notification.error({title: 'Notice', content: t('bill.confirm_select_empty')})
|
||||
return
|
||||
}
|
||||
setState({checkingId: records.length > 1 ? 0 : records[0] })
|
||||
confirmBills(records).then(() => {
|
||||
Notification.success({title: 'Notice', content: t('bill.confirm_success')})
|
||||
refresh()
|
||||
}).catch((e:BizError) => {
|
||||
Toast.error({
|
||||
content: `${t('base.operate_fail')}:${e.message}`,
|
||||
duration: 3
|
||||
})
|
||||
}).finally(() => {setState({checkingId: -1})})
|
||||
}
|
||||
const operation = (_record: BillModel) => {
|
||||
return (<Space>
|
||||
<Popconfirm
|
||||
title={'Notice'}
|
||||
content={t('bill.confirm_confirm_title')}
|
||||
onConfirm={() => confirmBill([_record.id])}
|
||||
>
|
||||
<Button loading={state.checkingId == _record.id} size={'small'} theme={'solid'}
|
||||
type={'primary'}>{t('bill.confirm')}</Button>
|
||||
</Popconfirm>
|
||||
</Space>)
|
||||
}
|
||||
const [selectKeys, setSelectedKeys] = useState<(string | number)[]>([])
|
||||
const [state, setState] = useSetState({
|
||||
checkingId: -1
|
||||
})
|
||||
const confirmBill = (records: number[]) => {
|
||||
if (records.length == 0) {
|
||||
Notification.error({title: 'Notice', content: t('bill.confirm_select_empty')})
|
||||
return
|
||||
}
|
||||
setState({checkingId: records.length > 1 ? 0 : records[0]})
|
||||
confirmBills(records).then(() => {
|
||||
Notification.success({title: 'Notice', content: t('bill.confirm_success')})
|
||||
refresh()
|
||||
}).catch((e: BizError) => {
|
||||
Toast.error({
|
||||
content: `${t('base.operate_fail')}:${e.message}`,
|
||||
duration: 3
|
||||
})
|
||||
}).finally(() => {
|
||||
setState({checkingId: -1})
|
||||
})
|
||||
}
|
||||
const operation = (_record: BillModel) => {
|
||||
return (<Space>
|
||||
<Popconfirm
|
||||
title={'Notice'}
|
||||
content={t('bill.confirm_confirm_title')}
|
||||
onConfirm={() => confirmBill([_record.id])}
|
||||
>
|
||||
<Button
|
||||
loading={state.checkingId == _record.id} size={'small'} theme={'solid'}
|
||||
type={'primary'}>{t('bill.confirm')}</Button>
|
||||
</Popconfirm>
|
||||
</Space>)
|
||||
}
|
||||
|
||||
return (<div>
|
||||
return (<div>
|
||||
|
||||
<SearchForm
|
||||
searchHeader={(
|
||||
<Tabs className={'no-border'} onChange={(apply_status) => setBillQueryParams({
|
||||
apply_status,
|
||||
status: 'PAID'
|
||||
})}>
|
||||
<TabPane tab={<span>{t('bill.reconciliation_status_pending')}</span>} itemKey="UNCHECKED"/>
|
||||
<TabPane tab={<span>{t('bill.reconciliation_status_submitted')}</span>} itemKey="CHECKED"/>
|
||||
</Tabs>
|
||||
)}
|
||||
loading={loading}
|
||||
onSearch={(params) => {
|
||||
setBillQueryParams({...params, apply_status: queryParams.apply_status})
|
||||
}}
|
||||
/>
|
||||
<BillList
|
||||
source={data} type={'reconciliation'}
|
||||
operationRender={queryParams.apply_status == 'CHECKED' ? undefined : operation}
|
||||
onRowSelection={queryParams.apply_status == 'CHECKED' ? undefined : (keys: (number | string)[]) => {
|
||||
setSelectedKeys(keys);
|
||||
}}
|
||||
loading={loading}
|
||||
onPageChange={(page_number) => setBillQueryParams({
|
||||
...queryParams,
|
||||
page_number
|
||||
})}
|
||||
tableFooter={queryParams.apply_status != 'CHECKED' && selectKeys?.length > 0 && (
|
||||
<Popconfirm
|
||||
title={'Notice'}
|
||||
content={`${t('bill.cancel_confirm_bills')}?`}
|
||||
onConfirm={() => confirmBill(selectKeys as number[])}
|
||||
>
|
||||
<Button style={{marginRight: 10}}>
|
||||
{t('bill.confirm_batch')}
|
||||
</Button>
|
||||
</Popconfirm>
|
||||
)}
|
||||
/>
|
||||
</div>)
|
||||
<SearchForm
|
||||
searchHeader={(
|
||||
<Tabs className={'no-border'} onChange={(apply_status) => setBillQueryParams({
|
||||
apply_status,
|
||||
status: 'PAID'
|
||||
})}>
|
||||
<TabPane tab={<span>{t('bill.reconciliation_status_pending')}</span>} itemKey="UNCHECKED"/>
|
||||
<TabPane tab={<span>{t('bill.reconciliation_status_submitted')}</span>} itemKey="CHECKED"/>
|
||||
</Tabs>
|
||||
)}
|
||||
loading={loading}
|
||||
onSearch={(params) => {
|
||||
setBillQueryParams({...params, apply_status: queryParams.apply_status})
|
||||
}}
|
||||
/>
|
||||
<BillList
|
||||
source={data} type={'reconciliation'}
|
||||
operationRender={queryParams.apply_status == 'CHECKED' ? undefined : operation}
|
||||
onRowSelection={queryParams.apply_status == 'CHECKED' ? undefined : (keys: (number | string)[]) => {
|
||||
setSelectedKeys(keys);
|
||||
}}
|
||||
loading={loading}
|
||||
onPageChange={(page_number) => setBillQueryParams({
|
||||
...queryParams,
|
||||
page_number
|
||||
})}
|
||||
tableFooter={queryParams.apply_status != 'CHECKED' && selectKeys?.length > 0 && (
|
||||
<Popconfirm
|
||||
title={'Notice'}
|
||||
content={`${t('bill.cancel_confirm_bills')}?`}
|
||||
onConfirm={() => confirmBill(selectKeys as number[])}
|
||||
>
|
||||
<Button style={{marginRight: 10}}>
|
||||
{t('bill.confirm_batch')}
|
||||
</Button>
|
||||
</Popconfirm>
|
||||
)}
|
||||
/>
|
||||
</div>)
|
||||
}
|
||||
export default BillReconciliation
|
@ -1,4 +1,5 @@
|
||||
import {get, post, put} from "@/service/request.ts";
|
||||
import dayjs from "dayjs";
|
||||
|
||||
export type BillQueryResult = {
|
||||
result: BillModel[];
|
||||
@ -62,4 +63,58 @@ export function updateBillPaymentSuccess(bill_id: number, merchant_ref: string,
|
||||
|
||||
export function createExternalBill(params: ExternalCreateParamsType) {
|
||||
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');
|
||||
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: 'Print Date:', content: dayjs().format('YYYY-MM-DD')}, 48, "right")
|
||||
|
||||
@ -58,10 +58,10 @@ export function GeneratePdf(bill: BillModel) {
|
||||
body: [
|
||||
...(bill.details.map(it=>{
|
||||
return [
|
||||
`#${bill.id}${it.id?'-' + it.id:''}`,
|
||||
`#${it.id}`,
|
||||
dayjs(bill.paid_at).format('YYYY-MM-DD'),
|
||||
it.bill_type,
|
||||
`${bill.payment_channel}(${bill.payment_method})`,
|
||||
`${bill.payment_channel}` + bill.payment_channel != bill.payment_method ? `(${bill.payment_method})` : '',
|
||||
`${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))
|
||||
return;
|
||||
}
|
||||
if (getOriginResult) {
|
||||
resolve(res.data as unknown as T)
|
||||
return;
|
||||
}
|
||||
// const
|
||||
const {code, message, data,request_id} = res.data
|
||||
if (code == 0) {
|
||||
if (getOriginResult) {
|
||||
resolve(res.data as unknown as T)
|
||||
return;
|
||||
}
|
||||
resolve(data as unknown as T)
|
||||
} else {
|
||||
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 BillStatus = 'PAID' | 'CANCELLED' | 'PENDING'
|
||||
declare type ConfirmStatus = 'UNCONFIRMED' | 'CONFIRMED'
|
||||
declare type SortOrderType = 'ASC'|'DESC' | string;
|
||||
|
||||
// 现场支付账单数据
|
||||
declare type ManualCreateBillParam = {
|
||||
@ -12,10 +14,9 @@ declare type BillDetail = {
|
||||
id: string | number;
|
||||
bill_id: string | number;
|
||||
bill_type: string;
|
||||
confirm_status?: number;
|
||||
confirm_status: ConfirmStatus;
|
||||
amount: decimal;
|
||||
}
|
||||
declare type SortOrderType = 'ASC'|'DESC' | string;
|
||||
/**
|
||||
* 账单查询参数
|
||||
*/
|
||||
@ -31,6 +32,7 @@ declare type BillQueryParam = {
|
||||
start_date:string;
|
||||
end_date:string;
|
||||
department:string;
|
||||
confirm_status: ConfirmStatus;
|
||||
sort_field:string;
|
||||
sort_order:SortOrderType;
|
||||
}
|
||||
@ -57,19 +59,22 @@ declare type BillModel = {
|
||||
service_charge?: number;
|
||||
payment_amount?: number;
|
||||
actual_payment_amount?: null | number;
|
||||
payment_method?: null | string | number;
|
||||
payment_method?: null | string;
|
||||
currency?: string;
|
||||
payment_channel?: null | string | number;
|
||||
payment_channel?: null | string ;
|
||||
expiration_time?: BaseDate;
|
||||
status: string;
|
||||
apply_status: string;
|
||||
paid_area?: null | string | number;
|
||||
paid_at?:BaseDate;
|
||||
merchant_ref: null | string;
|
||||
merchant_ref?: string;
|
||||
payment_id?: null | string | number;
|
||||
create_at: BaseDate;
|
||||
update_at: BaseDate;
|
||||
|
||||
student_first_name: string;
|
||||
student_last_name: string;
|
||||
remark: string;
|
||||
confirm_status: ConfirmStatus;
|
||||
details: BillDetail[]
|
||||
}
|
||||
|
||||
@ -91,3 +96,12 @@ declare type AsiaPayModel = {
|
||||
type ExternalCreateParamsType = {
|
||||
[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