lamassu-server/lib/customers.js

194 lines
5.3 KiB
JavaScript

const db = require('./db')
const uuid = require('uuid')
const _ = require('lodash/fp')
const BN = require('./bn')
const anonymous = require('../lib/constants').anonymousCustomer
const NUM_RESULTS = 20
const camelize = require('camelize')
const Pgp = require('pg-promise')()
const complianceOverrides = require('./compliance_overrides')
function add (customer) {
const sql = 'insert into customers (id, phone, phone_at) values ($1, $2, now()) returning *'
return db.one(sql, [uuid.v4(), customer.phone])
}
function get (phone) {
const sql = 'select id, phone from customers where phone=$1'
return db.oneOrNone(sql, [phone])
.then(customer => {
if (!customer) return
return getDailyVolume(customer.id).then(dailyVolume => {
return _.set('dailyVolume', dailyVolume, customer)
})
})
}
/**
* Update customer record
*
* @name update
* @function
*
* @param {string} id Customer's id
* @param {object} data Fields to update
* @param {string} Acting user's token
*
* @returns {Promise} Newly updated Customer
*/
function update (id, data, userToken) {
const formattedData = _.omit(['id'], _.mapKeys(_.snakeCase, data))
const updateData = addOverrideUser(formattedData, userToken)
addComplianceOverrides(id, updateData, userToken)
const sql = Pgp.helpers.update(updateData, _.keys(updateData), 'customers') +
' where id=$1 returning *'
return db.one(sql, [id])
.then(customer => customer ? format(customer) : null)
}
function getById (id) {
const sql = 'select * from customers where id=$1'
return db.oneOrNone(sql, [id])
.then(customer => customer ? format(customer) : null)
}
function getDailyVolume (id) {
return Promise.all([
db.one(`select coalesce(sum(fiat), 0) as total from cash_in_txs
where customer_id=$1
and created > now() - interval '1 day'`, [id]),
db.one(`select coalesce(sum(fiat), 0) as total from cash_out_txs
where customer_id=$1
and created > now() - interval '1 day'`, [id])
]).then(([cashInTotal, cashOutTotal]) => {
return BN(cashInTotal.total).add(cashOutTotal.total)
})
}
/**
* Add *override_by fields with acting user's token
*
* @name addOverrideUser
* @function
*
* @param {object} customer Customer's object to add the fields
* @param {string} userToken Acting user's token
* @returns {object} Customer populated with *_by fields
*/
function addOverrideUser (customer, userToken) {
if (!userToken) return customer
// Overrode fields
const overrideFields = [
'sms_override',
'id_card_data_override',
'id_card_photo_override',
'front_facing_cam_override',
'sanctions_check_override',
'authorized_override' ]
overrideFields.forEach(field => {
if (customer[field]) customer[field + '_by'] = userToken
})
return customer
}
/**
* Save new compliance override records
*
* Take the override fields that are modified in customer and create
* a compliance override record in db for each compliance type.
*
* @name addComplianceOverrides
* @function
*
* @param {string} id Customer's id
* @param {object} customer Customer that is updating
* @param {string} userToken Acting user's token
*
* @returns {promise} Result from compliance_overrides creation
*/
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
const overrides = _.map(field => {
return (customer[field.name]) ? {
customerId: id,
complianceType: field.complianceType,
overrideBy: userToken,
verification: customer[field.name]
} : null
}, overrideFields)
// Save all the updated compliance override fields
return Promise.all(_.compact(overrides)
.map(override => complianceOverrides.add(override)))
}
/**
* Format and populate fields
* for customer record
*
* @function format
*
* @param {object} Customer object
* @returns {object} Customer camelized & populated with computed fields
*/
function format (customer) {
/**
* Populate with status field
*
*/
const status = _.maxBy('value', [{
label: 'Phone',
value: customer.phone_at
}, {
label: 'ID card',
value: customer.id_card_at
}, {
label: 'Front facing camera',
value: customer.front_facing_cam_at
}, {
label: 'ID card image',
value: customer.id_card_image_at
}])
customer.status = status.label
return camelize(customer)
}
/**
* Query all customers
*
* Add status as computed column,
* which will indicate the name of the latest
* compliance verfication completed by user.
*
* @returns {array} Array of customers populated with status field
*/
function batch () {
const sql = `select * from customers
where id != $1
order by created desc limit $2`
return db.any(sql, [ anonymous.uuid, NUM_RESULTS ])
.then(_.map(format))
}
module.exports = { add, get, batch, getById, update}