Merge pull request #817 from josepfo/feat/sms-receipts
feat: toggle for sms receipt
This commit is contained in:
commit
c580f4cbf1
5 changed files with 146 additions and 3 deletions
|
|
@ -233,5 +233,6 @@ module.exports = {
|
||||||
updateNetworkPerformance,
|
updateNetworkPerformance,
|
||||||
updateNetworkHeartbeat,
|
updateNetworkHeartbeat,
|
||||||
getNetworkPerformance,
|
getNetworkPerformance,
|
||||||
getNetworkHeartbeat
|
getNetworkHeartbeat,
|
||||||
|
getConfig
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,9 @@
|
||||||
const express = require('express')
|
const express = require('express')
|
||||||
const router = express.Router()
|
const router = express.Router()
|
||||||
const semver = require('semver')
|
const semver = require('semver')
|
||||||
|
const sms = require('../sms')
|
||||||
const _ = require('lodash/fp')
|
const _ = require('lodash/fp')
|
||||||
|
const BN = require('../bn')
|
||||||
|
|
||||||
const compliance = require('../compliance')
|
const compliance = require('../compliance')
|
||||||
const complianceTriggers = require('../compliance-triggers')
|
const complianceTriggers = require('../compliance-triggers')
|
||||||
|
|
@ -11,6 +13,10 @@ const txs = require('../new-admin/services/transactions')
|
||||||
const httpError = require('../route-helpers').httpError
|
const httpError = require('../route-helpers').httpError
|
||||||
const notifier = require('../notifier')
|
const notifier = require('../notifier')
|
||||||
const respond = require('../respond')
|
const respond = require('../respond')
|
||||||
|
const { getTx } = require('../new-admin/services/transactions.js')
|
||||||
|
const { getCustomerById } = require('../customers')
|
||||||
|
const machineLoader = require('../machine-loader')
|
||||||
|
const { loadLatestConfig } = require('../new-settings-loader')
|
||||||
|
|
||||||
function updateCustomer (req, res, next) {
|
function updateCustomer (req, res, next) {
|
||||||
const id = req.params.id
|
const id = req.params.id
|
||||||
|
|
@ -116,11 +122,59 @@ function updateTxCustomerPhoto (req, res, next) {
|
||||||
.catch(next)
|
.catch(next)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function buildSms (data, receiptOptions) {
|
||||||
|
return Promise.all([getTx(data.session, data.txClass), loadLatestConfig()])
|
||||||
|
.then(([tx, config]) => {
|
||||||
|
return Promise.all([getCustomerById(tx.customer_id), machineLoader.getMachine(tx.device_id, config)])
|
||||||
|
.then(([customer, deviceConfig]) => {
|
||||||
|
const formattedTx = _.mapKeys(_.camelCase)(tx)
|
||||||
|
const localeConfig = configManager.getLocale(formattedTx.deviceId, config)
|
||||||
|
const timezone = localeConfig.timezone.split(':')
|
||||||
|
const dstOffset = timezone[1]
|
||||||
|
|
||||||
|
const cashInCommission = new BN(1).plus(new BN(formattedTx.commissionPercentage))
|
||||||
|
|
||||||
|
const rate = new BN(formattedTx.rawTickerPrice).multipliedBy(cashInCommission).decimalPlaces(2)
|
||||||
|
const date = new Date()
|
||||||
|
date.setMinutes(date.getMinutes() + parseInt(dstOffset))
|
||||||
|
const dateString = `${date.toISOString().replace('T', ' ').slice(0, 19)}`
|
||||||
|
|
||||||
|
const data = {
|
||||||
|
operatorInfo: configManager.getOperatorInfo(config),
|
||||||
|
location: deviceConfig.machineLocation,
|
||||||
|
customerName: customer.name,
|
||||||
|
customerPhone: customer.phone,
|
||||||
|
session: formattedTx.id,
|
||||||
|
time: dateString,
|
||||||
|
direction: formattedTx.direction === 'cashIn' ? 'Cash-in' : 'Cash-out',
|
||||||
|
fiat: `${formattedTx.fiat.toString()} ${formattedTx.fiatCode}`,
|
||||||
|
crypto: `${sms.toCryptoUnits(BN(formattedTx.cryptoAtoms), formattedTx.cryptoCode)} ${formattedTx.cryptoCode}`,
|
||||||
|
rate: `1 ${formattedTx.cryptoCode} = ${rate} ${formattedTx.fiatCode}`,
|
||||||
|
address: formattedTx.toAddress,
|
||||||
|
txId: formattedTx.txHash
|
||||||
|
}
|
||||||
|
|
||||||
|
return sms.formatSmsReceipt(data, receiptOptions)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function sendSmsReceipt (req, res, next) {
|
||||||
|
const receiptOptions = _.omit(['active', 'sms'], configManager.getReceipt(req.settings.config))
|
||||||
|
buildSms(req.body.data, receiptOptions)
|
||||||
|
.then(smsRequest => {
|
||||||
|
sms.sendMessage(req.settings, smsRequest)
|
||||||
|
.then(() => respond(req, res, {}))
|
||||||
|
.catch(next)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
router.patch('/:id', updateCustomer)
|
router.patch('/:id', updateCustomer)
|
||||||
router.patch('/:id/sanctions', triggerSanctions)
|
router.patch('/:id/sanctions', triggerSanctions)
|
||||||
router.patch('/:id/block', triggerBlock)
|
router.patch('/:id/block', triggerBlock)
|
||||||
router.patch('/:id/suspend', triggerSuspend)
|
router.patch('/:id/suspend', triggerSuspend)
|
||||||
router.patch('/:id/photos/idcarddata', updateIdCardData)
|
router.patch('/:id/photos/idcarddata', updateIdCardData)
|
||||||
router.patch('/:id/:txId/photos/customerphoto', updateTxCustomerPhoto)
|
router.patch('/:id/:txId/photos/customerphoto', updateTxCustomerPhoto)
|
||||||
|
router.patch('/:id/smsreceipt', sendSmsReceipt)
|
||||||
|
|
||||||
module.exports = router
|
module.exports = router
|
||||||
|
|
|
||||||
|
|
@ -73,6 +73,7 @@ function poll (req, res, next) {
|
||||||
locale,
|
locale,
|
||||||
version,
|
version,
|
||||||
receiptPrintingActive: receipt.active,
|
receiptPrintingActive: receipt.active,
|
||||||
|
smsReceiptActive: receipt.sms,
|
||||||
cassettes,
|
cassettes,
|
||||||
twoWayMode: cashOutConfig.active,
|
twoWayMode: cashOutConfig.active,
|
||||||
zeroConfLimits,
|
zeroConfLimits,
|
||||||
|
|
|
||||||
68
lib/sms.js
68
lib/sms.js
|
|
@ -1,5 +1,6 @@
|
||||||
const ph = require('./plugin-helper')
|
const ph = require('./plugin-helper')
|
||||||
const argv = require('minimist')(process.argv.slice(2))
|
const argv = require('minimist')(process.argv.slice(2))
|
||||||
|
const { utils: coinUtils } = require('lamassu-coins')
|
||||||
|
|
||||||
function getPlugin (settings) {
|
function getPlugin (settings) {
|
||||||
const pluginCode = argv.mockSms ? 'mock-sms' : 'twilio'
|
const pluginCode = argv.mockSms ? 'mock-sms' : 'twilio'
|
||||||
|
|
@ -24,5 +25,70 @@ function getLookup (settings, number) {
|
||||||
return plugin.getLookup(account, number)
|
return plugin.getLookup(account, number)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
const toCryptoUnits = (cryptoAtoms, cryptoCode) => {
|
||||||
|
const unitScale = coinUtils.getCryptoCurrency(cryptoCode).unitScale
|
||||||
|
return cryptoAtoms.shiftedBy(-unitScale)
|
||||||
|
}
|
||||||
|
|
||||||
module.exports = { sendMessage, getLookup }
|
function formatSmsReceipt (data, options) {
|
||||||
|
var message = `RECEIPT\n`
|
||||||
|
if (data.operatorInfo) {
|
||||||
|
message = message.concat(`Operator information:\n`)
|
||||||
|
if (data.operatorInfo.name) {
|
||||||
|
message = message.concat(`${data.operatorInfo.name}\n`)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data.operatorInfo.website && options.operatorWebsite) {
|
||||||
|
message = message.concat(`${data.operatorInfo.website}\n`)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data.operatorInfo.email && options.operatorEmail) {
|
||||||
|
message = message.concat(`${data.operatorInfo.email}\n`)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data.operatorInfo.phone && options.operatorPhone) {
|
||||||
|
message = message.concat(`${data.operatorInfo.phone}\n`)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data.operatorInfo.companyNumber && options.companyNumber) {
|
||||||
|
message = message.concat(`${data.operatorInfo.companyNumber}\n`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (data.location && options.machineLocation) {
|
||||||
|
message = message.concat(`Location: ${data.location}\n`)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (options.customerNameOrPhoneNumber) {
|
||||||
|
if (data.customerName) {
|
||||||
|
message = message.concat(`Customer: ${data.customerName}\n`)
|
||||||
|
} else {
|
||||||
|
message = message.concat(`Customer: ${data.customerPhone}\n`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
message = message.concat(`Session: ${data.session}\n`)
|
||||||
|
message = message.concat(`Time: ${data.time}\n`)
|
||||||
|
message = message.concat(`Direction: ${data.direction}\n`)
|
||||||
|
message = message.concat(`Fiat: ${data.fiat}\n`)
|
||||||
|
message = message.concat(`Crypto: ${data.crypto}\n`)
|
||||||
|
|
||||||
|
if (data.rate && options.exchangeRate) {
|
||||||
|
message = message.concat(`Rate: ${data.rate}\n`)
|
||||||
|
}
|
||||||
|
|
||||||
|
message = message.concat(`TXID: ${data.txId}\n`)
|
||||||
|
|
||||||
|
if (data.address && options.addressQRCode) {
|
||||||
|
message = message.concat(`Address: ${data.address}\n`)
|
||||||
|
}
|
||||||
|
|
||||||
|
const request = {
|
||||||
|
sms: {
|
||||||
|
toNumber: data.customerPhone,
|
||||||
|
body: message
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return request
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = { sendMessage, formatSmsReceipt, getLookup, toCryptoUnits }
|
||||||
|
|
|
||||||
|
|
@ -49,7 +49,7 @@ const ReceiptPrinting = memo(({ wizard }) => {
|
||||||
<H4>Receipt options</H4>
|
<H4>Receipt options</H4>
|
||||||
</div>
|
</div>
|
||||||
<div className={classes.switchRow}>
|
<div className={classes.switchRow}>
|
||||||
<P>Enable receipt printing?</P>
|
<P>Enable receipt printing</P>
|
||||||
<div className={classes.switch}>
|
<div className={classes.switch}>
|
||||||
<Switch
|
<Switch
|
||||||
checked={receiptPrintingConfig.active}
|
checked={receiptPrintingConfig.active}
|
||||||
|
|
@ -69,6 +69,27 @@ const ReceiptPrinting = memo(({ wizard }) => {
|
||||||
<Label2>{receiptPrintingConfig.active ? 'Yes' : 'No'}</Label2>
|
<Label2>{receiptPrintingConfig.active ? 'Yes' : 'No'}</Label2>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div className={classes.switchRow}>
|
||||||
|
<P>Offer SMS receipt</P>
|
||||||
|
<div className={classes.switch}>
|
||||||
|
<Switch
|
||||||
|
checked={receiptPrintingConfig.sms}
|
||||||
|
onChange={event =>
|
||||||
|
saveConfig({
|
||||||
|
variables: {
|
||||||
|
config: toNamespace(
|
||||||
|
namespaces.RECEIPT,
|
||||||
|
R.merge(receiptPrintingConfig, {
|
||||||
|
sms: event.target.checked
|
||||||
|
})
|
||||||
|
)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
<Label2>{receiptPrintingConfig.sms ? 'Yes' : 'No'}</Label2>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<BooleanPropertiesTable
|
<BooleanPropertiesTable
|
||||||
editing={wizard}
|
editing={wizard}
|
||||||
title={'Visible on the receipt (options)'}
|
title={'Visible on the receipt (options)'}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue