223 lines
6.7 KiB
JavaScript
223 lines
6.7 KiB
JavaScript
const constants = require('./constants')
|
|
const db = require('./db')
|
|
const _ = require('lodash/fp')
|
|
const uuid = require('uuid')
|
|
const camelize = require('./utils')
|
|
|
|
function createCashboxBatch(deviceId, cashboxCount) {
|
|
if (_.isEqual(0, cashboxCount))
|
|
throw new Error('Cash box is empty. Cash box batch could not be created.')
|
|
const sql = `INSERT INTO cash_unit_operation (id, device_id, created, operation_type) VALUES ($1, $2, now(), 'cash-box-empty') RETURNING *`
|
|
const sql2 = `
|
|
UPDATE bills SET cashbox_batch_id=$1
|
|
FROM cash_in_txs
|
|
WHERE bills.cash_in_txs_id = cash_in_txs.id AND
|
|
cash_in_txs.device_id = $2 AND
|
|
bills.destination_unit = 'cashbox' AND
|
|
bills.cashbox_batch_id IS NULL
|
|
`
|
|
const sql3 = `
|
|
UPDATE empty_unit_bills SET cashbox_batch_id=$1
|
|
WHERE empty_unit_bills.device_id = $2 AND empty_unit_bills.cashbox_batch_id IS NULL`
|
|
|
|
return db.tx(t => {
|
|
const batchId = uuid.v4()
|
|
const q1 = t.one(sql, [batchId, deviceId])
|
|
const q2 = t.none(sql2, [batchId, deviceId])
|
|
const q3 = t.none(sql3, [batchId, deviceId])
|
|
return t.batch([q1, q2, q3]).then(([it]) => it)
|
|
})
|
|
}
|
|
|
|
function updateMachineWithBatch(machineContext, oldCashboxCount) {
|
|
const cashUnits = machineContext.cashUnits
|
|
const cashUnitNames = [
|
|
'cashbox',
|
|
'cassette1',
|
|
'cassette2',
|
|
'cassette3',
|
|
'cassette4',
|
|
'recycler1',
|
|
'recycler2',
|
|
'recycler3',
|
|
'recycler4',
|
|
'recycler5',
|
|
'recycler6',
|
|
]
|
|
const isValidContext =
|
|
_.has(['deviceId', 'cashUnits'], machineContext) &&
|
|
_.has(cashUnitNames, cashUnits)
|
|
const cassettes = _.filter(it => !_.isNil(it))([
|
|
cashUnits.cassette1,
|
|
cashUnits.cassette2,
|
|
cashUnits.cassette3,
|
|
cashUnits.cassette4,
|
|
])
|
|
const isCassetteAmountWithinRange = _.inRange(
|
|
constants.CASH_OUT_MINIMUM_AMOUNT_OF_CASSETTES,
|
|
constants.CASH_OUT_MAXIMUM_AMOUNT_OF_CASSETTES + 1,
|
|
_.size(cassettes),
|
|
)
|
|
if (!isValidContext && !isCassetteAmountWithinRange)
|
|
throw new Error('Insufficient info to create a new cashbox batch')
|
|
if (_.isEqual(0, oldCashboxCount))
|
|
throw new Error('Cash box is empty. Cash box batch could not be created.')
|
|
|
|
return db.tx(t => {
|
|
const deviceId = machineContext.deviceId
|
|
const batchId = uuid.v4()
|
|
const q1 = t.none(
|
|
`INSERT INTO cash_unit_operation (id, device_id, created, operation_type) VALUES ($1, $2, now(), 'cash-box-empty')`,
|
|
[batchId, deviceId],
|
|
)
|
|
const q2 = t.none(
|
|
`UPDATE bills SET cashbox_batch_id=$1 FROM cash_in_txs
|
|
WHERE bills.cash_in_txs_id = cash_in_txs.id AND
|
|
cash_in_txs.device_id = $2 AND
|
|
bills.destination_unit = 'cashbox' AND
|
|
bills.cashbox_batch_id IS NULL`,
|
|
[batchId, deviceId],
|
|
)
|
|
const q3 = t.none(
|
|
`UPDATE empty_unit_bills SET cashbox_batch_id=$1
|
|
WHERE empty_unit_bills.device_id = $2 AND empty_unit_bills.cashbox_batch_id IS NULL`,
|
|
[batchId, deviceId],
|
|
)
|
|
const q4 = t.none(
|
|
`
|
|
UPDATE devices SET cassette1=$1, cassette2=$2, cassette3=$3, cassette4=$4,
|
|
recycler1=coalesce($5, recycler1), recycler2=coalesce($6, recycler2), recycler3=coalesce($7, recycler3),
|
|
recycler4=coalesce($8, recycler4), recycler5=coalesce($9, recycler5), recycler6=coalesce($10, recycler6) WHERE device_id=$11
|
|
`,
|
|
[
|
|
cashUnits.cassette1,
|
|
cashUnits.cassette2,
|
|
cashUnits.cassette3,
|
|
cashUnits.cassette4,
|
|
cashUnits.recycler1,
|
|
cashUnits.recycler2,
|
|
cashUnits.recycler3,
|
|
cashUnits.recycler4,
|
|
cashUnits.recycler5,
|
|
cashUnits.recycler6,
|
|
machineContext.deviceId,
|
|
],
|
|
)
|
|
|
|
return t.batch([q1, q2, q3, q4])
|
|
})
|
|
}
|
|
|
|
function getBatches(
|
|
from = new Date(0).toISOString(),
|
|
until = new Date().toISOString(),
|
|
) {
|
|
const sql = `
|
|
SELECT
|
|
cuo.id,
|
|
cuo.device_id,
|
|
cuo.created,
|
|
cuo.operation_type,
|
|
cuo.bill_count_override,
|
|
cuo.performed_by,
|
|
COUNT(bi.id) AS bill_count,
|
|
COALESCE(SUM(bi.fiat), 0) AS fiat_total
|
|
FROM cash_unit_operation AS cuo
|
|
LEFT JOIN (
|
|
SELECT b.id, b.fiat, b.fiat_code, b.created, b.cashbox_batch_id, cit.device_id AS device_id FROM bills b LEFT OUTER JOIN (SELECT id, device_id FROM cash_in_txs) AS cit ON cit.id = b.cash_in_txs_id UNION
|
|
SELECT id, fiat, fiat_code, created, cashbox_batch_id, device_id FROM empty_unit_bills
|
|
) AS bi ON cuo.id = bi.cashbox_batch_id
|
|
WHERE cuo.created >= $1 AND cuo.created <= $2 AND cuo.operation_type = 'cash-box-empty'
|
|
GROUP BY cuo.id, cuo.device_id, cuo.created, cuo.operation_type, cuo.bill_count_override, cuo.performed_by
|
|
ORDER BY cuo.created DESC
|
|
`
|
|
|
|
return db.any(sql, [from, until]).then(camelize)
|
|
}
|
|
|
|
function editBatchById(id, performedBy) {
|
|
const sql = `UPDATE cash_unit_operation SET performed_by=$1 WHERE id=$2 AND cuo.operation_type = 'cash-box-empty'`
|
|
return db.none(sql, [performedBy, id])
|
|
}
|
|
|
|
function logFormatter(data) {
|
|
return _.map(it => {
|
|
return {
|
|
id: it.id,
|
|
deviceId: it.deviceId,
|
|
created: it.created,
|
|
operationType: it.operationType,
|
|
billCount: it.billCount,
|
|
fiatTotal: it.fiatTotal,
|
|
}
|
|
}, data)
|
|
}
|
|
|
|
function getMachineUnbatchedBills(deviceId) {
|
|
const sql = `
|
|
SELECT now() AS created, cash_in_txs.device_id, json_agg(b.*) AS bills FROM bills b LEFT OUTER JOIN cash_in_txs
|
|
ON b.cash_in_txs_id = cash_in_txs.id
|
|
WHERE b.cashbox_batch_id IS NULL AND cash_in_txs.device_id = $1
|
|
GROUP BY cash_in_txs.device_id
|
|
`
|
|
|
|
return db
|
|
.oneOrNone(sql, [deviceId])
|
|
.then(res => _.mapKeys(it => _.camelCase(it), res))
|
|
.then(logFormatterSingle)
|
|
}
|
|
|
|
function getBatchById(id) {
|
|
const sql = `
|
|
SELECT cb.id, cb.device_id, cb.created, cb.operation_type, cb.bill_count_override, cb.performed_by, json_agg(b.*) AS bills
|
|
FROM cash_unit_operation AS cb
|
|
LEFT JOIN bills AS b ON cb.id = b.cashbox_batch_id
|
|
WHERE cb.id = $1
|
|
GROUP BY cb.id
|
|
`
|
|
|
|
return db
|
|
.oneOrNone(sql, [id])
|
|
.then(res => _.mapKeys(it => _.camelCase(it), res))
|
|
.then(logFormatterSingle)
|
|
}
|
|
|
|
function logFormatterSingle(data) {
|
|
const bills = _.filter(
|
|
it =>
|
|
!(
|
|
_.isNil(it) ||
|
|
_.isNil(it.fiat_code) ||
|
|
_.isNil(it.fiat) ||
|
|
_.isNaN(it.fiat)
|
|
),
|
|
data.bills,
|
|
)
|
|
|
|
return {
|
|
id: data.id,
|
|
deviceId: data.deviceId,
|
|
created: data.created,
|
|
operationType: data.operationType,
|
|
billCount: _.size(bills),
|
|
fiatTotals: _.reduce(
|
|
(acc, value) => {
|
|
acc[value.fiat_code] = (acc[value.fiat_code] || 0) + value.fiat
|
|
return acc
|
|
},
|
|
{},
|
|
bills,
|
|
),
|
|
billsByDenomination: _.countBy(it => `${it.fiat} ${it.fiat_code}`, bills),
|
|
}
|
|
}
|
|
|
|
module.exports = {
|
|
createCashboxBatch,
|
|
updateMachineWithBatch,
|
|
getBatches,
|
|
editBatchById,
|
|
getBatchById,
|
|
getMachineUnbatchedBills,
|
|
logFormatter,
|
|
}
|