diff --git a/lib/cash-out/cash-out-helper.js b/lib/cash-out/cash-out-helper.js index f86086a6..a98f7a31 100644 --- a/lib/cash-out/cash-out-helper.js +++ b/lib/cash-out/cash-out-helper.js @@ -138,7 +138,7 @@ function toObj (row) { const billFieldsArr = _.concat( _.map(it => ({ name: `cassette${it + 1}`, denomination: newObj[`denomination${it + 1}`], provisioned: newObj[`provisioned${it + 1}`] }))(_.range(0, MAX_CASSETTES)), - _.map(it => ({ name: `recycler${it + 1}`, denomination: newObj[`denomination_recycler${it + 1}`], provisioned: newObj[`provisioned_recycler${it + 1}`] }))(_.range(0, MAX_RECYCLERS)), + _.map(it => ({ name: `recycler${it + 1}`, denomination: newObj[`denominationRecycler${it + 1}`], provisioned: newObj[`provisionedRecycler${it + 1}`] }))(_.range(0, MAX_RECYCLERS)), ) // There can't be bills with denomination === 0. diff --git a/lib/plugins.js b/lib/plugins.js index 6b81f158..4a7ba823 100644 --- a/lib/plugins.js +++ b/lib/plugins.js @@ -109,79 +109,42 @@ function plugins (settings, deviceId) { return tx.fiat.lte(zeroConfLimit) } + const accountProvisioned = (cashUnitType, cashUnits, redeemableTxs) => { + const kons = (cashUnits, tx) => { + // cash-out-helper sends 0 as fallback value, need to filter it out as there are no '0' denominations + const cashUnitsBills = _.flow( + _.get(['bills']), + _.filter(it => _.includes(cashUnitType, it.name) && it.denomination > 0), + _.zip(cashUnits), + )(tx) + + const sameDenominations = ([cashUnit, bill]) => cashUnit?.denomination === bill?.denomination + if (!_.every(sameDenominations, cashUnitsBills)) + throw new Error(`Denominations don't add up, ${cashUnitType}s were changed.`) + + return _.map( + ([cashUnit, { provisioned }]) => _.set('count', cashUnit.count - provisioned, cashUnit), + cashUnitsBills + ) + } + + return _.reduce(kons, cashUnits, redeemableTxs) + } + function computeAvailableCassettes (cassettes, redeemableTxs) { if (_.isEmpty(redeemableTxs)) return cassettes - - const sumTxs = (sum, tx) => { - // cash-out-helper sends 0 as fallback value, need to filter it out as there are no '0' denominations - const bills = _.filter(it => _.includes('cassette', it.name) && it.denomination > 0, tx.bills) - const sameDenominations = a => a[0]?.denomination === a[1]?.denomination - - const doDenominationsMatch = _.every(sameDenominations, _.zip(cassettes, bills)) - - if (!doDenominationsMatch) { - throw new Error('Denominations don\'t add up, cassettes were changed.') - } - - return _.map(r => r[0] + r[1].provisioned, _.zip(sum, tx.bills)) - } - - const provisioned = _.reduce(sumTxs, _.times(_.constant(0), _.size(cassettes)), redeemableTxs) - const zipped = _.zip(_.map('count', cassettes), provisioned) - const counts = _.map(r => r[0] - r[1], zipped) - - if (_.some(_.lt(_, 0), counts)) { + cassettes = accountProvisioned('cassette', cassettes, redeemableTxs) + if (_.some(({ count }) => count < 0, cassettes)) throw new Error('Negative note count: %j', counts) - } - - const computedCassettes = [] - _.forEach(it => { - computedCassettes.push({ - name: cassettes[it].name, - denomination: cassettes[it].denomination, - count: counts[it] - }) - }, _.times(_.identity(), _.size(cassettes))) - - return computedCassettes + return cassettes } function computeAvailableRecyclers (recyclers, redeemableTxs) { if (_.isEmpty(redeemableTxs)) return recyclers - - const sumTxs = (sum, tx) => { - // cash-out-helper sends 0 as fallback value, need to filter it out as there are no '0' denominations - const bills = _.filter(it => _.includes('recycler', it.name) && it.denomination > 0, tx.bills) - const sameDenominations = a => a[0]?.denomination === a[1]?.denomination - - const doDenominationsMatch = _.every(sameDenominations, _.zip(recyclers, bills)) - - if (!doDenominationsMatch) { - throw new Error('Denominations don\'t add up, recyclers were changed.') - } - - return _.map(r => r[0] + r[1].provisioned, _.zip(sum, tx.bills)) - } - - const provisioned = _.reduce(sumTxs, _.times(_.constant(0), _.size(recyclers)), redeemableTxs) - const zipped = _.zip(_.map('count', recyclers), provisioned) - const counts = _.map(r => r[0] - r[1], zipped) - - if (_.some(_.lt(_, 0), counts)) { + recyclers = accountProvisioned('recycler', recyclers, redeemableTxs) + if (_.some(({ count }) => count < 0, recyclers)) throw new Error('Negative note count: %j', counts) - } - - const computedRecyclers = [] - _.forEach(it => { - computedRecyclers.push({ - number: recyclers[it].number, - name: recyclers[it].name, - denomination: recyclers[it].denomination, - count: counts[it] - }) - }, _.times(_.identity(), _.size(recyclers))) - - return computedRecyclers + return recyclers } function buildAvailableCassettes (excludeTxId) { @@ -190,30 +153,27 @@ function plugins (settings, deviceId) { if (!cashOutConfig.active) return Promise.resolve() return Promise.all([dbm.cassetteCounts(deviceId), cashOutHelper.redeemableTxs(deviceId, excludeTxId)]) - .then(([_cassettes, _redeemableTxs]) => { - const redeemableTxs = _.reject(_.matchesProperty('id', excludeTxId), _redeemableTxs) + .then(([{ counts, numberOfCassettes }, redeemableTxs]) => { + redeemableTxs = _.reject(_.matchesProperty('id', excludeTxId), redeemableTxs) - const denominations = [] - _.forEach(it => { - denominations.push(cashOutConfig[`cassette${it + 1}`]) - }, _.times(_.identity(), _cassettes.numberOfCassettes)) + const denominations = _.map( + it => cashOutConfig[`cassette${it}`], + _.range(1, numberOfCassettes+1) + ) - const virtualCassettes = denominations.length ? [Math.max(...denominations) * 2] : [] - - const counts = _cassettes.counts - - if (counts.length !== denominations.length) { + if (counts.length !== denominations.length) throw new Error('Denominations and respective counts do not match!') - } - const cassettes = [] - _.forEach(it => { - cassettes.push({ + const cassettes = _.map( + it => ({ name: `cassette${it + 1}`, denomination: parseInt(denominations[it], 10), count: parseInt(counts[it], 10) - }) - }, _.times(_.identity(), _cassettes.numberOfCassettes)) + }), + _.range(0, numberOfCassettes) + ) + + const virtualCassettes = denominations.length ? [Math.max(...denominations) * 2] : [] try { return { @@ -236,32 +196,28 @@ function plugins (settings, deviceId) { if (!cashOutConfig.active) return Promise.resolve() return Promise.all([dbm.recyclerCounts(deviceId), cashOutHelper.redeemableTxs(deviceId, excludeTxId)]) - .then(([_recyclers, _redeemableTxs]) => { - const redeemableTxs = _.reject(_.matchesProperty('id', excludeTxId), _redeemableTxs) + .then(([{ counts, numberOfRecyclers }, redeemableTxs]) => { + redeemableTxs = _.reject(_.matchesProperty('id', excludeTxId), redeemableTxs) - const denominations = [] - - _.forEach(it => { - denominations.push(cashOutConfig[`recycler${it + 1}`]) - }, _.times(_.identity(), _recyclers.numberOfRecyclers)) + const denominations = _.map( + it => cashOutConfig[`recycler${it}`], + _.range(1, numberOfRecyclers+1) + ) - const virtualRecyclers = denominations.length ? [Math.max(..._.flatten(denominations)) * 2] : [] - - const counts = _recyclers.counts - - if (counts.length !== denominations.length) { + if (counts.length !== denominations.length) throw new Error('Denominations and respective counts do not match!') - } - const recyclers = [] - _.forEach(it => { - recyclers.push({ + const recyclers = _.map( + it => ({ number: it + 1, name: `recycler${it + 1}`, denomination: parseInt(denominations[it], 10), count: parseInt(counts[it], 10) - }) - }, _.times(_.identity(), _recyclers.numberOfRecyclers)) + }), + _.range(0, numberOfRecyclers) + ) + + const virtualRecyclers = denominations.length ? [Math.max(..._.flatten(denominations)) * 2] : [] try { return {