Merge pull request #1694 from siiky/feat/lam-1111/customer-last-used-machine
LAM-1111 View last-used machine name on customer profile
This commit is contained in:
commit
6274bccde5
8 changed files with 39 additions and 17 deletions
|
|
@ -562,13 +562,13 @@ function getCustomerById (id) {
|
||||||
phone, phone_at, email, email_at, phone_override, sms_override, id_card_data_at, id_card_data, id_card_data_override, id_card_data_expiration,
|
phone, phone_at, email, email_at, phone_override, sms_override, id_card_data_at, id_card_data, id_card_data_override, id_card_data_expiration,
|
||||||
id_card_photo_path, id_card_photo_at, id_card_photo_override, us_ssn_at, us_ssn, us_ssn_override, sanctions, sanctions_at,
|
id_card_photo_path, id_card_photo_at, id_card_photo_override, us_ssn_at, us_ssn, us_ssn_override, sanctions, sanctions_at,
|
||||||
sanctions_override, total_txs, total_spent, GREATEST(created, last_transaction, last_auth_attempt, last_data_provided) AS last_active, fiat AS last_tx_fiat,
|
sanctions_override, total_txs, total_spent, GREATEST(created, last_transaction, last_auth_attempt, last_data_provided) AS last_active, fiat AS last_tx_fiat,
|
||||||
fiat_code AS last_tx_fiat_code, tx_class AS last_tx_class, subscriber_info, subscriber_info_at, custom_fields, notes, is_test_customer
|
fiat_code AS last_tx_fiat_code, tx_class AS last_tx_class, subscriber_info, subscriber_info_at, custom_fields, notes, is_test_customer, last_used_machine
|
||||||
FROM (
|
FROM (
|
||||||
SELECT c.id, c.authorized_override,
|
SELECT c.id, c.authorized_override,
|
||||||
greatest(0, date_part('day', c.suspended_until - now())) AS days_suspended,
|
greatest(0, date_part('day', c.suspended_until - now())) AS days_suspended,
|
||||||
GREATEST(c.phone_at, c.email_at, c.id_card_data_at, c.front_camera_at, c.id_card_photo_at, c.us_ssn_at) AS last_data_provided,
|
GREATEST(c.phone_at, c.email_at, c.id_card_data_at, c.front_camera_at, c.id_card_photo_at, c.us_ssn_at) AS last_data_provided,
|
||||||
c.suspended_until > now() AS is_suspended,
|
c.suspended_until > now() AS is_suspended,
|
||||||
c.front_camera_path, c.front_camera_override, c.front_camera_at, c.last_auth_attempt,
|
c.front_camera_path, c.front_camera_override, c.front_camera_at, c.last_auth_attempt, c.last_used_machine,
|
||||||
c.phone, c.phone_at, c.email, c.email_at, c.phone_override, c.sms_override, c.id_card_data, c.id_card_data_at, c.id_card_data_override, c.id_card_data_expiration,
|
c.phone, c.phone_at, c.email, c.email_at, c.phone_override, c.sms_override, c.id_card_data, c.id_card_data_at, c.id_card_data_override, c.id_card_data_expiration,
|
||||||
c.id_card_photo_path, c.id_card_photo_at, c.id_card_photo_override, c.us_ssn, c.us_ssn_at, c.us_ssn_override, c.sanctions,
|
c.id_card_photo_path, c.id_card_photo_at, c.id_card_photo_override, c.us_ssn, c.us_ssn_at, c.us_ssn_override, c.sanctions,
|
||||||
c.sanctions_at, c.sanctions_override, c.subscriber_info, c.subscriber_info_at, c.is_test_customer, c.created, t.tx_class, t.fiat, t.fiat_code, t.created as last_transaction, cn.notes,
|
c.sanctions_at, c.sanctions_override, c.subscriber_info, c.subscriber_info_at, c.is_test_customer, c.created, t.tx_class, t.fiat, t.fiat_code, t.created as last_transaction, cn.notes,
|
||||||
|
|
@ -724,11 +724,11 @@ function updatePhotoCard (id, patch) {
|
||||||
|
|
||||||
function updatePhotos (imagesData, id, dir) {
|
function updatePhotos (imagesData, id, dir) {
|
||||||
return Promise.resolve(imagesData)
|
return Promise.resolve(imagesData)
|
||||||
.then(patch => {
|
.then(imagesData => {
|
||||||
if (_.isEmpty(imagesData)) {
|
|
||||||
return patch
|
|
||||||
}
|
|
||||||
const newPatch = {}
|
const newPatch = {}
|
||||||
|
if (_.isEmpty(imagesData)) {
|
||||||
|
return newPatch
|
||||||
|
}
|
||||||
// i.e. ../<lamassu-server-home>/<operatorid>/<customerid>/idcarddata
|
// i.e. ../<lamassu-server-home>/<operatorid>/<customerid>/idcarddata
|
||||||
const dirname = path.join(dir)
|
const dirname = path.join(dir)
|
||||||
// create the directory tree if needed
|
// create the directory tree if needed
|
||||||
|
|
@ -764,7 +764,6 @@ function updateIdCardData (patch, id) {
|
||||||
.then(patch => {
|
.then(patch => {
|
||||||
const imagesData = _.get('photos', patch)
|
const imagesData = _.get('photos', patch)
|
||||||
return updatePhotos(imagesData, id, directory)
|
return updatePhotos(imagesData, id, directory)
|
||||||
.then(newPatch => newPatch)
|
|
||||||
.catch(err => logger.error('while saving the image: ', err))
|
.catch(err => logger.error('while saving the image: ', err))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
@ -931,9 +930,9 @@ function disableTestCustomer (customerId) {
|
||||||
return db.none(sql, [customerId])
|
return db.none(sql, [customerId])
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateLastAuthAttempt (customerId) {
|
function updateLastAuthAttempt (customerId, deviceId) {
|
||||||
const sql = `UPDATE customers SET last_auth_attempt=NOW() WHERE id=$1`
|
const sql = `UPDATE customers SET last_auth_attempt=NOW(), last_used_machine=$2 WHERE id=$1`
|
||||||
return db.none(sql, [customerId])
|
return db.none(sql, [customerId, deviceId])
|
||||||
}
|
}
|
||||||
|
|
||||||
function getExternalComplianceMachine (customer) {
|
function getExternalComplianceMachine (customer) {
|
||||||
|
|
|
||||||
|
|
@ -148,7 +148,7 @@ function getMachineNames (config) {
|
||||||
* @returns {string} machine name
|
* @returns {string} machine name
|
||||||
*/
|
*/
|
||||||
function getMachineName (machineId) {
|
function getMachineName (machineId) {
|
||||||
const sql = 'SELECT * FROM devices WHERE device_id=$1'
|
const sql = 'SELECT name FROM devices WHERE device_id=$1'
|
||||||
return db.oneOrNone(sql, [machineId])
|
return db.oneOrNone(sql, [machineId])
|
||||||
.then(it => it.name)
|
.then(it => it.name)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,15 +3,19 @@ const anonymous = require('../../../constants').anonymousCustomer
|
||||||
const customers = require('../../../customers')
|
const customers = require('../../../customers')
|
||||||
const filters = require('../../filters')
|
const filters = require('../../filters')
|
||||||
const customerNotes = require('../../../customer-notes')
|
const customerNotes = require('../../../customer-notes')
|
||||||
|
const machineLoader = require('../../../machine-loader')
|
||||||
|
|
||||||
|
const addLastUsedMachineName = customer =>
|
||||||
|
(customer.lastUsedMachine ? machineLoader.getMachineName(customer.lastUsedMachine) : Promise.resolve(null))
|
||||||
|
.then(lastUsedMachineName => Object.assign(customer, { lastUsedMachineName }))
|
||||||
|
|
||||||
const resolvers = {
|
const resolvers = {
|
||||||
|
|
||||||
Customer: {
|
Customer: {
|
||||||
isAnonymous: parent => (parent.customerId === anonymous.uuid)
|
isAnonymous: parent => (parent.customerId === anonymous.uuid)
|
||||||
},
|
},
|
||||||
Query: {
|
Query: {
|
||||||
customers: (...[, { phone, email, name, address, id }]) => customers.getCustomersList(phone, name, address, id, email),
|
customers: (...[, { phone, email, name, address, id }]) => customers.getCustomersList(phone, name, address, id, email),
|
||||||
customer: (...[, { customerId }]) => customers.getCustomerById(customerId),
|
customer: (...[, { customerId }]) => customers.getCustomerById(customerId).then(addLastUsedMachineName),
|
||||||
customerFilters: () => filters.customer()
|
customerFilters: () => filters.customer()
|
||||||
},
|
},
|
||||||
Mutation: {
|
Mutation: {
|
||||||
|
|
|
||||||
|
|
@ -33,6 +33,8 @@ const typeDef = gql`
|
||||||
lastTxFiat: String
|
lastTxFiat: String
|
||||||
lastTxFiatCode: String
|
lastTxFiatCode: String
|
||||||
lastTxClass: String
|
lastTxClass: String
|
||||||
|
lastUsedMachine: String
|
||||||
|
lastUsedMachineName: String
|
||||||
transactions: [Transaction]
|
transactions: [Transaction]
|
||||||
subscriberInfo: JSONObject
|
subscriberInfo: JSONObject
|
||||||
phoneOverride: String
|
phoneOverride: String
|
||||||
|
|
|
||||||
|
|
@ -257,7 +257,7 @@ function getExternalComplianceLink (req, res, next) {
|
||||||
.then(url => respond(req, res, { url }))
|
.then(url => respond(req, res, { url }))
|
||||||
}
|
}
|
||||||
|
|
||||||
function addOrUpdateCustomer (customerData, config, isEmailAuth) {
|
function addOrUpdateCustomer (customerData, deviceId, config, isEmailAuth) {
|
||||||
const triggers = configManager.getTriggers(config)
|
const triggers = configManager.getTriggers(config)
|
||||||
const maxDaysThreshold = complianceTriggers.maxDaysThreshold(triggers)
|
const maxDaysThreshold = complianceTriggers.maxDaysThreshold(triggers)
|
||||||
|
|
||||||
|
|
@ -273,7 +273,7 @@ function addOrUpdateCustomer (customerData, config, isEmailAuth) {
|
||||||
})
|
})
|
||||||
.then(customer => customers.getById(customer.id))
|
.then(customer => customers.getById(customer.id))
|
||||||
.then(customer => {
|
.then(customer => {
|
||||||
customers.updateLastAuthAttempt(customer.id).catch(() => {
|
customers.updateLastAuthAttempt(customer.id, deviceId).catch(() => {
|
||||||
logger.info('failure updating last auth attempt for customer ', customer.id)
|
logger.info('failure updating last auth attempt for customer ', customer.id)
|
||||||
})
|
})
|
||||||
return customer
|
return customer
|
||||||
|
|
@ -292,14 +292,15 @@ function addOrUpdateCustomer (customerData, config, isEmailAuth) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function getOrAddCustomerPhone (req, res, next) {
|
function getOrAddCustomerPhone (req, res, next) {
|
||||||
|
const deviceId = req.deviceId
|
||||||
const customerData = req.body
|
const customerData = req.body
|
||||||
|
|
||||||
const pi = plugins(req.settings, req.deviceId)
|
const pi = plugins(req.settings, deviceId)
|
||||||
const phone = req.body.phone
|
const phone = req.body.phone
|
||||||
|
|
||||||
return pi.getPhoneCode(phone)
|
return pi.getPhoneCode(phone)
|
||||||
.then(code => {
|
.then(code => {
|
||||||
return addOrUpdateCustomer(customerData, req.settings.config, false)
|
return addOrUpdateCustomer(customerData, deviceId, req.settings.config, false)
|
||||||
.then(customer => respond(req, res, { code, customer }))
|
.then(customer => respond(req, res, { code, customer }))
|
||||||
})
|
})
|
||||||
.catch(err => {
|
.catch(err => {
|
||||||
|
|
|
||||||
9
migrations/1721313145136-customer-last-used-machine.js
Normal file
9
migrations/1721313145136-customer-last-used-machine.js
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
const db = require('./db')
|
||||||
|
|
||||||
|
exports.up = function (next) {
|
||||||
|
db.multi(['ALTER TABLE customers ADD COLUMN last_used_machine TEXT REFERENCES devices (device_id)'], next)
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.down = function (next) {
|
||||||
|
next()
|
||||||
|
}
|
||||||
|
|
@ -74,6 +74,7 @@ const GET_CUSTOMER = gql`
|
||||||
totalTxs
|
totalTxs
|
||||||
totalSpent
|
totalSpent
|
||||||
lastActive
|
lastActive
|
||||||
|
lastUsedMachineName
|
||||||
lastTxFiat
|
lastTxFiat
|
||||||
lastTxFiatCode
|
lastTxFiatCode
|
||||||
lastTxClass
|
lastTxClass
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@ const TransactionsList = ({ customer, data, loading }) => {
|
||||||
const classes = useStyles()
|
const classes = useStyles()
|
||||||
const LastTxIcon = customer.lastTxClass === 'cashOut' ? TxOutIcon : TxInIcon
|
const LastTxIcon = customer.lastTxClass === 'cashOut' ? TxOutIcon : TxInIcon
|
||||||
const hasData = !(R.isEmpty(data) || R.isNil(data))
|
const hasData = !(R.isEmpty(data) || R.isNil(data))
|
||||||
|
const { lastUsedMachineName } = customer
|
||||||
|
|
||||||
const timezone = Intl.DateTimeFormat().resolvedOptions().timeZone
|
const timezone = Intl.DateTimeFormat().resolvedOptions().timeZone
|
||||||
const tableSpacingClasses = {
|
const tableSpacingClasses = {
|
||||||
|
|
@ -65,6 +66,11 @@ const TransactionsList = ({ customer, data, loading }) => {
|
||||||
${customer.lastTxFiatCode}`}
|
${customer.lastTxFiatCode}`}
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
header: 'Last used machine',
|
||||||
|
size: 198,
|
||||||
|
value: ifNotNull(lastUsedMachineName, <>{lastUsedMachineName}</>)
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue