Merge branch 'release-10.0' into feat/lam-1111/customer-last-used-machine

* release-10.0:
  chore: use map instead of foreach
  chore: v10.0.1 (#1696)
  Add InforU SMS plugin (#1695)
  fix: add machine name and timestamp to pending notifs messages
  refactor: drop unused debug logs
  refactor: replace `fs`+`util.promisify` with `fs/promises`
  refactor: drop unnecessary use of `_.curry`
  refactor: destruct in parameters list
  refactor: drop unnecessary curly braces
  chore: drop unused import
  refactor: destruct in parameters list to build object
  refactor: destruct in parameters list instead
  refactor: use `set` from `lodash/fp` instead of syntax
  feat: notifications and flow fixes
  fix: generic external auth on ui
  fix: admin ui
  refactor: yagni and flow of external compliance
  fix: change sumsub usage away from self-hosted solutions
  feat: implement sumsub API module
  chore: remove unused files
This commit is contained in:
siiky 2024-07-18 13:07:17 +01:00
commit 4b4af106a8
338 changed files with 1005 additions and 81792 deletions

View file

@ -17,6 +17,9 @@ const NUM_RESULTS = 1000
const sms = require('./sms')
const settingsLoader = require('./new-settings-loader')
const logger = require('./logger')
const externalCompliance = require('./compliance-external')
const { APPROVED, RETRY } = require('./plugins/compliance/consts')
const TX_PASSTHROUGH_ERROR_CODES = ['operatorCancel', 'scoreThresholdReached', 'walletScoringError']
@ -243,7 +246,7 @@ function deleteEditedData (id, data) {
'id_card_data',
'id_card_photo',
'us_ssn',
'subcriber_info',
'subscriber_info',
'name'
]
const filteredData = _.pick(defaults, _.mapKeys(_.snakeCase, data))
@ -322,6 +325,7 @@ function getById (id) {
return db.oneOrNone(sql, [id])
.then(assignCustomerData)
.then(getCustomInfoRequestsData)
.then(getExternalComplianceMachine)
.then(camelize)
}
@ -342,7 +346,11 @@ function camelize (customer) {
function camelizeDeep (customer) {
return _.flow(
camelize,
it => ({ ...it, notes: (it.notes ?? []).map(camelize) })
it => ({
...it,
notes: (it.notes ?? []).map(camelize),
externalCompliance: (it.externalCompliance ?? []).map(camelize)
})
)(customer)
}
@ -587,6 +595,7 @@ function getCustomerById (id) {
return db.oneOrNone(sql, [passableErrorCodes, id])
.then(assignCustomerData)
.then(getCustomInfoRequestsData)
.then(getExternalCompliance)
.then(camelizeDeep)
.then(formatSubscriberInfo)
}
@ -926,6 +935,95 @@ function updateLastAuthAttempt (customerId) {
return db.none(sql, [customerId])
}
function getExternalComplianceMachine (customer) {
return settingsLoader.loadLatest()
.then(settings => externalCompliance.getStatusMap(settings, customer.id))
.then(statusMap => {
return updateExternalComplianceByMap(customer.id, statusMap)
.then(() => customer.externalCompliance = statusMap)
.then(() => customer)
})
}
function updateExternalCompliance(customerId, service, status) {
const sql = `
UPDATE customer_external_compliance SET last_known_status = $1, last_updated = now()
WHERE customer_id=$2 AND service=$3
`
return db.none(sql, [status, customerId, service])
}
function updateExternalComplianceByMap(customerId, serviceMap) {
const sql = `
UPDATE customer_external_compliance SET last_known_status = $1, last_updated = now()
WHERE customer_id=$2 AND service=$3
`
const pairs = _.toPairs(serviceMap)
const promises = _.map(([service, status]) => db.none(sql, [status.answer, customerId, service]))(pairs)
return Promise.all(promises)
}
function getExternalCompliance(customer) {
const sql = `SELECT external_id, service, last_known_status, last_updated
FROM customer_external_compliance where customer_id=$1`
return db.manyOrNone(sql, [customer.id])
.then(compliance => {
customer.externalCompliance = compliance
})
.then(() => customer)
}
function getOpenExternalCompliance() {
const sql = `SELECT customer_id, service, last_known_status FROM customer_external_compliance where last_known_status in ('PENDING', 'RETRY') or last_known_status is null`
return db.manyOrNone(sql)
}
function notifyRetryExternalCompliance(settings, customerId, service) {
const sql = 'SELECT phone FROM customers WHERE id=$1'
const promises = [db.one(sql, [customerId]), externalCompliance.createLink(settings, service, customerId)]
return Promise.all(promises)
.then(([toNumber, link]) => {
const body = `Your external compliance verification has failed. Please try again. Link for retry: ${link}`
return sms.sendMessage(settings, { toNumber, body })
})
}
function notifyApprovedExternalCompliance(settings, customerId) {
const sql = 'SELECT phone FROM customers WHERE id=$1'
return db.one(sql, [customerId])
.then((toNumber) => {
const body = 'Your external compliance verification has been approved.'
return sms.sendMessage(settings, { toNumber, body })
})
}
function checkExternalCompliance(settings) {
return getOpenExternalCompliance()
.then(externals => {
console.log(externals)
const promises = _.map(external => {
return externalCompliance.getStatus(settings, external.service, external.customer_id)
.then(status => {
console.log('status', status, external.customer_id, external.service)
if (status.status.answer === RETRY) notifyRetryExternalCompliance(settings, external.customer_id, status.service)
if (status.status.answer === APPROVED) notifyApprovedExternalCompliance(settings, external.customer_id)
return updateExternalCompliance(external.customer_id, external.service, status.status.answer)
})
}, externals)
return Promise.all(promises)
})
}
function addExternalCompliance(customerId, service, id) {
const sql = `INSERT INTO customer_external_compliance (customer_id, external_id, service) VALUES ($1, $2, $3)`
return db.none(sql, [customerId, id, service])
}
module.exports = {
add,
addWithEmail,
@ -949,5 +1047,7 @@ module.exports = {
updateTxCustomerPhoto,
enableTestCustomer,
disableTestCustomer,
updateLastAuthAttempt
updateLastAuthAttempt,
addExternalCompliance,
checkExternalCompliance
}