From 99f8a516c39c20bf1b99626dcfebdf59908edf84 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20S=C3=A1?= Date: Mon, 24 Jan 2022 19:21:23 +0000 Subject: [PATCH 1/7] fix: give custom info back to the machine --- lib/routes/phoneCodeRoutes.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/routes/phoneCodeRoutes.js b/lib/routes/phoneCodeRoutes.js index ac92531f..585c1e9d 100644 --- a/lib/routes/phoneCodeRoutes.js +++ b/lib/routes/phoneCodeRoutes.js @@ -6,7 +6,7 @@ const _ = require('lodash/fp') const compliance = require('../compliance') const complianceTriggers = require('../compliance-triggers') const configManager = require('../new-config-manager') -const { get, add, getEditedData, selectLatestData, getCustomerById, update } = require('../customers') +const { get, add, getEditedData, selectLatestData, getById, update } = require('../customers') const httpError = require('../route-helpers').httpError const plugins = require('../plugins') const Tx = require('../tx') @@ -26,7 +26,7 @@ function addOrUpdateCustomer (req) { return add(req.body) }) - .then(customer => Promise.all([getEditedData(customer.id), getCustomerById(customer.id)])) + .then(customer => Promise.all([getEditedData(customer.id), getById(customer.id, null)])) .then(([customerEditedData, customerOriginalData]) => selectLatestData(customerOriginalData, customerEditedData)) .then(customer => { // BACKWARDS_COMPATIBILITY 7.5 From 9d49c172f412a8e4229444f9010830843c0ee819 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20S=C3=A1?= Date: Wed, 26 Jan 2022 16:25:28 +0000 Subject: [PATCH 2/7] fix: reset custom info override when customer reanswers question --- lib/new-admin/services/customInfoRequests.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/new-admin/services/customInfoRequests.js b/lib/new-admin/services/customInfoRequests.js index 590dd48b..14d402dd 100644 --- a/lib/new-admin/services/customInfoRequests.js +++ b/lib/new-admin/services/customInfoRequests.js @@ -113,7 +113,10 @@ const setCustomerData = (customerId, infoRequestId, data) => { INSERT INTO customers_custom_info_requests (customer_id, info_request_id, customer_data) VALUES ($1, $2, $3) ON CONFLICT (customer_id, info_request_id) - DO UPDATE SET customer_data = $3` + DO UPDATE SET customer_data = $3, + override = 'automatic', + override_by = NULL, + override_at = NULL` return db.none(sql, [customerId, infoRequestId, data]) } From c2329be5881243b8d5d36151bc88f1bd677a1dd4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20S=C3=A1?= Date: Thu, 27 Jan 2022 15:38:48 +0000 Subject: [PATCH 3/7] fix: send manually entered customer data to machine --- lib/customers.js | 17 +++++++++-------- lib/routes/phoneCodeRoutes.js | 5 ++--- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/lib/customers.js b/lib/customers.js index a9e57ef8..09e7d031 100644 --- a/lib/customers.js +++ b/lib/customers.js @@ -88,10 +88,7 @@ function update (id, data, userToken, txId) { ' where id=$1 returning *' return db.one(sql, [id]) - .then(customerData => { - return getEditedData(id) - .then(customerEditedData => selectLatestData(customerData, customerEditedData)) - }) + .then(assignCustomerData) .then(addComplianceOverrides(id, updateData, userToken)) .then(populateOverrideUsernames) .then(computeStatus) @@ -324,6 +321,7 @@ function getById (id, userToken) { .then(populateOverrideUsernames) .then(computeStatus) .then(populateDailyVolume) + .then(assignCustomerData) .then(getCustomInfoRequestsData) .then(camelize) } @@ -723,15 +721,18 @@ function getCustomerById (id) { WHERE c.id = $2 ) AS cl WHERE rn = 1` return db.oneOrNone(sql, [passableErrorCodes, id]) - .then(customerData => { - return getEditedData(id) - .then(customerEditedData => selectLatestData(customerData, customerEditedData)) - }) + .then(assignCustomerData) .then(populateOverrideUsernames) .then(camelize) .then(it => ({ ...it, notes: (it.notes ?? []).map(camelize) })) } +function assignCustomerData (customer) { + return getEditedData(customer.id) + .then(customerEditedData => selectLatestData(customer, customerEditedData)) + .then(_.assign(customer)) +} + /** * Query the specific customer manually edited data * diff --git a/lib/routes/phoneCodeRoutes.js b/lib/routes/phoneCodeRoutes.js index 585c1e9d..4a4905bc 100644 --- a/lib/routes/phoneCodeRoutes.js +++ b/lib/routes/phoneCodeRoutes.js @@ -6,7 +6,7 @@ const _ = require('lodash/fp') const compliance = require('../compliance') const complianceTriggers = require('../compliance-triggers') const configManager = require('../new-config-manager') -const { get, add, getEditedData, selectLatestData, getById, update } = require('../customers') +const { get, add, getById, update } = require('../customers') const httpError = require('../route-helpers').httpError const plugins = require('../plugins') const Tx = require('../tx') @@ -26,8 +26,7 @@ function addOrUpdateCustomer (req) { return add(req.body) }) - .then(customer => Promise.all([getEditedData(customer.id), getById(customer.id, null)])) - .then(([customerEditedData, customerOriginalData]) => selectLatestData(customerOriginalData, customerEditedData)) + .then(customer => getById(customer.id)) .then(customer => { // BACKWARDS_COMPATIBILITY 7.5 // machines before 7.5 expect customer with sanctions result From 31929efc5baf687ebbeb590bd08195f87ba7cd8d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20S=C3=A1?= Date: Thu, 27 Jan 2022 18:01:31 +0000 Subject: [PATCH 4/7] refactor: clean up some names --- lib/customers.js | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/lib/customers.js b/lib/customers.js index 09e7d031..c6881691 100644 --- a/lib/customers.js +++ b/lib/customers.js @@ -756,13 +756,12 @@ function selectLatestData (customerData, customerEditedData) { 'name' ] _.map(field => { - let fieldName = field - if (_.includes(field, ['front_camera', 'id_card_photo'])) fieldName = fieldName + '_path' const atField = field + '_at' const byField = field + '_by' - if (!_.has(fieldName, customerData) || !_.has(fieldName, customerEditedData)) return + if (_.includes(field, ['front_camera', 'id_card_photo'])) field = field + '_path' + if (!_.has(field, customerData) || !_.has(field, customerEditedData)) return if (customerData[atField] < customerEditedData[atField]) { - customerData[fieldName] = customerEditedData[fieldName] + customerData[field] = customerEditedData[field] customerData[atField] = customerEditedData[atField] customerData[byField] = customerEditedData[byField] } From 050fb6589ddb92f4281167abef20c372368bb1f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20S=C3=A1?= Date: Mon, 31 Jan 2022 15:00:49 +0000 Subject: [PATCH 5/7] refactor: remove unnecessary step --- lib/customers.js | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/customers.js b/lib/customers.js index c6881691..c1f4e85c 100644 --- a/lib/customers.js +++ b/lib/customers.js @@ -730,7 +730,6 @@ function getCustomerById (id) { function assignCustomerData (customer) { return getEditedData(customer.id) .then(customerEditedData => selectLatestData(customer, customerEditedData)) - .then(_.assign(customer)) } /** From bc78837d39633d20e8e52998fe3394050c110195 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20S=C3=A1?= Date: Wed, 2 Feb 2022 14:51:43 +0000 Subject: [PATCH 6/7] refactor: remove unnecessary operations --- lib/customers.js | 172 ++--------------------------------- lib/routes/customerRoutes.js | 3 +- 2 files changed, 8 insertions(+), 167 deletions(-) diff --git a/lib/customers.js b/lib/customers.js index c1f4e85c..d60f6a3c 100644 --- a/lib/customers.js +++ b/lib/customers.js @@ -40,10 +40,6 @@ const TX_PASSTHROUGH_ERROR_CODES = ['operatorCancel'] 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]) - .then(populateOverrideUsernames) - .then(computeStatus) - .then(populateDailyVolume) - .then(getCustomInfoRequestsData) .then(camelize) } @@ -61,8 +57,6 @@ function add (customer) { function get (phone) { const sql = 'select * from customers where phone=$1' return db.oneOrNone(sql, [phone]) - .then(populateDailyVolume) - .then(getCustomInfoRequestsData) .then(camelize) } @@ -78,7 +72,7 @@ function get (phone) { * * @returns {Promise} Newly updated Customer */ -function update (id, data, userToken, txId) { +function update (id, data, userToken) { const formattedData = _.omit(['id'], _.mapKeys(_.snakeCase, data)) const enhancedUpdateData = enhanceAtFields(enhanceOverrideFields(formattedData, userToken)) @@ -90,9 +84,6 @@ function update (id, data, userToken, txId) { return db.one(sql, [id]) .then(assignCustomerData) .then(addComplianceOverrides(id, updateData, userToken)) - .then(populateOverrideUsernames) - .then(computeStatus) - .then((it) => populateDailyVolume(it, txId)) .then(getCustomInfoRequestsData) .then(camelize) } @@ -314,75 +305,17 @@ const updateSubscriberData = (customerId, data, userToken) => { * @param {string} userToken Acting user's token * * @returns {object} Customer found + * + * Used for the machine. */ function getById (id, userToken) { const sql = 'select * from customers where id=$1' return db.oneOrNone(sql, [id]) - .then(populateOverrideUsernames) - .then(computeStatus) - .then(populateDailyVolume) .then(assignCustomerData) .then(getCustomInfoRequestsData) .then(camelize) } -/** - * Get and calculate customer's daily volume - * for both cash_in & cash_out txs - * - * @name getDailyVolume - * @function - * - * @param {string} id Customer's id - * @param {string} txId current tx, to be ignored in the query - * @returns {Bignumber} Customer's daily volume - */ -function getDailyVolume (id, txId) { - const queries = txId ? getDailyVolumeMinusCurrentTxQueries(id, txId) : getDailyVolumeQueries(id) - return Promise.all(queries).then(([cashIn, cashOut]) => { - const dailyVolume = new BN(cashIn.total).plus(cashOut.total) - const hoursTillLimitClear = getHoursTillLimitClear(cashIn.maxdate, cashOut.maxdate) - return { dailyVolume, hoursTillLimitClear } - }) -} - -function getDailyVolumeQueries (id) { - return [ - db.one(`select coalesce(sum(fiat), 0) as total, max(created) as maxdate from cash_in_txs - where customer_id=$1 - and created > now() - interval '1 day'`, [id]), - db.one(`select coalesce(sum(fiat), 0) as total, max(created) as maxdate from cash_out_txs - where customer_id=$1 - and created > now() - interval '1 day'`, [id]) - ] -} - -function getDailyVolumeMinusCurrentTxQueries (id, txId) { - return [ - db.one(`select coalesce(sum(fiat), 0) as total, max(created) as maxdate from cash_in_txs - where customer_id=$1 - and id!=$2 - and created > now() - interval '1 day'`, [id, txId]), - db.one(`select coalesce(sum(fiat), 0) as total, max(created) as maxdate from cash_out_txs - where customer_id=$1 - and id!=$2 - and created > now() - interval '1 day'`, [id, txId]) - ] -} - -function getHoursTillLimitClear (cashInDate, cashOutDate) { - let startDate = new Date() - startDate = sub({ days: 1 }, startDate) - - const cashInMoment = new Date(cashInDate || startDate) - const cashOutMoment = new Date(cashOutDate || startDate) - - const cashInDuration = differenceInHours(cashInMoment, startDate) - const cashOutDuration = differenceInHours(cashOutMoment, startDate) - - return _.ceil(_.max([cashInDuration, cashOutDuration, 0])) -} - /** * Camelize customer fields * Note: return null if customer is undefined @@ -397,24 +330,6 @@ function camelize (customer) { return customer ? _.mapKeys(_.camelCase, customer) : null } -/** - * Populate customer object - * with dailyVolume information - * - * @name populateDailyVolume - * @function - * - * @param {object} customer Customer object - * @returns {object} Customer object populated with dailyVolume - */ -function populateDailyVolume (customer, txId) { - if (!customer) return - return getDailyVolume(customer.id, txId).then(({ dailyVolume, hoursTillLimitClear }) => { - let withHours = _.set('hours_till_limit_clear', hoursTillLimitClear, customer) - return _.set('daily_volume', dailyVolume, withHours) - }) -} - /** * Get all available complianceTypes * that can be overriden (excluding hard_limit) @@ -525,76 +440,6 @@ function addComplianceOverrides (id, customer, userToken) { .then(() => customer) } -/** - * Compute status field - * - * Status field indicates the last - * compliance user has verified - * - * @name computeStatus - * @function - * - * @param {object} Customer object - * @returns {object} Customer populated with status field - */ -function computeStatus (customer) { - if (!customer) return null - /** - * Populate with status field - * - */ - const status = _.maxBy('value', [{ - label: 'Phone', - value: customer.phone_at - }, { - label: 'ID card', - value: customer.id_card_at - }, { - label: 'Sanctions', - value: customer.sanctions_at - }, { - label: 'Front camera', - value: customer.front_camera_at - }, { - label: 'ID card image', - value: customer.id_card_image_at - }]) - - return _.assign(customer, { - status: _.get('label', status) - }) -} - -/** - * Populate the customer object with user names - * for override fields ( fields ending with _override_by ) - * - * @name populateOverrideUsernames - * @function - * - * @param {object} customer Customer object to populate - * @returns {promise} Customer with populated *by_name fields - */ -function populateOverrideUsernames (customer) { - const fieldsToUpdate = _.map(field => { - return { - token: customer[field + '_override_by'] || customer[field + '_override_by_old'], - field: field + '_override_by_name' - } - }, getComplianceTypes()) - const queryTokens = _.map('token', fieldsToUpdate) - - return users.getByIds(queryTokens) - .then(usersList => { - return _.map(userField => { - const user = _.find({ token: userField.token }, usersList) - return { - [userField.field]: user ? user.name : null - } - }, fieldsToUpdate) - }) - .then(_.reduce(_.assign, customer)) -} /** * Query all customers @@ -611,10 +456,7 @@ function batch () { order by created desc limit $2` return db.any(sql, [ anonymous.uuid, NUM_RESULTS ]) .then(customers => Promise.all(_.map(customer => { - return populateOverrideUsernames(customer) - .then(computeStatus) - .then(populateDailyVolume) - .then(getCustomInfoRequestsData) + return getCustomInfoRequestsData(customer) .then(camelize) }, customers))) } @@ -672,8 +514,7 @@ function getCustomersList (phone = null, name = null, address = null, id = null) limit $3` return db.any(sql, [ passableErrorCodes, anonymous.uuid, NUM_RESULTS, phone, name, address, id ]) .then(customers => Promise.all(_.map(customer => { - return populateOverrideUsernames(customer) - .then(camelize) + return camelize(customer) .then(it => ({ ...it, notes: (it.notes ?? []).map(camelize) })) }, customers))) } @@ -684,6 +525,8 @@ function getCustomersList (phone = null, name = null, address = null, id = null) * transactions * * @returns {array} A single customer instance with non edited + * + * Used for the server. */ function getCustomerById (id) { const passableErrorCodes = _.map(Pgp.as.text, TX_PASSTHROUGH_ERROR_CODES).join(',') @@ -722,7 +565,6 @@ function getCustomerById (id) { ) AS cl WHERE rn = 1` return db.oneOrNone(sql, [passableErrorCodes, id]) .then(assignCustomerData) - .then(populateOverrideUsernames) .then(camelize) .then(it => ({ ...it, notes: (it.notes ?? []).map(camelize) })) } diff --git a/lib/routes/customerRoutes.js b/lib/routes/customerRoutes.js index 8b0e51d6..e59acb52 100644 --- a/lib/routes/customerRoutes.js +++ b/lib/routes/customerRoutes.js @@ -15,7 +15,6 @@ const httpError = require('../route-helpers').httpError const notifier = require('../notifier') 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') const customInfoRequestQueries = require('../new-admin/services/customInfoRequests') @@ -142,7 +141,7 @@ function updateTxCustomerPhoto (req, res, 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)]) + return Promise.all([customers.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) From 724e8c05b1064f3ea456bc74b9a89878dace45d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20S=C3=A1?= Date: Fri, 11 Feb 2022 15:42:12 +0000 Subject: [PATCH 7/7] fix: `.then()` on non-Promise --- lib/customers.js | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/lib/customers.js b/lib/customers.js index d60f6a3c..2a0da442 100644 --- a/lib/customers.js +++ b/lib/customers.js @@ -330,6 +330,13 @@ function camelize (customer) { return customer ? _.mapKeys(_.camelCase, customer) : null } +function camelizeDeep (customer) { + return _.flow( + camelize, + it => ({ ...it, notes: (it.notes ?? []).map(camelize) }) + )(customer) +} + /** * Get all available complianceTypes * that can be overriden (excluding hard_limit) @@ -513,10 +520,7 @@ function getCustomersList (phone = null, name = null, address = null, id = null) AND ($7 IS NULL OR id_card_data::json->>'documentNumber' = $7) limit $3` return db.any(sql, [ passableErrorCodes, anonymous.uuid, NUM_RESULTS, phone, name, address, id ]) - .then(customers => Promise.all(_.map(customer => { - return camelize(customer) - .then(it => ({ ...it, notes: (it.notes ?? []).map(camelize) })) - }, customers))) + .then(customers => Promise.all(_.map(camelizeDeep, customers))) } /** @@ -565,8 +569,7 @@ function getCustomerById (id) { ) AS cl WHERE rn = 1` return db.oneOrNone(sql, [passableErrorCodes, id]) .then(assignCustomerData) - .then(camelize) - .then(it => ({ ...it, notes: (it.notes ?? []).map(camelize) })) + .then(camelizeDeep) } function assignCustomerData (customer) {