feat: add empty and refill unit machine actions
fix: remove certain actions from the state middleware after being consumed by the poller
This commit is contained in:
parent
2e9bb3c7df
commit
797f074898
10 changed files with 163 additions and 2 deletions
|
|
@ -182,7 +182,7 @@ const dynamicConfig = ({ deviceId, operatorId, pid, pq, settings, }) => {
|
|||
|
||||
state.pids = _.update(operatorId, _.set(deviceId, { pid, ts: Date.now() }), state.pids)
|
||||
|
||||
return _.flow(
|
||||
const res = _.flow(
|
||||
_.pick(['areThereAvailablePromoCodes', 'balances', 'cassettes', 'stackers', 'coins', 'rates']),
|
||||
|
||||
_.update('cassettes', massageCassettes),
|
||||
|
|
@ -225,7 +225,20 @@ const dynamicConfig = ({ deviceId, operatorId, pid, pq, settings, }) => {
|
|||
_.set('reboot', !!pid && state.reboots?.[operatorId]?.[deviceId] === pid),
|
||||
_.set('shutdown', !!pid && state.shutdowns?.[operatorId]?.[deviceId] === pid),
|
||||
_.set('restartServices', !!pid && state.restartServicesMap?.[operatorId]?.[deviceId] === pid),
|
||||
_.set('emptyUnit', !!pid && state.emptyUnit?.[operatorId]?.[deviceId] === pid),
|
||||
_.set('refillUnit', !!pid && state.refillUnit?.[operatorId]?.[deviceId] === pid),
|
||||
)(pq)
|
||||
|
||||
// Clean up the state middleware and prevent commands from being issued more than once
|
||||
if (!_.isNil(state.emptyUnit?.[operatorId]?.[deviceId])) {
|
||||
delete state.emptyUnit?.[operatorId]?.[deviceId]
|
||||
}
|
||||
|
||||
if (!_.isNil(state.refillUnit?.[operatorId]?.[deviceId])) {
|
||||
delete state.refillUnit?.[operatorId]?.[deviceId]
|
||||
}
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -196,6 +196,8 @@ type DynamicConfig {
|
|||
reboot: Boolean!
|
||||
shutdown: Boolean!
|
||||
restartServices: Boolean!
|
||||
emptyUnit: Boolean!
|
||||
refillUnit: Boolean!
|
||||
}
|
||||
|
||||
type Configs {
|
||||
|
|
|
|||
|
|
@ -173,6 +173,42 @@ function setCassetteBills (rec) {
|
|||
})
|
||||
}
|
||||
|
||||
function emptyMachineUnits (deviceId, units) {
|
||||
return Promise.all([getMachine(deviceId), configManager.getCashOut(deviceId, getConfig())])
|
||||
.then(([machine, cashoutSettings]) => {
|
||||
const movedBills = _.reduce(
|
||||
(acc, value) => ({
|
||||
...acc,
|
||||
[value]: {
|
||||
delta: machine[value] - units[value],
|
||||
denomination: cashoutSettings[value]
|
||||
}
|
||||
}),
|
||||
{},
|
||||
_.keys(units)
|
||||
)
|
||||
|
||||
const sql = `UPDATE devices SET cassette1=$2, cassette2=$3, cassette3=$4, cassette4=$5, stacker1f=$6, stacker1r=$7, stacker2f=$8, stacker2r=$9, stacker3f=$10, stacker3r=$11 WHERE device_id=$1`
|
||||
return db.none(sql, [
|
||||
deviceId,
|
||||
_.defaultTo(0, units.cassette1),
|
||||
_.defaultTo(0, units.cassette2),
|
||||
_.defaultTo(0, units.cassette3),
|
||||
_.defaultTo(0, units.cassette4),
|
||||
_.defaultTo(0, units.stacker1f),
|
||||
_.defaultTo(0, units.stacker1r),
|
||||
_.defaultTo(0, units.stacker2f),
|
||||
_.defaultTo(0, units.stacker2r),
|
||||
_.defaultTo(0, units.stacker3f),
|
||||
_.defaultTo(0, units.stacker3r)
|
||||
])
|
||||
})
|
||||
}
|
||||
|
||||
function refillMachineUnits (deviceId, units) {
|
||||
return Promise.resolve()
|
||||
}
|
||||
|
||||
function unpair (rec) {
|
||||
return pairing.unpair(rec.deviceId)
|
||||
}
|
||||
|
|
@ -204,6 +240,24 @@ function restartServices (rec) {
|
|||
)])
|
||||
}
|
||||
|
||||
function emptyUnit (rec) {
|
||||
return db.none('NOTIFY $1:name, $2', ['machineAction', JSON.stringify(
|
||||
{
|
||||
action: 'emptyUnit',
|
||||
value: _.pick(['deviceId', 'operatorId', 'action'], rec)
|
||||
}
|
||||
)])
|
||||
}
|
||||
|
||||
function refillUnit (rec) {
|
||||
return db.none('NOTIFY $1:name, $2', ['machineAction', JSON.stringify(
|
||||
{
|
||||
action: 'refillUnit',
|
||||
value: _.pick(['deviceId', 'operatorId', 'action'], rec)
|
||||
}
|
||||
)])
|
||||
}
|
||||
|
||||
function setMachine (rec, operatorId) {
|
||||
rec.operatorId = operatorId
|
||||
switch (rec.action) {
|
||||
|
|
@ -215,6 +269,8 @@ function setMachine (rec, operatorId) {
|
|||
case 'reboot': return reboot(rec)
|
||||
case 'shutdown': return shutdown(rec)
|
||||
case 'restartServices': return restartServices(rec)
|
||||
case 'emptyUnit': return emptyUnit(rec)
|
||||
case 'refillUnit': return refillUnit(rec)
|
||||
default: throw new Error('No such action: ' + rec.action)
|
||||
}
|
||||
}
|
||||
|
|
@ -288,5 +344,7 @@ module.exports = {
|
|||
updateNetworkHeartbeat,
|
||||
getNetworkPerformance,
|
||||
getNetworkHeartbeat,
|
||||
getConfig
|
||||
getConfig,
|
||||
emptyMachineUnits,
|
||||
refillMachineUnits
|
||||
}
|
||||
|
|
|
|||
|
|
@ -37,6 +37,14 @@ function machineAction (type, value) {
|
|||
logger.debug(`Restarting services of machine '${deviceId}' from operator ${operatorId}`)
|
||||
state.restartServicesMap[operatorId] = { [deviceId]: pid }
|
||||
break
|
||||
case 'emptyUnit':
|
||||
logger.debug(`Emptying units from machine '${deviceId}' from operator ${operatorId}`)
|
||||
state.emptyUnit[operatorId] = { [deviceId]: pid }
|
||||
break
|
||||
case 'refillUnit':
|
||||
logger.debug(`Refilling stackers from machine '${deviceId}' from operator ${operatorId}`)
|
||||
state.refillUnit[operatorId] = { [deviceId]: pid }
|
||||
break
|
||||
default:
|
||||
break
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,6 +15,8 @@ module.exports = (function () {
|
|||
reboots: {},
|
||||
shutdowns: {},
|
||||
restartServicesMap: {},
|
||||
emptyUnit: {},
|
||||
refillUnit: {},
|
||||
mnemonic: null
|
||||
}
|
||||
}())
|
||||
|
|
|
|||
|
|
@ -80,6 +80,8 @@ const typeDef = gql`
|
|||
reboot
|
||||
shutdown
|
||||
restartServices
|
||||
emptyUnit
|
||||
refillUnit
|
||||
}
|
||||
|
||||
type Query {
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ const populateDeviceId = require('./middlewares/populateDeviceId')
|
|||
const populateSettings = require('./middlewares/populateSettings')
|
||||
const recordPing = require('./middlewares/recordPing')
|
||||
|
||||
const unitsRoutes = require('./routes/unitsRoutes')
|
||||
const cashboxRoutes = require('./routes/cashboxRoutes')
|
||||
const customerRoutes = require('./routes/customerRoutes')
|
||||
const logsRoutes = require('./routes/logsRoutes')
|
||||
|
|
@ -82,6 +83,7 @@ app.use('/customer', customerRoutes)
|
|||
app.use('/tx', txRoutes)
|
||||
|
||||
app.use('/logs', logsRoutes)
|
||||
app.use('/units', unitsRoutes)
|
||||
|
||||
graphQLServer.applyMiddleware({ app })
|
||||
|
||||
|
|
|
|||
|
|
@ -96,6 +96,8 @@ function poll (req, res, next) {
|
|||
const reboot = pid && state.reboots?.[operatorId]?.[deviceId] === pid
|
||||
const shutdown = pid && state.shutdowns?.[operatorId]?.[deviceId] === pid
|
||||
const restartServices = pid && state.restartServicesMap?.[operatorId]?.[deviceId] === pid
|
||||
const emptyUnit = pid && state.emptyUnit?.[operatorId]?.[deviceId] === pid
|
||||
const refillUnit = pid && state.refillUnit?.[operatorId]?.[deviceId] === pid
|
||||
const langs = localeConfig.languages
|
||||
|
||||
const locale = {
|
||||
|
|
@ -119,6 +121,8 @@ function poll (req, res, next) {
|
|||
reboot,
|
||||
shutdown,
|
||||
restartServices,
|
||||
emptyUnit,
|
||||
refillUnit,
|
||||
hasLightning,
|
||||
receipt,
|
||||
operatorInfo,
|
||||
|
|
|
|||
34
lib/routes/unitsRoutes.js
Normal file
34
lib/routes/unitsRoutes.js
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
const express = require('express')
|
||||
const { emptyMachineUnits, refillMachineUnits } = require('../machine-loader')
|
||||
const router = express.Router()
|
||||
|
||||
const emptyUnitUpdateCounts = (req, res, next) => {
|
||||
const deviceId = req.deviceId
|
||||
const newUnits = req.body.newUnits
|
||||
|
||||
return emptyMachineUnits({ deviceId, cashUnits: newUnits })
|
||||
.then(() => res.sendStatus(200))
|
||||
.catch(e => {
|
||||
console.error(e)
|
||||
return res.sendStatus(500)
|
||||
})
|
||||
.finally(next)
|
||||
}
|
||||
|
||||
const refillUnitUpdateCounts = (req, res, next) => {
|
||||
const deviceId = req.deviceId
|
||||
const newUnits = req.body.newUnits
|
||||
|
||||
return refillMachineUnits({ deviceId, cashUnits: newUnits })
|
||||
.then(() => res.sendStatus(200))
|
||||
.catch(e => {
|
||||
console.error(e)
|
||||
return res.sendStatus(500)
|
||||
})
|
||||
.finally(next)
|
||||
}
|
||||
|
||||
router.post('/empty', emptyUnitUpdateCounts)
|
||||
router.post('/refill', refillUnitUpdateCounts)
|
||||
|
||||
module.exports = router
|
||||
|
|
@ -185,6 +185,42 @@ const MachineActions = memo(({ machine, onActionSuccess }) => {
|
|||
}}>
|
||||
Restart Services
|
||||
</ActionButton>
|
||||
{machine.model === 'aveiro' && (
|
||||
<ActionButton
|
||||
color="primary"
|
||||
className={classes.inlineChip}
|
||||
Icon={RebootIcon}
|
||||
InverseIcon={RebootReversedIcon}
|
||||
disabled={loading}
|
||||
onClick={() => {
|
||||
setAction({
|
||||
command: 'emptyUnit',
|
||||
display: 'Empty',
|
||||
message:
|
||||
"Triggering this action will move all cash inside the machine towards its cashbox (if possible), allowing for the collection of cash from the machine via only its cashbox. Depending on how full the cash units are, it's possible that this action will need to be used more than once to ensure that the unit is left completely empty."
|
||||
})
|
||||
}}>
|
||||
Empty Unit
|
||||
</ActionButton>
|
||||
)}
|
||||
{machine.model === 'aveiro' && (
|
||||
<ActionButton
|
||||
color="primary"
|
||||
className={classes.inlineChip}
|
||||
Icon={RebootIcon}
|
||||
InverseIcon={RebootReversedIcon}
|
||||
disabled={loading}
|
||||
onClick={() => {
|
||||
setAction({
|
||||
command: 'refillUnit',
|
||||
display: 'Refill',
|
||||
message:
|
||||
'Triggering this action will refill the stackers in this machine, by using bills present in its cassettes. This action may require manual operation of the cassettes and close attention to make sure that the denominations in the cassettes match the denominations in the stackers.'
|
||||
})
|
||||
}}>
|
||||
Refill Unit
|
||||
</ActionButton>
|
||||
)}
|
||||
</div>
|
||||
<ConfirmDialog
|
||||
disabled={disabled}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue