Merge pull request #1759 from RafaelTaranto/backport/fixedfee-for-cashout
LAM-222 backport: fixedfee for cashout
This commit is contained in:
commit
ec66f2291e
20 changed files with 154 additions and 49 deletions
|
|
@ -51,7 +51,7 @@ const mapValuesWithKey = _.mapValues.convert({cap: false})
|
|||
|
||||
function convertBigNumFields (obj) {
|
||||
const convert = (value, key) => {
|
||||
if (_.includes(key, [ 'cryptoAtoms', 'receivedCryptoAtoms', 'fiat' ])) {
|
||||
if (_.includes(key, [ 'cryptoAtoms', 'receivedCryptoAtoms', 'fiat', 'fixedFee', 'fixedFeeCrypto' ])) {
|
||||
return value.toString()
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ function mapCoin (rates, deviceId, settings, cryptoCode) {
|
|||
const cashInFee = showCommissions ? commissions.cashIn / 100 : null
|
||||
const cashOutFee = showCommissions ? commissions.cashOut / 100 : null
|
||||
const cashInFixedFee = showCommissions ? commissions.fixedFee : null
|
||||
const cashOutFixedFee = showCommissions ? commissions.cashOutFixedFee : null
|
||||
const cashInRate = showCommissions ? _.invoke('cashIn.toNumber', buildedRates) : null
|
||||
const cashOutRate = showCommissions ? _.invoke('cashOut.toNumber', buildedRates) : null
|
||||
|
||||
|
|
@ -37,6 +38,7 @@ function mapCoin (rates, deviceId, settings, cryptoCode) {
|
|||
cashInFee,
|
||||
cashOutFee,
|
||||
cashInFixedFee,
|
||||
cashOutFixedFee,
|
||||
cashInRate,
|
||||
cashOutRate
|
||||
}
|
||||
|
|
|
|||
|
|
@ -89,6 +89,7 @@ const staticConfig = ({ currentConfigVersion, deviceId, deviceName, pq, settings
|
|||
'cashInCommission',
|
||||
'cashInFee',
|
||||
'cashOutCommission',
|
||||
'cashOutFee',
|
||||
'cryptoCode',
|
||||
'cryptoCodeDisplay',
|
||||
'cryptoNetwork',
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ type Coin {
|
|||
display: String!
|
||||
minimumTx: String!
|
||||
cashInFee: String!
|
||||
cashOutFee: String!
|
||||
cashInCommission: String!
|
||||
cashOutCommission: String!
|
||||
cryptoNetwork: String!
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ const typeDef = gql`
|
|||
errorCode: String
|
||||
operatorCompleted: Boolean
|
||||
sendPending: Boolean
|
||||
cashInFee: String
|
||||
fixedFee: String
|
||||
minimumTx: Float
|
||||
customerId: ID
|
||||
isAnonymous: Boolean
|
||||
|
|
|
|||
|
|
@ -50,7 +50,19 @@ function batch (
|
|||
excludeTestingCustomers = false,
|
||||
simplified
|
||||
) {
|
||||
const packager = _.flow(_.flatten, _.orderBy(_.property('created'), ['desc']), _.map(camelize), addProfits, addNames)
|
||||
const packager = _.flow(
|
||||
_.flatten,
|
||||
_.orderBy(_.property('created'), ['desc']),
|
||||
_.map(_.flow(
|
||||
camelize,
|
||||
_.mapKeys(k =>
|
||||
k == 'cashInFee' ? 'fixedFee' :
|
||||
k
|
||||
)
|
||||
)),
|
||||
addProfits,
|
||||
addNames
|
||||
)
|
||||
|
||||
const cashInSql = `SELECT 'cashIn' AS tx_class, txs.*,
|
||||
c.phone AS customer_phone,
|
||||
|
|
@ -153,7 +165,7 @@ function batch (
|
|||
function advancedBatch (data) {
|
||||
const fields = ['txClass', 'id', 'deviceId', 'toAddress', 'cryptoAtoms',
|
||||
'cryptoCode', 'fiat', 'fiatCode', 'fee', 'status', 'fiatProfit', 'cryptoAmount',
|
||||
'dispense', 'notified', 'redeem', 'phone', 'error',
|
||||
'dispense', 'notified', 'redeem', 'phone', 'error', 'fixedFee',
|
||||
'created', 'confirmedAt', 'hdIndex', 'swept', 'timedout',
|
||||
'dispenseConfirmed', 'provisioned1', 'provisioned2', 'provisioned3', 'provisioned4',
|
||||
'provisionedRecycler1', 'provisionedRecycler2', 'provisionedRecycler3', 'provisionedRecycler4', 'provisionedRecycler5', 'provisionedRecycler6',
|
||||
|
|
@ -169,7 +181,9 @@ function advancedBatch (data) {
|
|||
...it,
|
||||
status: getStatus(it),
|
||||
fiatProfit: getProfit(it).toString(),
|
||||
cryptoAmount: getCryptoAmount(it).toString()
|
||||
cryptoAmount: getCryptoAmount(it).toString(),
|
||||
fixedFee: it.fixedFee ?? null,
|
||||
fee: it.fee ?? null,
|
||||
}))
|
||||
|
||||
return _.compose(_.map(_.pick(fields)), addAdvancedFields)(data)
|
||||
|
|
|
|||
|
|
@ -249,6 +249,7 @@ function plugins (settings, deviceId) {
|
|||
const commissions = configManager.getCommissions(cryptoCode, deviceId, settings.config)
|
||||
const minimumTx = new BN(commissions.minimumTx)
|
||||
const cashInFee = new BN(commissions.fixedFee)
|
||||
const cashOutFee = new BN(commissions.cashOutFixedFee)
|
||||
const cashInCommission = new BN(commissions.cashIn)
|
||||
const cashOutCommission = _.isNumber(commissions.cashOut) ? new BN(commissions.cashOut) : null
|
||||
const cryptoRec = coinUtils.getCryptoCurrency(cryptoCode)
|
||||
|
|
@ -261,6 +262,7 @@ function plugins (settings, deviceId) {
|
|||
isCashInOnly: Boolean(cryptoRec.isCashinOnly),
|
||||
minimumTx: BN.max(minimumTx, cashInFee),
|
||||
cashInFee,
|
||||
cashOutFee,
|
||||
cashInCommission,
|
||||
cashOutCommission,
|
||||
cryptoNetwork,
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@ function massage (tx, pi) {
|
|||
: {
|
||||
cryptoAtoms: new BN(r.cryptoAtoms),
|
||||
fiat: new BN(r.fiat),
|
||||
fixedFee: new BN(r.fixedFee),
|
||||
rawTickerPrice: r.rawTickerPrice ? new BN(r.rawTickerPrice) : null,
|
||||
commissionPercentage: new BN(r.commissionPercentage)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,7 @@
|
|||
const db = require('./db')
|
||||
|
||||
exports.up = next => db.multi([
|
||||
'ALTER TABLE cash_out_txs ADD COLUMN fixed_fee numeric(14, 5) NOT NULL DEFAULT 0;'
|
||||
], next)
|
||||
|
||||
exports.down = next => next()
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
const { saveConfig } = require('../lib/new-settings-loader')
|
||||
|
||||
exports.up = next => saveConfig({ 'commissions_cashOutFixedFee': 0 })
|
||||
.then(next)
|
||||
.catch(next)
|
||||
|
||||
exports.down = next => next()
|
||||
|
|
@ -22,22 +22,27 @@ const styles = {
|
|||
const useStyles = makeStyles(styles)
|
||||
|
||||
const groupSecondHeader = elements => {
|
||||
const [toSHeader, noSHeader] = R.partition(R.has('doubleHeader'))(elements)
|
||||
|
||||
if (!toSHeader.length) {
|
||||
return [elements, THead]
|
||||
const doubleHeader = R.prop('doubleHeader')
|
||||
const sameDoubleHeader = (a, b) => doubleHeader(a) === doubleHeader(b)
|
||||
const group = R.pipe(
|
||||
R.groupWith(sameDoubleHeader),
|
||||
R.map(group =>
|
||||
R.isNil(doubleHeader(group[0])) // No doubleHeader
|
||||
? group
|
||||
: [
|
||||
{
|
||||
width: R.sum(R.map(R.prop('width'), group)),
|
||||
elements: group,
|
||||
name: doubleHeader(group[0])
|
||||
}
|
||||
|
||||
const index = R.indexOf(toSHeader[0], elements)
|
||||
const width = R.compose(R.sum, R.map(R.path(['width'])))(toSHeader)
|
||||
|
||||
const innerElements = R.insert(
|
||||
index,
|
||||
{ width, elements: toSHeader, name: toSHeader[0].doubleHeader },
|
||||
noSHeader
|
||||
]
|
||||
),
|
||||
R.reduce(R.concat, [])
|
||||
)
|
||||
|
||||
return [innerElements, TDoubleLevelHead]
|
||||
return R.all(R.pipe(doubleHeader, R.isNil), elements)
|
||||
? [elements, THead]
|
||||
: [group(elements), TDoubleLevelHead]
|
||||
}
|
||||
|
||||
const Header = () => {
|
||||
|
|
|
|||
|
|
@ -77,7 +77,7 @@ const GET_TRANSACTIONS = gql`
|
|||
hasError: error
|
||||
deviceId
|
||||
fiat
|
||||
cashInFee
|
||||
fixedFee
|
||||
fiatCode
|
||||
cryptoAtoms
|
||||
cryptoCode
|
||||
|
|
|
|||
|
|
@ -91,7 +91,7 @@ const getOverridesFields = (getData, currency, auxElements) => {
|
|||
},
|
||||
{
|
||||
name: 'cryptoCurrencies',
|
||||
width: 280,
|
||||
width: 145,
|
||||
size: 'sm',
|
||||
view: displayCodeArray(cryptoData),
|
||||
input: Autocomplete,
|
||||
|
|
@ -108,7 +108,7 @@ const getOverridesFields = (getData, currency, auxElements) => {
|
|||
header: cashInHeader,
|
||||
name: 'cashIn',
|
||||
display: 'Cash-in',
|
||||
width: 130,
|
||||
width: 123,
|
||||
input: NumberInput,
|
||||
textAlign: 'right',
|
||||
suffix: '%',
|
||||
|
|
@ -121,7 +121,7 @@ const getOverridesFields = (getData, currency, auxElements) => {
|
|||
header: cashOutHeader,
|
||||
name: 'cashOut',
|
||||
display: 'Cash-out',
|
||||
width: 130,
|
||||
width: 127,
|
||||
input: NumberInput,
|
||||
textAlign: 'right',
|
||||
suffix: '%',
|
||||
|
|
@ -133,7 +133,7 @@ const getOverridesFields = (getData, currency, auxElements) => {
|
|||
{
|
||||
name: 'fixedFee',
|
||||
display: 'Fixed fee',
|
||||
width: 144,
|
||||
width: 126,
|
||||
input: NumberInput,
|
||||
doubleHeader: 'Cash-in only',
|
||||
textAlign: 'right',
|
||||
|
|
@ -146,7 +146,7 @@ const getOverridesFields = (getData, currency, auxElements) => {
|
|||
{
|
||||
name: 'minimumTx',
|
||||
display: 'Minimum Tx',
|
||||
width: 169,
|
||||
width: 140,
|
||||
doubleHeader: 'Cash-in only',
|
||||
textAlign: 'center',
|
||||
editingAlign: 'right',
|
||||
|
|
@ -156,6 +156,20 @@ const getOverridesFields = (getData, currency, auxElements) => {
|
|||
inputProps: {
|
||||
decimalPlaces: 2
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'cashOutFixedFee',
|
||||
display: 'Fixed fee',
|
||||
width: 134,
|
||||
doubleHeader: 'Cash-out only',
|
||||
textAlign: 'center',
|
||||
editingAlign: 'right',
|
||||
input: NumberInput,
|
||||
suffix: currency,
|
||||
bold: bold,
|
||||
inputProps: {
|
||||
decimalPlaces: 2
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -218,6 +232,21 @@ const mainFields = currency => [
|
|||
inputProps: {
|
||||
decimalPlaces: 2
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'cashOutFixedFee',
|
||||
display: 'Fixed fee',
|
||||
width: 169,
|
||||
size: 'lg',
|
||||
doubleHeader: 'Cash-out only',
|
||||
textAlign: 'center',
|
||||
editingAlign: 'right',
|
||||
input: NumberInput,
|
||||
suffix: currency,
|
||||
bold: bold,
|
||||
inputProps: {
|
||||
decimalPlaces: 2
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
|
|
@ -245,7 +274,7 @@ const getSchema = locale => {
|
|||
.max(percentMax)
|
||||
.required(),
|
||||
fixedFee: Yup.number()
|
||||
.label('Fixed fee')
|
||||
.label('Cash-in fixed fee')
|
||||
.min(0)
|
||||
.max(highestBill)
|
||||
.required(),
|
||||
|
|
@ -253,6 +282,11 @@ const getSchema = locale => {
|
|||
.label('Minimum Tx')
|
||||
.min(0)
|
||||
.max(highestBill)
|
||||
.required(),
|
||||
cashOutFixedFee: Yup.number()
|
||||
.label('Cash-out fixed fee')
|
||||
.min(0)
|
||||
.max(highestBill)
|
||||
.required()
|
||||
})
|
||||
}
|
||||
|
|
@ -340,7 +374,7 @@ const getOverridesSchema = (values, rawData, locale) => {
|
|||
.max(percentMax)
|
||||
.required(),
|
||||
fixedFee: Yup.number()
|
||||
.label('Fixed fee')
|
||||
.label('Cash-in fixed fee')
|
||||
.min(0)
|
||||
.max(highestBill)
|
||||
.required(),
|
||||
|
|
@ -348,6 +382,11 @@ const getOverridesSchema = (values, rawData, locale) => {
|
|||
.label('Minimum Tx')
|
||||
.min(0)
|
||||
.max(highestBill)
|
||||
.required(),
|
||||
cashOutFixedFee: Yup.number()
|
||||
.label('Cash-out fixed fee')
|
||||
.min(0)
|
||||
.max(highestBill)
|
||||
.required()
|
||||
})
|
||||
}
|
||||
|
|
@ -356,7 +395,8 @@ const defaults = {
|
|||
cashIn: '',
|
||||
cashOut: '',
|
||||
fixedFee: '',
|
||||
minimumTx: ''
|
||||
minimumTx: '',
|
||||
cashOutFixedFee: ''
|
||||
}
|
||||
|
||||
const overridesDefaults = {
|
||||
|
|
@ -365,7 +405,8 @@ const overridesDefaults = {
|
|||
cashIn: '',
|
||||
cashOut: '',
|
||||
fixedFee: '',
|
||||
minimumTx: ''
|
||||
minimumTx: '',
|
||||
cashOutFixedFee: ''
|
||||
}
|
||||
|
||||
const getOrder = ({ machine, cryptoCurrencies }) => {
|
||||
|
|
@ -385,6 +426,7 @@ const createCommissions = (cryptoCode, deviceId, isDefault, config) => {
|
|||
fixedFee: config.fixedFee,
|
||||
cashOut: config.cashOut,
|
||||
cashIn: config.cashIn,
|
||||
cashOutFixedFee: config.cashOutFixedFee,
|
||||
machine: deviceId,
|
||||
cryptoCurrencies: [cryptoCode],
|
||||
default: isDefault,
|
||||
|
|
@ -451,7 +493,7 @@ const getListCommissionsSchema = locale => {
|
|||
.max(percentMax)
|
||||
.required(),
|
||||
fixedFee: Yup.number()
|
||||
.label('Fixed fee')
|
||||
.label('Cash-in fixed fee')
|
||||
.min(0)
|
||||
.max(highestBill)
|
||||
.required(),
|
||||
|
|
@ -459,6 +501,11 @@ const getListCommissionsSchema = locale => {
|
|||
.label('Minimum Tx')
|
||||
.min(0)
|
||||
.max(highestBill)
|
||||
.required(),
|
||||
cashOutFixedFee: Yup.number()
|
||||
.label('Cash-out fixed fee')
|
||||
.min(0)
|
||||
.max(highestBill)
|
||||
.required()
|
||||
})
|
||||
}
|
||||
|
|
@ -487,7 +534,7 @@ const getListCommissionsFields = (getData, currency, defaults) => {
|
|||
{
|
||||
name: 'cryptoCurrencies',
|
||||
display: 'Crypto Currency',
|
||||
width: 255,
|
||||
width: 150,
|
||||
view: R.prop(0),
|
||||
size: 'sm',
|
||||
editable: false
|
||||
|
|
@ -496,7 +543,7 @@ const getListCommissionsFields = (getData, currency, defaults) => {
|
|||
header: cashInHeader,
|
||||
name: 'cashIn',
|
||||
display: 'Cash-in',
|
||||
width: 130,
|
||||
width: 120,
|
||||
input: NumberInput,
|
||||
textAlign: 'right',
|
||||
suffix: '%',
|
||||
|
|
@ -509,7 +556,7 @@ const getListCommissionsFields = (getData, currency, defaults) => {
|
|||
header: cashOutHeader,
|
||||
name: 'cashOut',
|
||||
display: 'Cash-out',
|
||||
width: 140,
|
||||
width: 126,
|
||||
input: NumberInput,
|
||||
textAlign: 'right',
|
||||
greenText: true,
|
||||
|
|
@ -522,7 +569,7 @@ const getListCommissionsFields = (getData, currency, defaults) => {
|
|||
{
|
||||
name: 'fixedFee',
|
||||
display: 'Fixed fee',
|
||||
width: 144,
|
||||
width: 140,
|
||||
input: NumberInput,
|
||||
doubleHeader: 'Cash-in only',
|
||||
textAlign: 'right',
|
||||
|
|
@ -535,7 +582,7 @@ const getListCommissionsFields = (getData, currency, defaults) => {
|
|||
{
|
||||
name: 'minimumTx',
|
||||
display: 'Minimum Tx',
|
||||
width: 144,
|
||||
width: 140,
|
||||
input: NumberInput,
|
||||
doubleHeader: 'Cash-in only',
|
||||
textAlign: 'right',
|
||||
|
|
@ -544,6 +591,20 @@ const getListCommissionsFields = (getData, currency, defaults) => {
|
|||
inputProps: {
|
||||
decimalPlaces: 2
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'cashOutFixedFee',
|
||||
display: 'Fixed fee',
|
||||
width: 140,
|
||||
input: NumberInput,
|
||||
doubleHeader: 'Cash-out only',
|
||||
textAlign: 'center',
|
||||
editingAlign: 'right',
|
||||
suffix: currency,
|
||||
textStyle: obj => getTextStyle(obj),
|
||||
inputProps: {
|
||||
decimalPlaces: 2
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,12 +4,7 @@ import React, { useEffect, useRef, useCallback } from 'react'
|
|||
|
||||
import { backgroundColor, zircon, primaryColor } from 'src/styling/variables'
|
||||
|
||||
const transactionProfit = tx => {
|
||||
const cashInFee = tx.cashInFee ? Number.parseFloat(tx.cashInFee) : 0
|
||||
const commission =
|
||||
Number.parseFloat(tx.commissionPercentage) * Number.parseFloat(tx.fiat)
|
||||
return commission + cashInFee
|
||||
}
|
||||
const transactionProfit = R.prop('profit')
|
||||
|
||||
const mockPoint = (tx, offsetMs, profit) => {
|
||||
const date = new Date(new Date(tx.created).getTime() + offsetMs).toISOString()
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ const GET_DATA = gql`
|
|||
transactions(excludeTestingCustomers: $excludeTestingCustomers) {
|
||||
fiatCode
|
||||
fiat
|
||||
cashInFee
|
||||
fixedFee
|
||||
commissionPercentage
|
||||
created
|
||||
txClass
|
||||
|
|
|
|||
|
|
@ -64,10 +64,11 @@ const Commissions = ({ name: SCREEN_KEY, id: deviceId }) => {
|
|||
cashIn: config.cashIn,
|
||||
cashOut: config.cashOut,
|
||||
fixedFee: config.fixedFee,
|
||||
minimumTx: config.minimumTx
|
||||
minimumTx: config.minimumTx,
|
||||
cashOutFixedFee: config.cashOutFixedFee
|
||||
},
|
||||
R.project(
|
||||
['cashIn', 'cashOut', 'fixedFee', 'minimumTx'],
|
||||
['cashIn', 'cashOut', 'fixedFee', 'minimumTx', 'cashOutFixedFee'],
|
||||
R.filter(
|
||||
o =>
|
||||
R.includes(coin.code, o.cryptoCurrencies) ||
|
||||
|
|
|
|||
|
|
@ -61,6 +61,14 @@ const getOverridesFields = currency => {
|
|||
doubleHeader: 'Cash-in only',
|
||||
textAlign: 'right',
|
||||
suffix: currency
|
||||
},
|
||||
{
|
||||
name: 'cashOutFixedFee',
|
||||
display: 'Fixed fee',
|
||||
width: 155,
|
||||
doubleHeader: 'Cash-out only',
|
||||
textAlign: 'right',
|
||||
suffix: currency
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ const GET_TRANSACTIONS = gql`
|
|||
hasError: error
|
||||
deviceId
|
||||
fiat
|
||||
cashInFee
|
||||
fixedFee
|
||||
fiatCode
|
||||
cryptoAtoms
|
||||
cryptoCode
|
||||
|
|
|
|||
|
|
@ -133,9 +133,9 @@ const DetailsRow = ({ it: tx, timezone }) => {
|
|||
const commission = BigNumber(tx.profit).toFixed(2, 1) // ROUND_DOWN
|
||||
const commissionPercentage =
|
||||
Number.parseFloat(tx.commissionPercentage, 2) * 100
|
||||
const cashInFee = isCashIn ? Number.parseFloat(tx.cashInFee) : 0
|
||||
const fixedFee = Number.parseFloat(tx.fixedFee) || 0
|
||||
const fiat = BigNumber(tx.fiat)
|
||||
.minus(cashInFee)
|
||||
.minus(fixedFee)
|
||||
.toFixed(2, 1) // ROUND_DOWN
|
||||
const crypto = getCryptoAmount(tx)
|
||||
const cryptoFee = tx.fee ? `${getCryptoFeeAmount(tx)} ${tx.fiatCode}` : 'N/A'
|
||||
|
|
@ -357,7 +357,7 @@ const DetailsRow = ({ it: tx, timezone }) => {
|
|||
</div>
|
||||
<div>
|
||||
<Label>Fixed fee</Label>
|
||||
<div>{isCashIn ? `${cashInFee} ${tx.fiatCode}` : 'N/A'}</div>
|
||||
<div>{`${fixedFee} ${tx.fiatCode}`}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className={classes.secondRow}>
|
||||
|
|
|
|||
|
|
@ -107,7 +107,7 @@ const GET_TRANSACTIONS = gql`
|
|||
deviceId
|
||||
fiat
|
||||
fee
|
||||
cashInFee
|
||||
fixedFee
|
||||
fiatCode
|
||||
cryptoAtoms
|
||||
cryptoCode
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue