Add payment management features to Finance dashboard, including AuthorisePayment, DeclinePayment, and CancelPayment components for handling payment actions. Update PaymentInfo to integrate new modals for these actions and enhance Payment model to support new states and attributes, improving overall payment processing functionality.
Some checks failed
farmcontrol/farmcontrol-ui/pipeline/head There was a failure building this commit
Some checks failed
farmcontrol/farmcontrol-ui/pipeline/head There was a failure building this commit
This commit is contained in:
parent
0406c0d0e0
commit
457c427928
@ -0,0 +1,46 @@
|
|||||||
|
import { useState, useContext } from 'react'
|
||||||
|
import PropTypes from 'prop-types'
|
||||||
|
import { ApiServerContext } from '../../context/ApiServerContext'
|
||||||
|
import { message } from 'antd'
|
||||||
|
import MessageDialogView from '../../common/MessageDialogView.jsx'
|
||||||
|
|
||||||
|
const AuthorisePayment = ({ onOk, objectData }) => {
|
||||||
|
const [authoriseLoading, setAuthoriseLoading] = useState(false)
|
||||||
|
const { sendObjectFunction } = useContext(ApiServerContext)
|
||||||
|
|
||||||
|
const handleAuthorise = async () => {
|
||||||
|
setAuthoriseLoading(true)
|
||||||
|
try {
|
||||||
|
const result = await sendObjectFunction(
|
||||||
|
objectData._id,
|
||||||
|
'Payment',
|
||||||
|
'authorise'
|
||||||
|
)
|
||||||
|
if (result) {
|
||||||
|
message.success('Payment authorised successfully')
|
||||||
|
onOk(result)
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error authorising payment:', error)
|
||||||
|
} finally {
|
||||||
|
setAuthoriseLoading(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<MessageDialogView
|
||||||
|
title={'Are you sure you want to authorise this payment?'}
|
||||||
|
description={`Authorising payment ${objectData?.name || objectData?._reference || objectData?._id} will update its status to authorised.`}
|
||||||
|
onOk={handleAuthorise}
|
||||||
|
okText='Authorise'
|
||||||
|
okLoading={authoriseLoading}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
AuthorisePayment.propTypes = {
|
||||||
|
onOk: PropTypes.func.isRequired,
|
||||||
|
objectData: PropTypes.object
|
||||||
|
}
|
||||||
|
|
||||||
|
export default AuthorisePayment
|
||||||
46
src/components/Dashboard/Finance/Payments/CancelPayment.jsx
Normal file
46
src/components/Dashboard/Finance/Payments/CancelPayment.jsx
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
import { useState, useContext } from 'react'
|
||||||
|
import PropTypes from 'prop-types'
|
||||||
|
import { ApiServerContext } from '../../context/ApiServerContext'
|
||||||
|
import { message } from 'antd'
|
||||||
|
import MessageDialogView from '../../common/MessageDialogView.jsx'
|
||||||
|
|
||||||
|
const CancelPayment = ({ onOk, objectData }) => {
|
||||||
|
const [cancelLoading, setCancelLoading] = useState(false)
|
||||||
|
const { sendObjectFunction } = useContext(ApiServerContext)
|
||||||
|
|
||||||
|
const handleCancel = async () => {
|
||||||
|
setCancelLoading(true)
|
||||||
|
try {
|
||||||
|
const result = await sendObjectFunction(
|
||||||
|
objectData._id,
|
||||||
|
'Payment',
|
||||||
|
'cancel'
|
||||||
|
)
|
||||||
|
if (result) {
|
||||||
|
message.success('Payment cancelled successfully')
|
||||||
|
onOk(result)
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error cancelling payment:', error)
|
||||||
|
} finally {
|
||||||
|
setCancelLoading(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<MessageDialogView
|
||||||
|
title={'Are you sure you want to cancel this payment?'}
|
||||||
|
description={`Cancelling payment ${objectData?.name || objectData?._reference || objectData?._id} will update its status to cancelled.`}
|
||||||
|
onOk={handleCancel}
|
||||||
|
okText='Cancel'
|
||||||
|
okLoading={cancelLoading}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
CancelPayment.propTypes = {
|
||||||
|
onOk: PropTypes.func.isRequired,
|
||||||
|
objectData: PropTypes.object
|
||||||
|
}
|
||||||
|
|
||||||
|
export default CancelPayment
|
||||||
46
src/components/Dashboard/Finance/Payments/DeclinePayment.jsx
Normal file
46
src/components/Dashboard/Finance/Payments/DeclinePayment.jsx
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
import { useState, useContext } from 'react'
|
||||||
|
import PropTypes from 'prop-types'
|
||||||
|
import { ApiServerContext } from '../../context/ApiServerContext'
|
||||||
|
import { message } from 'antd'
|
||||||
|
import MessageDialogView from '../../common/MessageDialogView.jsx'
|
||||||
|
|
||||||
|
const DeclinePayment = ({ onOk, objectData }) => {
|
||||||
|
const [declineLoading, setDeclineLoading] = useState(false)
|
||||||
|
const { sendObjectFunction } = useContext(ApiServerContext)
|
||||||
|
|
||||||
|
const handleDecline = async () => {
|
||||||
|
setDeclineLoading(true)
|
||||||
|
try {
|
||||||
|
const result = await sendObjectFunction(
|
||||||
|
objectData._id,
|
||||||
|
'Payment',
|
||||||
|
'decline'
|
||||||
|
)
|
||||||
|
if (result) {
|
||||||
|
message.success('Payment declined successfully')
|
||||||
|
onOk(result)
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error declining payment:', error)
|
||||||
|
} finally {
|
||||||
|
setDeclineLoading(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<MessageDialogView
|
||||||
|
title={'Are you sure you want to decline this payment?'}
|
||||||
|
description={`Declining payment ${objectData?.name || objectData?._reference || objectData?._id} will update its status to declined.`}
|
||||||
|
onOk={handleDecline}
|
||||||
|
okText='Decline'
|
||||||
|
okLoading={declineLoading}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
DeclinePayment.propTypes = {
|
||||||
|
onOk: PropTypes.func.isRequired,
|
||||||
|
objectData: PropTypes.object
|
||||||
|
}
|
||||||
|
|
||||||
|
export default DeclinePayment
|
||||||
@ -53,6 +53,8 @@ const NewPayment = ({ onOk, reset, defaultValues }) => {
|
|||||||
updatedAt: false,
|
updatedAt: false,
|
||||||
_reference: false,
|
_reference: false,
|
||||||
postedAt: false,
|
postedAt: false,
|
||||||
|
authorisedAt: false,
|
||||||
|
declinedAt: false,
|
||||||
cancelledAt: false
|
cancelledAt: false
|
||||||
}}
|
}}
|
||||||
isEditing={false}
|
isEditing={false}
|
||||||
|
|||||||
@ -24,6 +24,9 @@ import UserNotifierToggle from '../../common/UserNotifierToggle.jsx'
|
|||||||
import ScrollBox from '../../common/ScrollBox.jsx'
|
import ScrollBox from '../../common/ScrollBox.jsx'
|
||||||
import { getModelByName } from '../../../../database/ObjectModels.js'
|
import { getModelByName } from '../../../../database/ObjectModels.js'
|
||||||
import PostPayment from './PostPayment.jsx'
|
import PostPayment from './PostPayment.jsx'
|
||||||
|
import AuthorisePayment from './AuthorisePayment.jsx'
|
||||||
|
import DeclinePayment from './DeclinePayment.jsx'
|
||||||
|
import CancelPayment from './CancelPayment.jsx'
|
||||||
|
|
||||||
const log = loglevel.getLogger('PaymentInfo')
|
const log = loglevel.getLogger('PaymentInfo')
|
||||||
log.setLevel(config.logLevel)
|
log.setLevel(config.logLevel)
|
||||||
@ -48,6 +51,9 @@ const PaymentInfo = () => {
|
|||||||
objectData: {}
|
objectData: {}
|
||||||
})
|
})
|
||||||
const [postPaymentOpen, setPostPaymentOpen] = useState(false)
|
const [postPaymentOpen, setPostPaymentOpen] = useState(false)
|
||||||
|
const [authorisePaymentOpen, setAuthorisePaymentOpen] = useState(false)
|
||||||
|
const [declinePaymentOpen, setDeclinePaymentOpen] = useState(false)
|
||||||
|
const [cancelPaymentOpen, setCancelPaymentOpen] = useState(false)
|
||||||
|
|
||||||
const actions = {
|
const actions = {
|
||||||
edit: () => {
|
edit: () => {
|
||||||
@ -69,6 +75,18 @@ const PaymentInfo = () => {
|
|||||||
post: () => {
|
post: () => {
|
||||||
setPostPaymentOpen(true)
|
setPostPaymentOpen(true)
|
||||||
return true
|
return true
|
||||||
|
},
|
||||||
|
authorise: () => {
|
||||||
|
setAuthorisePaymentOpen(true)
|
||||||
|
return true
|
||||||
|
},
|
||||||
|
decline: () => {
|
||||||
|
setDeclinePaymentOpen(true)
|
||||||
|
return true
|
||||||
|
},
|
||||||
|
cancel: () => {
|
||||||
|
setCancelPaymentOpen(true)
|
||||||
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -234,6 +252,60 @@ const PaymentInfo = () => {
|
|||||||
objectData={objectFormState.objectData}
|
objectData={objectFormState.objectData}
|
||||||
/>
|
/>
|
||||||
</Modal>
|
</Modal>
|
||||||
|
<Modal
|
||||||
|
open={authorisePaymentOpen}
|
||||||
|
onCancel={() => {
|
||||||
|
setAuthorisePaymentOpen(false)
|
||||||
|
}}
|
||||||
|
width={515}
|
||||||
|
footer={null}
|
||||||
|
destroyOnHidden={true}
|
||||||
|
centered={true}
|
||||||
|
>
|
||||||
|
<AuthorisePayment
|
||||||
|
onOk={() => {
|
||||||
|
setAuthorisePaymentOpen(false)
|
||||||
|
objectFormRef?.current.handleFetchObject()
|
||||||
|
}}
|
||||||
|
objectData={objectFormState.objectData}
|
||||||
|
/>
|
||||||
|
</Modal>
|
||||||
|
<Modal
|
||||||
|
open={declinePaymentOpen}
|
||||||
|
onCancel={() => {
|
||||||
|
setDeclinePaymentOpen(false)
|
||||||
|
}}
|
||||||
|
width={515}
|
||||||
|
footer={null}
|
||||||
|
destroyOnHidden={true}
|
||||||
|
centered={true}
|
||||||
|
>
|
||||||
|
<DeclinePayment
|
||||||
|
onOk={() => {
|
||||||
|
setDeclinePaymentOpen(false)
|
||||||
|
objectFormRef?.current.handleFetchObject()
|
||||||
|
}}
|
||||||
|
objectData={objectFormState.objectData}
|
||||||
|
/>
|
||||||
|
</Modal>
|
||||||
|
<Modal
|
||||||
|
open={cancelPaymentOpen}
|
||||||
|
onCancel={() => {
|
||||||
|
setCancelPaymentOpen(false)
|
||||||
|
}}
|
||||||
|
width={515}
|
||||||
|
footer={null}
|
||||||
|
destroyOnHidden={true}
|
||||||
|
centered={true}
|
||||||
|
>
|
||||||
|
<CancelPayment
|
||||||
|
onOk={() => {
|
||||||
|
setCancelPaymentOpen(false)
|
||||||
|
objectFormRef?.current.handleFetchObject()
|
||||||
|
}}
|
||||||
|
objectData={objectFormState.objectData}
|
||||||
|
/>
|
||||||
|
</Modal>
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -140,6 +140,14 @@ const StateTag = ({ state, showBadge = true, style = {} }) => {
|
|||||||
status = 'magenta'
|
status = 'magenta'
|
||||||
text = 'Posted'
|
text = 'Posted'
|
||||||
break
|
break
|
||||||
|
case 'authorised':
|
||||||
|
status = 'success'
|
||||||
|
text = 'Authorised'
|
||||||
|
break
|
||||||
|
case 'declined':
|
||||||
|
status = 'error'
|
||||||
|
text = 'Declined'
|
||||||
|
break
|
||||||
case 'received':
|
case 'received':
|
||||||
status = 'success'
|
status = 'success'
|
||||||
text = 'Received'
|
text = 'Received'
|
||||||
|
|||||||
@ -82,6 +82,35 @@ export const Payment = {
|
|||||||
return objectData?.state?.type == 'draft'
|
return objectData?.state?.type == 'draft'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: 'authorise',
|
||||||
|
label: 'Authorise',
|
||||||
|
type: 'button',
|
||||||
|
icon: CheckIcon,
|
||||||
|
url: (_id) =>
|
||||||
|
`/dashboard/finance/payments/info?paymentId=${_id}&action=authorise`,
|
||||||
|
disabled: (objectData) => {
|
||||||
|
return objectData?.state?.type != 'posted'
|
||||||
|
},
|
||||||
|
visible: (objectData) => {
|
||||||
|
return objectData?.state?.type == 'posted'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'decline',
|
||||||
|
label: 'Decline',
|
||||||
|
type: 'button',
|
||||||
|
icon: XMarkIcon,
|
||||||
|
danger: true,
|
||||||
|
url: (_id) =>
|
||||||
|
`/dashboard/finance/payments/info?paymentId=${_id}&action=decline`,
|
||||||
|
disabled: (objectData) => {
|
||||||
|
return objectData?.state?.type != 'posted'
|
||||||
|
},
|
||||||
|
visible: (objectData) => {
|
||||||
|
return objectData?.state?.type == 'posted'
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: 'cancel',
|
name: 'cancel',
|
||||||
label: 'Cancel',
|
label: 'Cancel',
|
||||||
@ -91,13 +120,10 @@ export const Payment = {
|
|||||||
url: (_id) =>
|
url: (_id) =>
|
||||||
`/dashboard/finance/payments/info?paymentId=${_id}&action=cancel`,
|
`/dashboard/finance/payments/info?paymentId=${_id}&action=cancel`,
|
||||||
disabled: (objectData) => {
|
disabled: (objectData) => {
|
||||||
return objectData?.state?.type == 'cancelled'
|
return objectData?.state?.type != 'posted'
|
||||||
},
|
},
|
||||||
visible: (objectData) => {
|
visible: (objectData) => {
|
||||||
return (
|
return objectData?.state?.type == 'posted'
|
||||||
objectData?.state?.type == 'draft' ||
|
|
||||||
objectData?.state?.type == 'posted'
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
@ -197,6 +223,20 @@ export const Payment = {
|
|||||||
readOnly: true,
|
readOnly: true,
|
||||||
columnWidth: 175
|
columnWidth: 175
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: 'authorisedAt',
|
||||||
|
label: 'Authorised At',
|
||||||
|
type: 'dateTime',
|
||||||
|
readOnly: true,
|
||||||
|
columnWidth: 175
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'declinedAt',
|
||||||
|
label: 'Declined At',
|
||||||
|
type: 'dateTime',
|
||||||
|
readOnly: true,
|
||||||
|
columnWidth: 175
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: 'cancelledAt',
|
name: 'cancelledAt',
|
||||||
label: 'Cancelled At',
|
label: 'Cancelled At',
|
||||||
@ -256,6 +296,34 @@ export const Payment = {
|
|||||||
prefix: '£',
|
prefix: '£',
|
||||||
roundNumber: 2,
|
roundNumber: 2,
|
||||||
color: 'cyan'
|
color: 'cyan'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'authorised.authorisedCount.count',
|
||||||
|
label: 'Authorised',
|
||||||
|
type: 'number',
|
||||||
|
color: 'green'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'authorised.authorisedAmount.sum',
|
||||||
|
label: 'Authorised Amount',
|
||||||
|
type: 'number',
|
||||||
|
prefix: '£',
|
||||||
|
roundNumber: 2,
|
||||||
|
color: 'green'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'declined.declinedCount.count',
|
||||||
|
label: 'Declined',
|
||||||
|
type: 'number',
|
||||||
|
color: 'red'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'declined.declinedAmount.sum',
|
||||||
|
label: 'Declined Amount',
|
||||||
|
type: 'number',
|
||||||
|
prefix: '£',
|
||||||
|
roundNumber: 2,
|
||||||
|
color: 'red'
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user