fix: cancel cashout txs

This commit is contained in:
José Oliveira 2021-08-13 14:16:21 +01:00 committed by Josh Harvey
parent e5ab87c2a5
commit e952682917
4 changed files with 70 additions and 29 deletions

View file

@ -1,25 +0,0 @@
#!/usr/bin/env node
const uuid = require('@fczbkk/uuid4')
const tx = require('../lib/cash-out/cash-out-tx.js')
const argv = process.argv.slice(2)
if (argv.length !== 1) {
console.log('Usage: lamassu-cancel <tx-id>')
console.log('Cancels the cash out transaction with given tx-id so it cannot be dispensed.')
process.exit(1)
}
const txId = argv[0]
if (!uuid.validate(txId)) {
console.log('tx-id must be valid uuid. e.g.: f8093ded-c542-4916-8ab5-6ebeceb287c1')
process.exit(2)
}
tx.cancel(txId)
.then(() => console.log('Success.'))
.catch(err => console.log(`Error: ${err.message}`))
.then(() => process.exit(0))

View file

@ -19,6 +19,7 @@ const bills = require('../bills')
const anonymous = require('../../constants').anonymousCustomer
const serverVersion = require('../../../package.json').version
const cashOutTx = require('../../cash-out/cash-out-tx')
const transactions = require('../transactions')
const funding = require('../funding')
const forex = require('../../forex')
@ -344,6 +345,7 @@ const typeDefs = gql`
deletePromoCode(codeId: ID!): PromoCode
toggleClearNotification(id: ID!, read: Boolean!): Notification
clearAllNotifications: Notification
cancelCashOutTransaction(id: ID): Transaction
}
`
@ -440,7 +442,8 @@ const resolvers = {
createPromoCode: (...[, { code, discount }]) => promoCodeManager.createPromoCode(code, discount),
deletePromoCode: (...[, { codeId }]) => promoCodeManager.deletePromoCode(codeId),
toggleClearNotification: (...[, { id, read }]) => notifierQueries.setRead(id, read),
clearAllNotifications: () => notifierQueries.markAllAsRead()
clearAllNotifications: () => notifierQueries.markAllAsRead(),
cancelCashOutTransaction: (...[, { id }]) => cashOutTx.cancel(id)
}
}

View file

@ -1,10 +1,13 @@
import { useMutation } from '@apollo/react-hooks'
import { makeStyles, Box } from '@material-ui/core'
import BigNumber from 'bignumber.js'
import gql from 'graphql-tag'
import moment from 'moment'
import React, { memo } from 'react'
import React, { memo, useState } from 'react'
import { ConfirmDialog } from 'src/components/ConfirmDialog'
import { HoverableTooltip } from 'src/components/Tooltip'
import { IDButton } from 'src/components/buttons'
import { IDButton, ActionButton } from 'src/components/buttons'
import { P, Label1 } from 'src/components/typography'
import { ReactComponent as CardIdInverseIcon } from 'src/styling/icons/ID/card/white.svg'
import { ReactComponent as CardIdIcon } from 'src/styling/icons/ID/card/zodiac.svg'
@ -12,6 +15,8 @@ import { ReactComponent as PhoneIdInverseIcon } from 'src/styling/icons/ID/phone
import { ReactComponent as PhoneIdIcon } from 'src/styling/icons/ID/phone/zodiac.svg'
import { ReactComponent as CamIdInverseIcon } from 'src/styling/icons/ID/photo/white.svg'
import { ReactComponent as CamIdIcon } from 'src/styling/icons/ID/photo/zodiac.svg'
import { ReactComponent as CancelInverseIcon } from 'src/styling/icons/button/cancel/white.svg'
import { ReactComponent as CancelIcon } from 'src/styling/icons/button/cancel/zodiac.svg'
import { ReactComponent as TxInIcon } from 'src/styling/icons/direction/cash-in.svg'
import { ReactComponent as TxOutIcon } from 'src/styling/icons/direction/cash-out.svg'
import { URI } from 'src/utils/apollo'
@ -24,6 +29,14 @@ import { getStatus, getStatusDetails } from './helper'
const useStyles = makeStyles(styles)
const CANCEL_TRANSACTION = gql`
mutation cancelCashOutTransaction($id: ID!) {
cancelCashOutTransaction(id: $id) {
id
}
}
`
const formatAddress = (cryptoCode = '', address = '') =>
formatCryptoAddress(cryptoCode, address).replace(/(.{5})/g, '$1 ')
@ -34,6 +47,13 @@ const Label = ({ children }) => {
const DetailsRow = ({ it: tx }) => {
const classes = useStyles()
const [action, setAction] = useState({ command: null })
const [errorMessage, setErrorMessage] = useState('')
const [cancelCashOutTransaction] = useMutation(CANCEL_TRANSACTION, {
onError: ({ message }) => setErrorMessage(message ?? 'An error occurred.'),
refetchQueries: () => ['transactions']
})
const fiat = Number.parseFloat(tx.fiat)
const crypto = toUnit(new BigNumber(tx.cryptoAtoms), tx.cryptoCode)
@ -197,7 +217,7 @@ const DetailsRow = ({ it: tx }) => {
</div>
</div>
<div className={classes.lastRow}>
<div>
<div className={classes.status}>
{getStatusDetails(tx) ? (
<HoverableTooltip parentElements={errorElements} width={200}>
<P>{getStatusDetails(tx)}</P>
@ -205,8 +225,42 @@ const DetailsRow = ({ it: tx }) => {
) : (
errorElements
)}
{tx.txClass === 'cashOut' && getStatus(tx) !== 'Cancelled' && (
<ActionButton
color="primary"
Icon={CancelIcon}
InverseIcon={CancelInverseIcon}
className={classes.cancelTransaction}
onClick={() =>
setAction({
command: 'cancelTx'
})
}>
Cancel transaction
</ActionButton>
)}
</div>
</div>
<ConfirmDialog
open={action.command === 'cancelTx'}
title={`Cancel this transaction?`}
errorMessage={errorMessage}
toBeConfirmed={tx.machineName}
message={`The user will not be able to redeem the cash, even if they subsequently send the required coins. If they've already sent you coins, you'll need to reconcile this transaction with them manually.`}
onConfirmed={() => {
setErrorMessage(null)
setAction({ command: null })
cancelCashOutTransaction({
variables: {
id: tx.id
}
})
}}
onDissmised={() => {
setAction({ command: null })
setErrorMessage(null)
}}
/>
</div>
)
}

View file

@ -74,6 +74,15 @@ export default {
address: {
width: 280
},
cancelTransaction: {
width: 160
},
status: {
width: 230,
'& > button': {
marginTop: 20
}
},
transactionId: {
width: 280
},