diff --git a/lib/new-admin/graphql/types/transaction.type.js b/lib/new-admin/graphql/types/transaction.type.js index 8208ba0e..a06cfb61 100644 --- a/lib/new-admin/graphql/types/transaction.type.js +++ b/lib/new-admin/graphql/types/transaction.type.js @@ -47,6 +47,7 @@ const typeDef = gql` txCustomerPhotoAt: Date batched: Boolean batchTime: Date + batchError: String walletScore: Int } diff --git a/lib/new-admin/services/funding.js b/lib/new-admin/services/funding.js index 93adf062..2e07e9ab 100644 --- a/lib/new-admin/services/funding.js +++ b/lib/new-admin/services/funding.js @@ -4,6 +4,7 @@ const settingsLoader = require('../../new-settings-loader') const configManager = require('../../new-config-manager') const wallet = require('../../wallet') const ticker = require('../../ticker') +const txBatching = require('../../tx-batching') const { utils: coinUtils } = require('lamassu-coins') function computeCrypto (cryptoCode, _balance) { @@ -23,16 +24,17 @@ function computeFiat (rate, cryptoCode, _balance) { function getSingleCoinFunding (settings, fiatCode, cryptoCode) { const promises = [ wallet.newFunding(settings, cryptoCode), - ticker.getRates(settings, fiatCode, cryptoCode) + ticker.getRates(settings, fiatCode, cryptoCode), + txBatching.getOpenBatchCryptoValue(cryptoCode) ] return Promise.all(promises) - .then(([fundingRec, ratesRec]) => { + .then(([fundingRec, ratesRec, batchRec]) => { const rates = ratesRec.rates const rate = (rates.ask.plus(rates.bid)).div(2) const fundingConfirmedBalance = fundingRec.fundingConfirmedBalance const fiatConfirmedBalance = computeFiat(rate, cryptoCode, fundingConfirmedBalance) - const pending = fundingRec.fundingPendingBalance + const pending = fundingRec.fundingPendingBalance.minus(batchRec) const fiatPending = computeFiat(rate, cryptoCode, pending) const fundingAddress = fundingRec.fundingAddress const fundingAddressUrl = coinUtils.buildUrl(cryptoCode, fundingAddress) diff --git a/lib/new-admin/services/transactions.js b/lib/new-admin/services/transactions.js index daa226b0..28e73b6b 100644 --- a/lib/new-admin/services/transactions.js +++ b/lib/new-admin/services/transactions.js @@ -54,10 +54,12 @@ function batch ( c.id_card_photo_path AS customer_id_card_photo_path, txs.tx_customer_photo_at AS tx_customer_photo_at, txs.tx_customer_photo_path AS tx_customer_photo_path, - ((NOT txs.send_confirmed) AND (txs.created <= now() - interval $1)) AS expired + ((NOT txs.send_confirmed) AND (txs.created <= now() - interval $1)) AS expired, + tb.error_message AS batch_error FROM (SELECT *, ${cashInTx.TRANSACTION_STATES} AS txStatus FROM cash_in_txs) AS txs LEFT OUTER JOIN customers c ON txs.customer_id = c.id LEFT JOIN devices d ON txs.device_id = d.device_id + LEFT OUTER JOIN transaction_batches tb ON txs.batch_id = tb.id WHERE txs.created >= $2 AND txs.created <= $3 ${ id !== null ? `AND txs.device_id = $6` : `` } @@ -69,7 +71,7 @@ function batch ( AND ($12 is null or txs.to_address = $12) AND ($13 is null or txs.txStatus = $13) ${excludeTestingCustomers ? `AND c.is_test_customer is false` : ``} - AND (error IS NOT null OR fiat > 0) + AND (error IS NOT null OR tb.error_message IS NOT null OR fiat > 0) ORDER BY created DESC limit $4 offset $5` const cashOutSql = `SELECT 'cashOut' AS tx_class, @@ -151,6 +153,7 @@ const getCashOutStatus = it => { const getCashInStatus = it => { if (it.operatorCompleted) return 'Cancelled' if (it.hasError) return 'Error' + if (it.batchError) return 'Error' if (it.sendConfirmed) return 'Sent' if (it.expired) return 'Expired' return 'Pending' @@ -176,9 +179,11 @@ function getCustomerTransactionsBatch (ids) { c.name AS customer_name, c.front_camera_path AS customer_front_camera_path, c.id_card_photo_path AS customer_id_card_photo_path, - ((NOT txs.send_confirmed) AND (txs.created <= now() - interval $2)) AS expired + ((NOT txs.send_confirmed) AND (txs.created <= now() - interval $2)) AS expired, + tb.error_message AS batch_error FROM cash_in_txs AS txs LEFT OUTER JOIN customers c ON txs.customer_id = c.id + LEFT OUTER JOIN transaction_batches tb ON txs.batch_id = tb.id WHERE c.id IN ($1^) ORDER BY created DESC limit $3` @@ -220,9 +225,11 @@ function single (txId) { c.name AS customer_name, c.front_camera_path AS customer_front_camera_path, c.id_card_photo_path AS customer_id_card_photo_path, - ((NOT txs.send_confirmed) AND (txs.created <= now() - interval $1)) AS expired + ((NOT txs.send_confirmed) AND (txs.created <= now() - interval $1)) AS expired, + tb.error_message AS batch_error FROM cash_in_txs AS txs LEFT OUTER JOIN customers c ON txs.customer_id = c.id + LEFT OUTER JOIN transaction_batches tb ON txs.batch_id = tb.id WHERE id=$2` const cashOutSql = `SELECT 'cashOut' AS tx_class, diff --git a/lib/wallet.js b/lib/wallet.js index 2653ba77..06d19583 100644 --- a/lib/wallet.js +++ b/lib/wallet.js @@ -48,8 +48,7 @@ const lastBalance = {} function _balance (settings, cryptoCode) { return fetchWallet(settings, cryptoCode) .then(r => r.wallet.balance(r.account, cryptoCode, settings, r.operatorId)) - .then(balance => Promise.all([balance, supportsBatching(settings, cryptoCode)])) - .then(([balance, supportsBatching]) => Promise.all([balance, supportsBatching ? getOpenBatchCryptoValue(cryptoCode) : Promise.resolve(BN(0))])) + .then(balance => Promise.all([balance, getOpenBatchCryptoValue(cryptoCode)])) .then(([balance, reservedBalance]) => ({ balance: balance.minus(reservedBalance), reservedBalance, timestamp: Date.now() })) .then(r => { lastBalance[cryptoCode] = r @@ -82,7 +81,7 @@ function sendCoins (settings, tx) { function sendCoinsBatch (settings, txs, cryptoCode) { return fetchWallet(settings, cryptoCode) .then(r => { - const feeMultiplier = settings[`wallets_${tx.cryptoCode}_feeMultiplier`] + const feeMultiplier = settings[`wallets_${cryptoCode}_feeMultiplier`] return r.wallet.sendCoinsBatch(r.account, txs, cryptoCode, feeMultiplier) .then(res => { mem.clear(module.exports.balance) diff --git a/new-lamassu-admin/src/components/tables/DataTable.js b/new-lamassu-admin/src/components/tables/DataTable.js index 05ff7cd4..099ade01 100644 --- a/new-lamassu-admin/src/components/tables/DataTable.js +++ b/new-lamassu-admin/src/components/tables/DataTable.js @@ -61,9 +61,9 @@ const Row = ({ expandable && expandRow(id, data) onClick && onClick(data) }} - error={data.error || data.hasError} + error={data.error || data.hasError || data.batchError} shouldShowError={false} - errorMessage={data.errorMessage || data.hasError}> + errorMessage={data.errorMessage || data.hasError || data.batchError}> {elements.map(({ view = it => it?.toString(), ...props }, idx) => ( {view(data)} diff --git a/new-lamassu-admin/src/pages/Transactions/DetailsCard.js b/new-lamassu-admin/src/pages/Transactions/DetailsCard.js index d2ff2834..095eafc3 100644 --- a/new-lamassu-admin/src/pages/Transactions/DetailsCard.js +++ b/new-lamassu-admin/src/pages/Transactions/DetailsCard.js @@ -419,5 +419,6 @@ export default memo( (prev, next) => prev.it.id === next.it.id && prev.it.hasError === next.it.hasError && + prev.it.batchError === next.it.batchError && getStatus(prev.it) === getStatus(next.it) ) diff --git a/new-lamassu-admin/src/pages/Transactions/Transactions.js b/new-lamassu-admin/src/pages/Transactions/Transactions.js index e001a69d..b60ebb66 100644 --- a/new-lamassu-admin/src/pages/Transactions/Transactions.js +++ b/new-lamassu-admin/src/pages/Transactions/Transactions.js @@ -116,6 +116,7 @@ const GET_TRANSACTIONS = gql` isAnonymous batched batchTime + batchError walletScore } } @@ -190,7 +191,7 @@ const Transactions = () => {
{getCustomerDisplayName(it)}
{!it.isAnonymous && (
redirect(it.customerId)}> - {it.hasError ? ( + {it.hasError || it.batchError ? ( ) : ( diff --git a/new-lamassu-admin/src/pages/Transactions/helper.js b/new-lamassu-admin/src/pages/Transactions/helper.js index 5e90626d..bc3532d1 100644 --- a/new-lamassu-admin/src/pages/Transactions/helper.js +++ b/new-lamassu-admin/src/pages/Transactions/helper.js @@ -1,3 +1,5 @@ +import * as R from 'ramda' + const getCashOutStatus = it => { if (it.hasError === 'Operator cancel') return 'Cancelled' if (it.hasError) return 'Error' @@ -8,7 +10,7 @@ const getCashOutStatus = it => { const getCashInStatus = it => { if (it.operatorCompleted) return 'Cancelled' - if (it.hasError) return 'Error' + if (it.hasError || it.batchError) return 'Error' if (it.sendConfirmed) return 'Sent' if (it.expired) return 'Expired' if (it.batched) return 'Batched' @@ -23,11 +25,14 @@ const getStatus = it => { } const getStatusDetails = it => { - return it.hasError ? it.hasError : null + if (!R.isNil(it.hasError)) return it.hasError + if (!R.isNil(it.batchError)) return `Batch error: ${it.batchError}` + return null } const getStatusProperties = status => ({ hasError: status === 'Error' || null, + batchError: status === 'Error' || null, dispense: status === 'Success' || null, expired: status === 'Expired' || null, operatorCompleted: status === 'Cancelled' || null,