diff --git a/lib/customers.js b/lib/customers.js index 2613165f..ae76e032 100644 --- a/lib/customers.js +++ b/lib/customers.js @@ -21,6 +21,8 @@ const NUM_RESULTS = 1000 const idPhotoCardBasedir = _.get('idPhotoCardDir', options) const frontCameraBaseDir = _.get('frontCameraDir', options) const operatorDataDir = _.get('operatorDataDir', options) +const sms = require('./sms') +const settingsLoader = require('./new-settings-loader') const TX_PASSTHROUGH_ERROR_CODES = ['operatorCancel'] @@ -117,13 +119,21 @@ async function updateCustomer (id, data, userToken) { const enhancedUpdateData = enhanceAtFields(enhanceOverrideFields(formattedData, userToken)) const updateData = updateOverride(enhancedUpdateData) - - const sql = Pgp.helpers.update(updateData, _.keys(updateData), 'customers') + + + if (!_.isEmpty(updateData)) { + const sql = Pgp.helpers.update(updateData, _.keys(updateData), 'customers') + ' where id=$1' + + await db.none(sql, [id]) + } + + if (data.subscriberInfo) { + Promise.all([getCustomerById(id), settingsLoader.loadLatest()]) + .then(([customer, config]) => sms.getLookup(config, customer.phone)) + .then(res => updateSubscriberData(id, res, userToken)) + .catch(console.error) + } invalidateCustomerNotifications(id, formattedData) - - await db.none(sql, [id]) - return getCustomerById(id) } @@ -134,6 +144,11 @@ const invalidateCustomerNotifications = (id, data) => { return notifierQueries.invalidateNotification(detailB, 'compliance') } +const updateSubscriberData = (customerId, data, userToken) => { + const sql = `UPDATE customers SET subscriber_info=$1, subscriber_info_at=now(), subscriber_info_by=$2 WHERE id=$3` + return db.none(sql, [data, userToken, customerId]) +} + /** * Get customer by id * @@ -508,7 +523,7 @@ function getCustomerById (id) { phone, sms_override, id_card_data, id_card_data_override, id_card_data_expiration, id_card_photo_path, id_card_photo_override, us_ssn, us_ssn_override, sanctions, sanctions_at, sanctions_override, total_txs, total_spent, created as last_active, fiat as last_tx_fiat, - fiat_code as last_tx_fiat_code, tx_class as last_tx_class + fiat_code as last_tx_fiat_code, tx_class as last_tx_class, subscriber_info from ( select c.id, c.authorized_override, greatest(0, date_part('day', c.suspended_until - now())) as days_suspended, @@ -516,7 +531,7 @@ function getCustomerById (id) { c.front_camera_path, c.front_camera_override, c.phone, c.sms_override, c.id_card_data, c.id_card_data_override, c.id_card_data_expiration, c.id_card_photo_path, c.id_card_photo_override, c.us_ssn, c.us_ssn_override, c.sanctions, - c.sanctions_at, c.sanctions_override, t.tx_class, t.fiat, t.fiat_code, t.created, + c.sanctions_at, c.sanctions_override, c.subscriber_info, t.tx_class, t.fiat, t.fiat_code, t.created, row_number() over (partition by c.id order by t.created desc) as rn, sum(case when t.id is not null then 1 else 0 end) over (partition by c.id) as total_txs, sum(case when error_code is null or error_code not in ($1^) then t.fiat else 0 end) over (partition by c.id) as total_spent diff --git a/lib/new-admin/graphql/types/customer.type.js b/lib/new-admin/graphql/types/customer.type.js index 8ee9cdeb..6b933489 100644 --- a/lib/new-admin/graphql/types/customer.type.js +++ b/lib/new-admin/graphql/types/customer.type.js @@ -28,6 +28,7 @@ const typeDef = gql` lastTxFiatCode: String lastTxClass: String transactions: [Transaction] + subscriberInfo: JSONObject } input CustomerInput { @@ -53,6 +54,7 @@ const typeDef = gql` lastTxFiatCode: String lastTxClass: String suspendedUntil: Date + subscriberInfo: Boolean } type Query { diff --git a/lib/plugins/sms/mock-sms/mock-sms.js b/lib/plugins/sms/mock-sms/mock-sms.js index 952fca3c..447180b8 100644 --- a/lib/plugins/sms/mock-sms/mock-sms.js +++ b/lib/plugins/sms/mock-sms/mock-sms.js @@ -1,8 +1,19 @@ const _ = require('lodash/fp') -exports.NAME = 'MockSMS' +const NAME = 'MockSMS' -exports.sendMessage = function sendMessage (account, rec) { +function getLookup (account, number) { + console.log('Looking up number: %j', number) + return new Promise((resolve, reject) => { + if (_.endsWith('666', number)) { + reject (new Error(`${exports.NAME} mocked error!`)) + } else { + setTimeout(resolve, 1) + } + }) +} + +function sendMessage (account, rec) { console.log('Sending SMS: %j', rec) return new Promise((resolve, reject) => { if (_.endsWith('666', _.getOr(false, 'sms.toNumber', rec))) { @@ -12,3 +23,9 @@ exports.sendMessage = function sendMessage (account, rec) { } }) } + +module.exports = { + NAME, + sendMessage, + getLookup +} diff --git a/lib/plugins/sms/twilio/twilio.js b/lib/plugins/sms/twilio/twilio.js index cedd6952..eb9fb0c4 100644 --- a/lib/plugins/sms/twilio/twilio.js +++ b/lib/plugins/sms/twilio/twilio.js @@ -37,7 +37,27 @@ function sendMessage (account, rec) { }) } +function getLookup (account, number) { + return Promise.resolve() + .then(() => { + const client = twilio(account.accountSid, account.authToken) + return client.lookups.v1.phoneNumbers(number) + .fetch({ addOns: ['lamassu_ekata'] }) + }) + .then(info => info.addOns.results['lamassu_ekata']) + .catch(err => { + if (_.includes(err.code, BAD_NUMBER_CODES)) { + const badNumberError = new Error(err.message) + badNumberError.name = 'BadNumberError' + throw badNumberError + } + + throw new Error(`Twilio error: ${err.message}`) + }) +} + module.exports = { NAME, - sendMessage + sendMessage, + getLookup } diff --git a/lib/sms.js b/lib/sms.js index f5474571..e5b3d4d5 100644 --- a/lib/sms.js +++ b/lib/sms.js @@ -12,4 +12,15 @@ function sendMessage (settings, rec) { }) } -module.exports = {sendMessage} +function getLookup (settings, number) { + return Promise.resolve() + .then(() => { + const pluginCode = argv.mockSms ? 'mock-sms' : 'twilio' + const plugin = ph.load(ph.SMS, pluginCode) + const account = settings.accounts[pluginCode] + + return plugin.getLookup(account, number) + }) +} + +module.exports = { sendMessage, getLookup } diff --git a/migrations/1628100660620-subscriber-info.js b/migrations/1628100660620-subscriber-info.js new file mode 100644 index 00000000..0a1f0eb0 --- /dev/null +++ b/migrations/1628100660620-subscriber-info.js @@ -0,0 +1,15 @@ +var db = require('./db') + +exports.up = function (next) { + var sql = [ + `ALTER TABLE customers ADD COLUMN subscriber_info JSON`, + `ALTER TABLE customers ADD COLUMN subscriber_info_at TIMESTAMPTZ`, + `ALTER TABLE customers ADD COLUMN subscriber_info_by UUID REFERENCES users(id)` + ] + + db.multi(sql, next) +} + +exports.down = function (next) { + next() +} diff --git a/new-lamassu-admin/src/pages/Customers/CustomerProfile.js b/new-lamassu-admin/src/pages/Customers/CustomerProfile.js index 94deb733..6649acd8 100644 --- a/new-lamassu-admin/src/pages/Customers/CustomerProfile.js +++ b/new-lamassu-admin/src/pages/Customers/CustomerProfile.js @@ -97,6 +97,7 @@ const SET_CUSTOMER = gql` lastTxFiat lastTxFiatCode lastTxClass + subscriberInfo } } ` @@ -202,6 +203,24 @@ const CustomerProfile = memo(() => { }> {`${blocked ? 'Authorize' : 'Block'} customer`} + + setCustomer({ + variables: { + customerId, + customerInput: { + subscriberInfo: true + } + } + }) + }> + {`Retrieve information`} + )}