Customer detail page changes

* Refactor code regarding override fields
 * Add *_override_at columns in customer table (migration)
 * Add *_override_at, *_override_by computed fields
   when updating customer
 * Rename compliance types to match override fields (migration)
 * Remove cross_ref compliance_type (migrations)
 * Populate customer object with usernames for every
   filled *_override_by field (users API)
This commit is contained in:
goga-m 2017-09-29 20:14:40 +03:00 committed by Josh Harvey
parent 409269d23d
commit 84bc84e7c1
3 changed files with 94 additions and 63 deletions

View file

@ -7,6 +7,7 @@ const NUM_RESULTS = 20
const camelize = require('camelize') const camelize = require('camelize')
const Pgp = require('pg-promise')() const Pgp = require('pg-promise')()
const complianceOverrides = require('./compliance_overrides') const complianceOverrides = require('./compliance_overrides')
const users = require('./users')
function add (customer) { function add (customer) {
const sql = 'insert into customers (id, phone, phone_at) values ($1, $2, now()) returning *' const sql = 'insert into customers (id, phone, phone_at) values ($1, $2, now()) returning *'
@ -38,18 +39,20 @@ function get (phone) {
*/ */
function update (id, data, userToken) { function update (id, data, userToken) {
const formattedData = _.omit(['id'], _.mapKeys(_.snakeCase, data)) const formattedData = _.omit(['id'], _.mapKeys(_.snakeCase, data))
const updateData = addOverrideUser(formattedData, userToken) const updateData = enhanceOverrideFields(formattedData, userToken)
addComplianceOverrides(id, updateData, userToken)
const sql = Pgp.helpers.update(updateData, _.keys(updateData), 'customers') + const sql = Pgp.helpers.update(updateData, _.keys(updateData), 'customers') +
' where id=$1 returning *' ' where id=$1 returning *'
return db.one(sql, [id]) return db.one(sql, [id])
.then(customer => customer ? format(customer) : null) .then(addComplianceOverrides(id, updateData, userToken))
.then(populateOverrideUsernames)
.then(format)
} }
function getById (id) { function getById (id, userToken) {
const sql = 'select * from customers where id=$1' const sql = 'select * from customers where id=$1'
return db.oneOrNone(sql, [id]) return db.oneOrNone(sql, [id])
.then(customer => customer ? format(customer) : null) .then(populateOverrideUsernames)
.then(format)
} }
function getDailyVolume (id) { function getDailyVolume (id) {
@ -66,29 +69,45 @@ function getDailyVolume (id) {
} }
/** /**
* Add *override_by fields with acting user's token * Get all available complianceTypes
* that can be overriden (excluding hard_limit)
* *
* @name addOverrideUser * @name getComplianceTypes
* @function * @function
* *
* @param {object} customer Customer's object to add the fields * @returns {array} Array of compliance types' names
* @param {string} userToken Acting user's token
* @returns {object} Customer populated with *_by fields
*/ */
function addOverrideUser (customer, userToken) { function getComplianceTypes () {
if (!userToken) return customer return [
// Overrode fields 'sms',
const overrideFields = [ 'id_card_data',
'sms_override', 'id_card_photo',
'id_card_data_override', 'front_facing_cam',
'id_card_photo_override', 'sanctions_check',
'front_facing_cam_override', 'authorized' ]
'sanctions_check_override', }
'authorized_override' ]
overrideFields.forEach(field => { /**
if (customer[field]) customer[field + '_by'] = userToken * Add *override_by and *override_at fields with acting user's token
}) * and date of override respectively before saving to db.
return customer *
* @name enhanceOverrideFields
* @function
*
* @param {object} fields Override fields to be enhanced
* @param {string} userToken Acting user's token
* @returns {object} fields enhanced with *_by and *_at fields
*/
function enhanceOverrideFields (fields, userToken) {
if (!userToken) return fields
// Populate with computedFields (user who overrode and overriden timestamps date)
_.each(field => {
if (fields[field + '_override']) {
fields[field + '_override_by'] = userToken
fields[field + '_override_at'] = new Date().toISOString()
}
}, getComplianceTypes())
return fields
} }
/** /**
@ -107,52 +126,33 @@ function addOverrideUser (customer, userToken) {
* @returns {promise} Result from compliance_overrides creation * @returns {promise} Result from compliance_overrides creation
*/ */
function addComplianceOverrides (id, customer, userToken) { function addComplianceOverrides (id, customer, userToken) {
// Compliance override field mappings
const overrideFields = [{
name: 'sms_override',
complianceType: 'sms'
}, {
name: 'id_card_data_override',
complianceType: 'id_card_data'
}, {
name: 'id_card_photo_override',
complianceType: 'id_card_photo'
}, {
name: 'front_facing_cam_override',
complianceType: 'front_camera'
}, {
name: 'sanctions_check_override',
complianceType: 'sanctions'
}, {
name: 'authorized_override',
complianceType: 'authorized'
}]
// Prepare compliance overrides to save // Prepare compliance overrides to save
const overrides = _.map(field => { const overrides = _.map(field => {
return (customer[field.name]) ? { const complianceName = field + '_override'
return (customer[complianceName]) ? {
customerId: id, customerId: id,
complianceType: field.complianceType, complianceType: field,
overrideBy: userToken, overrideBy: userToken,
verification: customer[field.name] verification: customer[complianceName]
} : null } : null
}, overrideFields) }, getComplianceTypes())
// Save all the updated compliance override fields // Save all the updated override fields
return Promise.all(_.compact(overrides) return Promise.all(_.map(complianceOverrides.add, _.compact(overrides)))
.map(override => complianceOverrides.add(override)))
} }
/** /**
* Format and populate fields * Format and populate fields
* for customer record * for customer record
* *
* @function format * @name format
* @function
* *
* @param {object} Customer object * @param {object} Customer object
* @returns {object} Customer camelized & populated with computed fields * @returns {object} Customer camelized & populated with computed fields
*/ */
function format (customer) { function format (customer) {
if (!customer) return null
/** /**
* Populate with status field * Populate with status field
* *
@ -174,6 +174,31 @@ function format (customer) {
return camelize(customer) return camelize(customer)
} }
/**
* Populate the customer object with user names
* only for those override fields that contain
* *override_by values (user token references)
*
* @name populateOverrideUsernames
* @function
*
* @param {object} customer Customer object to populate
* @returns {promise} Customer with populated *by_name fields
*/
function populateOverrideUsernames (customer) {
return Promise.all(_.map(field => {
if (customer[field + '_override_by']) {
return users.get(customer[field + '_override_by'])
.then(user => {
// just add the name to the customer object
customer[field + '_override_by_name'] = user.name
return null
})
} else return null
}, getComplianceTypes()))
.then(() => customer)
}
/** /**
* Query all customers * Query all customers
* *
@ -191,4 +216,4 @@ function batch () {
.then(_.map(format)) .then(_.map(format))
} }
module.exports = { add, get, batch, getById, update} module.exports = { add, get, batch, getById, update }

View file

@ -13,7 +13,7 @@ exports.up = function (next) {
* @see {@link http://blog.yo1.dog/updating-enum-values-in-postgresql-the-safe-and-easy-way/} * @see {@link http://blog.yo1.dog/updating-enum-values-in-postgresql-the-safe-and-easy-way/}
*/ */
`create type compliance_type as enum `create type compliance_type as enum
('authorized', 'sms', 'id_card_data', 'id_card_photo', 'sanctions', 'cross_ref', 'front_camera', 'hard_limit')`, ('authorized', 'sms', 'id_card_data', 'id_card_photo', 'sanctions_check', 'front_facing_cam', 'hard_limit')`,
'alter table compliance_authorizations alter column compliance_type set data type compliance_type using compliance_type::text::compliance_type', 'alter table compliance_authorizations alter column compliance_type set data type compliance_type using compliance_type::text::compliance_type',
'drop type compliance_types', 'drop type compliance_types',
@ -21,17 +21,23 @@ exports.up = function (next) {
'alter table customers drop column manually_verified ', 'alter table customers drop column manually_verified ',
"alter table customers add column sms_override verification_type not null default 'automatic'", "alter table customers add column sms_override verification_type not null default 'automatic'",
'alter table customers add column sms_override_by references user_tokens (token)', 'alter table customers add column sms_override_by text references user_tokens (token)',
'alter table customers add column sms_override_at timestamptz',
"alter table customers add column id_card_data_override verification_type not null default 'automatic'", "alter table customers add column id_card_data_override verification_type not null default 'automatic'",
'alter table customers add column id_card_data_override_by references user_tokens (token)', 'alter table customers add column id_card_data_override_by text references user_tokens (token)',
'alter table customers add column id_card_data_override_at timestamptz',
"alter table customers add column id_card_photo_override verification_type not null default 'automatic'", "alter table customers add column id_card_photo_override verification_type not null default 'automatic'",
'alter table customers add column id_card_photo_override_by references user_tokens (token)', 'alter table customers add column id_card_photo_override_by text references user_tokens (token)',
'alter table customers add column id_card_photo_override_at timestamptz',
"alter table customers add column front_facing_cam_override verification_type not null default 'automatic'", "alter table customers add column front_facing_cam_override verification_type not null default 'automatic'",
'alter table customers add column front_facing_cam_override_by references user_tokens (token)', 'alter table customers add column front_facing_cam_override_by text references user_tokens (token)',
'alter table customers add column front_facing_cam_override_at timestamptz',
"alter table customers add column sanctions_check_override verification_type not null default 'automatic'", "alter table customers add column sanctions_check_override verification_type not null default 'automatic'",
'alter table customers add column sanctions_check_override_by references user_tokens (token)', 'alter table customers add column sanctions_check_override_by text references user_tokens (token)',
'alter table customers add column sanctions_check_override_at timestamptz',
"alter table customers add column authorized_override verification_type not null default 'automatic'", "alter table customers add column authorized_override verification_type not null default 'automatic'",
'alter table customers add column authorized_override_by references user_tokens (token)', 'alter table customers add column authorized_override_by text references user_tokens (token)',
'alter table customers add column authorized_override_at timestamptz',
'alter table customers add column authorized_at timestamptz', 'alter table customers add column authorized_at timestamptz',
'alter table customers add column sanctions_check_at timestamptz', 'alter table customers add column sanctions_check_at timestamptz',

View file

@ -38298,12 +38298,12 @@ var _user$project$Customer_View$customerActions = F2(
{ {
ctor: '::', ctor: '::',
_0: _elm_lang$html$Html_Events$onClick( _0: _elm_lang$html$Html_Events$onClick(
A3(_user$project$Customer_Types$PatchCustomer, id, 'authorizedOverride', 'automatic')), A3(_user$project$Customer_Types$PatchCustomer, id, 'authorizedOverride', 'blocked')),
_1: {ctor: '[]'} _1: {ctor: '[]'}
}, },
{ {
ctor: '::', ctor: '::',
_0: _elm_lang$html$Html$text('Unblock'), _0: _elm_lang$html$Html$text('Block'),
_1: {ctor: '[]'} _1: {ctor: '[]'}
}); });
} }