From f597c0e4f822a72c92ebbc88c419213e8cfd3bed Mon Sep 17 00:00:00 2001 From: siiky Date: Fri, 25 Oct 2024 18:01:04 +0100 Subject: [PATCH 1/7] chore: remove dead code --- lib/plugins.js | 3 --- 1 file changed, 3 deletions(-) diff --git a/lib/plugins.js b/lib/plugins.js index 1abb0489..c56f996d 100644 --- a/lib/plugins.js +++ b/lib/plugins.js @@ -695,9 +695,6 @@ function plugins (settings, deviceId) { const denominationRecycler6 = cashOutConfig.recycler6 const cashOutEnabled = cashOutConfig.active const isUnitLow = (have, max, limit) => cashOutEnabled && ((have / max) * 100) < limit - // const isUnitHigh = (have, max, limit) => cashOutEnabled && ((have / max) * 100) > limit - - // const isUnitOutOfBounds = (have, max, lowerBound, upperBound) => isUnitLow(have, max, lowerBound) || isUnitHigh(have, max, upperBound) const notifications = configManager.getNotifications(null, device.deviceId, settings.config) From 7a7292d2faf83e1a93aabd6282aa93919085df43 Mon Sep 17 00:00:00 2001 From: siiky Date: Fri, 25 Oct 2024 17:53:26 +0100 Subject: [PATCH 2/7] refactor: deduplicate balance alerts checking code --- lib/plugins.js | 203 ++++++++++++++----------------------------------- 1 file changed, 55 insertions(+), 148 deletions(-) diff --git a/lib/plugins.js b/lib/plugins.js index c56f996d..a97e1350 100644 --- a/lib/plugins.js +++ b/lib/plugins.js @@ -682,166 +682,73 @@ function plugins (settings, deviceId) { } function checkDeviceCashBalances (fiatCode, device) { - const cashOutConfig = configManager.getCashOut(device.deviceId, settings.config) - const denomination1 = cashOutConfig.cassette1 - const denomination2 = cashOutConfig.cassette2 - const denomination3 = cashOutConfig.cassette3 - const denomination4 = cashOutConfig.cassette4 - const denominationRecycler1 = cashOutConfig.recycler1 - const denominationRecycler2 = cashOutConfig.recycler2 - const denominationRecycler3 = cashOutConfig.recycler3 - const denominationRecycler4 = cashOutConfig.recycler4 - const denominationRecycler5 = cashOutConfig.recycler5 - const denominationRecycler6 = cashOutConfig.recycler6 - const cashOutEnabled = cashOutConfig.active - const isUnitLow = (have, max, limit) => cashOutEnabled && ((have / max) * 100) < limit - - const notifications = configManager.getNotifications(null, device.deviceId, settings.config) - + const deviceId = device.deviceId const machineName = device.name + const notifications = configManager.getNotifications(null, deviceId, settings.config) - const cashInAlert = device.cashUnits.cashbox > notifications.cashInAlertThreshold - ? { + const cashInAlerts = device.cashUnits.cashbox > notifications.cashInAlertThreshold + ? [{ code: 'CASH_BOX_FULL', machineName, - deviceId: device.deviceId, + deviceId, notes: device.cashUnits.cashbox - } - : null + }] + : [] - const cassette1Alert = device.numberOfCassettes >= 1 && isUnitLow(device.cashUnits.cassette1, getCashUnitCapacity(device.model, 'cassette'), notifications.fillingPercentageCassette1) - ? { - code: 'LOW_CASH_OUT', - cassette: 1, - machineName, - deviceId: device.deviceId, - notes: device.cashUnits.cassette1, - denomination: denomination1, - fiatCode - } - : null + const cashOutConfig = configManager.getCashOut(deviceId, settings.config) + const cashOutEnabled = cashOutConfig.active + const isUnitLow = (have, max, limit) => ((have / max) * 100) < limit - const cassette2Alert = device.numberOfCassettes >= 2 && isUnitLow(device.cashUnits.cassette2, getCashUnitCapacity(device.model, 'cassette'), notifications.fillingPercentageCassette2) - ? { - code: 'LOW_CASH_OUT', - cassette: 2, - machineName, - deviceId: device.deviceId, - notes: device.cashUnits.cassette2, - denomination: denomination2, - fiatCode - } - : null + if (!cashOutEnabled) + return cashInAlerts - const cassette3Alert = device.numberOfCassettes >= 3 && isUnitLow(device.cashUnits.cassette3, getCashUnitCapacity(device.model, 'cassette'), notifications.fillingPercentageCassette3) - ? { - code: 'LOW_CASH_OUT', - cassette: 3, - machineName, - deviceId: device.deviceId, - notes: device.cashUnits.cassette3, - denomination: denomination3, - fiatCode - } - : null + const cassetteCapacity = getCashUnitCapacity(device.model, 'cassette') + const cassetteAlerts = Array(Math.min(device.numberOfCassettes ?? 0, 4)) + .fill(null) + .flatMap((_elem, idx) => { + const nth = idx + 1 + const cassetteField = `cassette${nth}` + const notes = device.cashUnits[cassetteField] + const denomination = cashOutConfig[cassetteField] - const cassette4Alert = device.numberOfCassettes >= 4 && isUnitLow(device.cashUnits.cassette4, getCashUnitCapacity(device.model, 'cassette'), notifications.fillingPercentageCassette4) - ? { - code: 'LOW_CASH_OUT', - cassette: 4, - machineName, - deviceId: device.deviceId, - notes: device.cashUnits.cassette4, - denomination: denomination4, - fiatCode - } - : null + const limit = notifications[`fillingPercentageCassette${nth}`] + return isUnitLow(notes, cassetteCapacity, limit) ? + [{ + code: 'LOW_CASH_OUT', + cassette: nth, + machineName, + deviceId, + notes, + denomination, + fiatCode + }] : + [] + }) - const recycler1Alert = device.numberOfRecyclers >= 1 && isUnitLow(device.cashUnits.recycler1, getCashUnitCapacity(device.model, 'recycler'), notifications.fillingPercentageRecycler1) - ? { - code: 'LOW_RECYCLER_STACKER', - cassette: 4, - machineName, - deviceId: device.deviceId, - notes: device.cashUnits.recycler1, - denomination: denominationRecycler1, - fiatCode - } - : null + const recyclerCapacity = getCashUnitCapacity(device.model, 'recycler') + const recyclerAlerts = Array(Math.min(device.numberOfRecyclers ?? 0, 6)) + .fill(null) + .flatMap((_elem, idx) => { + const nth = idx + 1 + const recyclerField = `recycler${nth}` + const notes = device.cashUnits[recyclerField] + const denomination = cashOutConfig[recyclerField] - const recycler2Alert = device.numberOfRecyclers >= 2 && isUnitLow(device.cashUnits.recycler2, getCashUnitCapacity(device.model, 'recycler'), notifications.fillingPercentageRecycler2) - ? { - code: 'LOW_RECYCLER_STACKER', - cassette: 4, - machineName, - deviceId: device.deviceId, - notes: device.cashUnits.recycler2, - denomination: denominationRecycler2, - fiatCode - } - : null + const limit = notifications[`fillingPercentageRecycler${nth}`] + return isUnitLow(notes, recyclerCapacity, limit) ? + [{ + code: 'LOW_RECYCLER_STACKER', + cassette: nth, // @see DETAIL_TEMPLATE in /lib/notifier/utils.js + machineName, + deviceId, + notes, + denomination, + fiatCode + }] : + [] + }) - const recycler3Alert = device.numberOfRecyclers >= 3 && isUnitLow(device.cashUnits.recycler3, getCashUnitCapacity(device.model, 'recycler'), notifications.fillingPercentageRecycler3) - ? { - code: 'LOW_RECYCLER_STACKER', - cassette: 4, - machineName, - deviceId: device.deviceId, - notes: device.cashUnits.recycler3, - denomination: denominationRecycler3, - fiatCode - } - : null - - const recycler4Alert = device.numberOfRecyclers >= 4 && isUnitLow(device.cashUnits.recycler4, getCashUnitCapacity(device.model, 'recycler'), notifications.fillingPercentageRecycler4) - ? { - code: 'LOW_RECYCLER_STACKER', - cassette: 4, - machineName, - deviceId: device.deviceId, - notes: device.cashUnits.recycler4, - denomination: denominationRecycler4, - fiatCode - } - : null - - const recycler5Alert = device.numberOfRecyclers >= 5 && isUnitLow(device.cashUnits.recycler5, getCashUnitCapacity(device.model, 'recycler'), notifications.fillingPercentageRecycler5) - ? { - code: 'LOW_RECYCLER_STACKER', - cassette: 4, - machineName, - deviceId: device.deviceId, - notes: device.cashUnits.recycler5, - denomination: denominationRecycler5, - fiatCode - } - : null - - const recycler6Alert = device.numberOfRecyclers >= 6 && isUnitLow(device.cashUnits.recycler6, getCashUnitCapacity(device.model, 'recycler'), notifications.fillingPercentageRecycler6) - ? { - code: 'LOW_RECYCLER_STACKER', - cassette: 4, - machineName, - deviceId: device.deviceId, - notes: device.cashUnits.recycler6, - denomination: denominationRecycler6, - fiatCode - } - : null - - return _.compact([ - cashInAlert, - cassette1Alert, - cassette2Alert, - cassette3Alert, - cassette4Alert, - recycler1Alert, - recycler2Alert, - recycler3Alert, - recycler4Alert, - recycler5Alert, - recycler6Alert - ]) + return [].concat(cashInAlerts, cassetteAlerts, recyclerAlerts) } function checkCryptoBalances (fiatCode, devices) { From 5c39140ea88a8511c4e5b3c7d14f5a405decc65c Mon Sep 17 00:00:00 2001 From: siiky Date: Fri, 25 Oct 2024 18:09:06 +0100 Subject: [PATCH 3/7] refactor: replace magic constants --- lib/constants.js | 2 ++ lib/plugins.js | 12 +++++++++--- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/lib/constants.js b/lib/constants.js index 60fcd128..07c2ad84 100644 --- a/lib/constants.js +++ b/lib/constants.js @@ -51,6 +51,7 @@ const CASH_UNIT_CAPACITY = { const CASH_OUT_MINIMUM_AMOUNT_OF_CASSETTES = 2 const CASH_OUT_MAXIMUM_AMOUNT_OF_CASSETTES = 4 +const CASH_OUT_MAXIMUM_AMOUNT_OF_RECYCLERS = 6 const AUTHENTICATOR_ISSUER_ENTITY = 'Lamassu' const AUTH_TOKEN_EXPIRATION_TIME = '30 minutes' const REGISTRATION_TOKEN_EXPIRATION_TIME = '30 minutes' @@ -85,6 +86,7 @@ module.exports = { CONFIRMATION_CODE, CASH_OUT_MINIMUM_AMOUNT_OF_CASSETTES, CASH_OUT_MAXIMUM_AMOUNT_OF_CASSETTES, + CASH_OUT_MAXIMUM_AMOUNT_OF_RECYCLERS, WALLET_SCORE_THRESHOLD, RECEIPT, PSQL_URL, diff --git a/lib/plugins.js b/lib/plugins.js index a97e1350..84a62cf8 100644 --- a/lib/plugins.js +++ b/lib/plugins.js @@ -24,7 +24,13 @@ const commissionMath = require('./commission-math') const loyalty = require('./loyalty') const transactionBatching = require('./tx-batching') -const { CASH_UNIT_CAPACITY, CASH_OUT_DISPENSE_READY, CONFIRMATION_CODE } = require('./constants') +const { + CASH_OUT_DISPENSE_READY, + CASH_OUT_MAXIMUM_AMOUNT_OF_CASSETTES, + CASH_OUT_MAXIMUM_AMOUNT_OF_RECYCLERS, + CASH_UNIT_CAPACITY, + CONFIRMATION_CODE, +} = require('./constants') const notifier = require('./notifier') @@ -703,7 +709,7 @@ function plugins (settings, deviceId) { return cashInAlerts const cassetteCapacity = getCashUnitCapacity(device.model, 'cassette') - const cassetteAlerts = Array(Math.min(device.numberOfCassettes ?? 0, 4)) + const cassetteAlerts = Array(Math.min(device.numberOfCassettes ?? 0, CASH_OUT_MAXIMUM_AMOUNT_OF_CASSETTES)) .fill(null) .flatMap((_elem, idx) => { const nth = idx + 1 @@ -726,7 +732,7 @@ function plugins (settings, deviceId) { }) const recyclerCapacity = getCashUnitCapacity(device.model, 'recycler') - const recyclerAlerts = Array(Math.min(device.numberOfRecyclers ?? 0, 6)) + const recyclerAlerts = Array(Math.min(device.numberOfRecyclers ?? 0, CASH_OUT_MAXIMUM_AMOUNT_OF_RECYCLERS)) .fill(null) .flatMap((_elem, idx) => { const nth = idx + 1 From 815fd36ede15c59ff11ac1c7ac2f2dc2b6a6bb76 Mon Sep 17 00:00:00 2001 From: siiky Date: Mon, 28 Oct 2024 16:26:10 +0000 Subject: [PATCH 4/7] refactor: use notification codes & explicitly test all possible codes --- lib/notifier/notificationCenter.js | 40 ++++++++++++++++++------------ 1 file changed, 24 insertions(+), 16 deletions(-) diff --git a/lib/notifier/notificationCenter.js b/lib/notifier/notificationCenter.js index 06f6e0ca..b53ca4eb 100644 --- a/lib/notifier/notificationCenter.js +++ b/lib/notifier/notificationCenter.js @@ -2,20 +2,26 @@ const _ = require('lodash/fp') const queries = require('./queries') const utils = require('./utils') -const codes = require('./codes') const customers = require('../customers') +const { + NOTIFICATION_TYPES: { + SECURITY, + COMPLIANCE, + CRYPTO_BALANCE, + FIAT_BALANCE, + ERROR, + HIGH_VALUE_TX, + NORMAL_VALUE_TX + }, -const { NOTIFICATION_TYPES: { - SECURITY, - COMPLIANCE, - CRYPTO_BALANCE, - FIAT_BALANCE, - ERROR, - HIGH_VALUE_TX, - NORMAL_VALUE_TX } -} = codes + STALE, + PING, -const { STALE, PING } = codes + HIGH_CRYPTO_BALANCE, + LOW_CRYPTO_BALANCE, + CASH_BOX_FULL, + LOW_CASH_OUT, +} = require('./codes') const sanctionsNotify = (customer, phone) => { const code = 'SANCTIONS' @@ -71,9 +77,11 @@ const fiatBalancesNotify = (fiatWarnings) => { const { cassette, deviceId } = o.detail return cassette === balance.cassette && deviceId === balance.deviceId }, notInvalidated)) return - const message = balance.code === 'LOW_CASH_OUT' ? + const message = balance.code === LOW_CASH_OUT ? `Cash-out cassette ${balance.cassette} low or empty!` : - `Cash box full or almost full!` + balance.code === CASH_BOX_FULL ? + `Cash box full or almost full!` : + `Cash box full or almost full!` /* Shouldn't happen */ const detailB = utils.buildDetail({ deviceId: balance.deviceId, cassette: balance.cassette }) return queries.addNotification(FIAT_BALANCE, message, detailB) }) @@ -105,7 +113,7 @@ const cryptoBalancesNotify = (cryptoWarnings) => { }, notInvalidated)) return const fiat = utils.formatCurrency(balance.fiatBalance.balance, balance.fiatCode) - const message = `${balance.code === 'HIGH_CRYPTO_BALANCE' ? 'High' : 'Low'} balance in ${balance.cryptoCode} [${fiat}]` + const message = `${balance.code === HIGH_CRYPTO_BALANCE ? 'High' : 'Low'} balance in ${balance.cryptoCode} [${fiat}]` const detailB = utils.buildDetail({ cryptoCode: balance.cryptoCode, code: balance.code }) return queries.addNotification(CRYPTO_BALANCE, message, detailB) }) @@ -113,8 +121,8 @@ const cryptoBalancesNotify = (cryptoWarnings) => { } const balancesNotify = (balances) => { - const isCryptoCode = c => _.includes(c, ['HIGH_CRYPTO_BALANCE', 'LOW_CRYPTO_BALANCE']) - const isFiatCode = c => _.includes(c, ['LOW_CASH_OUT', 'CASH_BOX_FULL']) + const isCryptoCode = c => _.includes(c, [HIGH_CRYPTO_BALANCE, LOW_CRYPTO_BALANCE]) + const isFiatCode = c => _.includes(c, [LOW_CASH_OUT, CASH_BOX_FULL]) const by = o => isCryptoCode(o) ? 'crypto' : isFiatCode(o) ? 'fiat' : From 1395448e78317504fd2ddfde14a17fce7c02a503 Mon Sep 17 00:00:00 2001 From: siiky Date: Mon, 28 Oct 2024 16:27:23 +0000 Subject: [PATCH 5/7] feat: add notif message for `LOW_RECYCLER_STACKER` --- lib/notifier/codes.js | 2 ++ lib/notifier/notificationCenter.js | 3 +++ 2 files changed, 5 insertions(+) diff --git a/lib/notifier/codes.js b/lib/notifier/codes.js index cb7da476..b0e02895 100644 --- a/lib/notifier/codes.js +++ b/lib/notifier/codes.js @@ -6,6 +6,7 @@ const LOW_CRYPTO_BALANCE = 'LOW_CRYPTO_BALANCE' const HIGH_CRYPTO_BALANCE = 'HIGH_CRYPTO_BALANCE' const CASH_BOX_FULL = 'CASH_BOX_FULL' const LOW_CASH_OUT = 'LOW_CASH_OUT' +const LOW_RECYCLER_STACKER = 'LOW_RECYCLER_STACKER' const SECURITY = 'SECURITY' const CODES_DISPLAY = { @@ -41,6 +42,7 @@ module.exports = { HIGH_CRYPTO_BALANCE, CASH_BOX_FULL, LOW_CASH_OUT, + LOW_RECYCLER_STACKER, SECURITY, CODES_DISPLAY, NETWORK_DOWN_TIME, diff --git a/lib/notifier/notificationCenter.js b/lib/notifier/notificationCenter.js index b53ca4eb..5b143bdd 100644 --- a/lib/notifier/notificationCenter.js +++ b/lib/notifier/notificationCenter.js @@ -21,6 +21,7 @@ const { LOW_CRYPTO_BALANCE, CASH_BOX_FULL, LOW_CASH_OUT, + LOW_RECYCLER_STACKER, } = require('./codes') const sanctionsNotify = (customer, phone) => { @@ -79,6 +80,8 @@ const fiatBalancesNotify = (fiatWarnings) => { }, notInvalidated)) return const message = balance.code === LOW_CASH_OUT ? `Cash-out cassette ${balance.cassette} low or empty!` : + balance.code === LOW_RECYCLER_STACKER ? + `Recycler ${balance.cassette} low or empty!` : balance.code === CASH_BOX_FULL ? `Cash box full or almost full!` : `Cash box full or almost full!` /* Shouldn't happen */ From e7e104d6a01a82bf1c826bd83c95d070f1eb68e1 Mon Sep 17 00:00:00 2001 From: siiky Date: Mon, 28 Oct 2024 16:51:48 +0000 Subject: [PATCH 6/7] fix: recycler notifications --- lib/notifier/notificationCenter.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/notifier/notificationCenter.js b/lib/notifier/notificationCenter.js index 5b143bdd..7f3480b0 100644 --- a/lib/notifier/notificationCenter.js +++ b/lib/notifier/notificationCenter.js @@ -125,7 +125,7 @@ const cryptoBalancesNotify = (cryptoWarnings) => { const balancesNotify = (balances) => { const isCryptoCode = c => _.includes(c, [HIGH_CRYPTO_BALANCE, LOW_CRYPTO_BALANCE]) - const isFiatCode = c => _.includes(c, [LOW_CASH_OUT, CASH_BOX_FULL]) + const isFiatCode = c => _.includes(c, [LOW_CASH_OUT, CASH_BOX_FULL, LOW_RECYCLER_STACKER]) const by = o => isCryptoCode(o) ? 'crypto' : isFiatCode(o) ? 'fiat' : From 5ca6fc4cdf62533ba9003a1b444e63eb9f60ca1a Mon Sep 17 00:00:00 2001 From: siiky Date: Mon, 28 Oct 2024 17:35:30 +0000 Subject: [PATCH 7/7] fix: enable recycler notifs in email --- lib/notifier/email.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/notifier/email.js b/lib/notifier/email.js index 5ad4b774..c53df248 100644 --- a/lib/notifier/email.js +++ b/lib/notifier/email.js @@ -10,6 +10,7 @@ const { HIGH_CRYPTO_BALANCE, CASH_BOX_FULL, LOW_CASH_OUT, + LOW_RECYCLER_STACKER, SECURITY } = require('./codes') @@ -80,6 +81,8 @@ function emailAlert (alert) { return `Cash box full on ${alert.machineName} [${alert.notes} banknotes]` case LOW_CASH_OUT: return `Cassette for ${alert.denomination} ${alert.fiatCode} low [${alert.notes} banknotes]` + case LOW_RECYCLER_STACKER: + return `Recycler for ${alert.denomination} ${alert.fiatCode} low [${alert.notes} banknotes]` case SECURITY: return `Cashbox removed on ${alert.machineName}` }