fix: allow for custom info requests to be allowed or blocked
fix: improve custom info requests backend fix: add custom info requests to trigger overrides
This commit is contained in:
parent
08bcf03a1e
commit
87a3b718db
11 changed files with 167 additions and 88 deletions
|
|
@ -1,3 +1,4 @@
|
|||
const authentication = require('../modules/userManagement')
|
||||
const queries = require('../../services/customInfoRequests')
|
||||
const DataLoader = require('dataloader')
|
||||
|
||||
|
|
@ -21,7 +22,10 @@ const resolvers = {
|
|||
insertCustomInfoRequest: (...[, { customRequest }]) => queries.addCustomInfoRequest(customRequest),
|
||||
removeCustomInfoRequest: (...[, { id }]) => queries.removeCustomInfoRequest(id),
|
||||
editCustomInfoRequest: (...[, { id, customRequest }]) => queries.editCustomInfoRequest(id, customRequest),
|
||||
setAuthorizedCustomRequest: (...[, { customerId, infoRequestId, isAuthorized }]) => queries.setAuthorizedCustomRequest(customerId, infoRequestId, isAuthorized),
|
||||
setAuthorizedCustomRequest: (...[, { customerId, infoRequestId, override }, context]) => {
|
||||
const token = authentication.getToken(context)
|
||||
return queries.setAuthorizedCustomRequest(customerId, infoRequestId, override, token)
|
||||
},
|
||||
setCustomerCustomInfoRequest: (...[, { customerId, infoRequestId, data }]) => queries.setCustomerData(customerId, infoRequestId, data)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,7 +32,9 @@ const typeDef = gql`
|
|||
type CustomRequestData {
|
||||
customerId: ID
|
||||
infoRequestId: ID
|
||||
approved: Boolean
|
||||
override: String
|
||||
overrideAt: Date
|
||||
overrideBy: ID
|
||||
customerData: JSON
|
||||
customInfoRequest: CustomInfoRequest
|
||||
}
|
||||
|
|
@ -47,7 +49,7 @@ const typeDef = gql`
|
|||
insertCustomInfoRequest(customRequest: CustomRequestInput!): CustomInfoRequest @auth
|
||||
removeCustomInfoRequest(id: ID!): CustomInfoRequest @auth
|
||||
editCustomInfoRequest(id: ID!, customRequest: CustomRequestInput!): CustomInfoRequest @auth
|
||||
setAuthorizedCustomRequest(customerId: ID!, infoRequestId: ID!, isAuthorized: Boolean!): Boolean @auth
|
||||
setAuthorizedCustomRequest(customerId: ID!, infoRequestId: ID!, override: String!): Boolean @auth
|
||||
setCustomerCustomInfoRequest(customerId: ID!, infoRequestId: ID!, data: JSON!): Boolean @auth
|
||||
}
|
||||
`
|
||||
|
|
|
|||
|
|
@ -35,8 +35,10 @@ const getAllCustomInfoRequestsForCustomer = (customerId) => {
|
|||
return db.any(sql, [customerId]).then(res => res.map(item => ({
|
||||
customerId: item.customer_id,
|
||||
infoRequestId: item.info_request_id,
|
||||
approved: item.approved,
|
||||
customerData: item.customer_data
|
||||
customerData: item.customer_data,
|
||||
override: item.override,
|
||||
overrideAt: item.override_at,
|
||||
overrideBy: item.override_by
|
||||
})))
|
||||
}
|
||||
|
||||
|
|
@ -46,8 +48,10 @@ const getCustomInfoRequestForCustomer = (customerId, infoRequestId) => {
|
|||
return {
|
||||
customerId: item.customer_id,
|
||||
infoRequestId: item.info_request_id,
|
||||
approved: item.approved,
|
||||
customerData: item.customer_data
|
||||
customerData: item.customer_data,
|
||||
override: item.override,
|
||||
overrideAt: item.override_at,
|
||||
overrideBy: item.override_by
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
@ -61,8 +65,10 @@ const batchGetAllCustomInfoRequestsForCustomer = (customerIds) => {
|
|||
return items.map(item => ({
|
||||
customerId: item.customer_id,
|
||||
infoRequestId: item.info_request_id,
|
||||
approved: item.approved,
|
||||
customerData: item.customer_data
|
||||
customerData: item.customer_data,
|
||||
override: item.override,
|
||||
overrideAt: item.override_at,
|
||||
overrideBy: item.override_by
|
||||
}))
|
||||
})
|
||||
})
|
||||
|
|
@ -93,9 +99,9 @@ const batchGetCustomInfoRequest = (infoRequestIds) => {
|
|||
})
|
||||
}
|
||||
|
||||
const setAuthorizedCustomRequest = (customerId, infoRequestId, isAuthorized) => {
|
||||
const sql = `UPDATE customers_custom_info_requests SET approved = $1 WHERE customer_id = $2 AND info_request_id = $3`
|
||||
return db.none(sql, [isAuthorized, customerId, infoRequestId]).then(() => true)
|
||||
const setAuthorizedCustomRequest = (customerId, infoRequestId, override, token) => {
|
||||
const sql = `UPDATE customers_custom_info_requests SET override = $1, override_by = $2, override_at = now() WHERE customer_id = $3 AND info_request_id = $4`
|
||||
return db.none(sql, [override, token, customerId, infoRequestId]).then(() => true)
|
||||
}
|
||||
|
||||
const setCustomerData = (customerId, infoRequestId, data) => {
|
||||
|
|
@ -103,7 +109,7 @@ 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, approved = null`
|
||||
DO UPDATE SET customer_data = $3`
|
||||
return db.none(sql, [customerId, infoRequestId, data])
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
const _ = require('lodash/fp')
|
||||
const { getCustomInfoRequests } = require('./new-admin/services/customInfoRequests')
|
||||
|
||||
const namespaces = {
|
||||
WALLETS: 'wallets',
|
||||
|
|
@ -107,22 +108,29 @@ const getGlobalNotifications = config => getNotifications(null, null, config)
|
|||
const getTriggers = _.get('triggers')
|
||||
|
||||
const getTriggersAutomation = config => {
|
||||
const defaultAutomation = _.get('triggersConfig_automation')(config)
|
||||
const requirements = {
|
||||
sanctions: defaultAutomation,
|
||||
idCardPhoto: defaultAutomation,
|
||||
idCardData: defaultAutomation,
|
||||
facephoto: defaultAutomation,
|
||||
usSsn: defaultAutomation
|
||||
}
|
||||
return getCustomInfoRequests(true)
|
||||
.then(infoRequests => {
|
||||
const defaultAutomation = _.get('triggersConfig_automation')(config)
|
||||
const requirements = {
|
||||
sanctions: defaultAutomation,
|
||||
idCardPhoto: defaultAutomation,
|
||||
idCardData: defaultAutomation,
|
||||
facephoto: defaultAutomation,
|
||||
usSsn: defaultAutomation
|
||||
}
|
||||
|
||||
const overrides = _.get('triggersConfig_overrides')(config)
|
||||
_.forEach(it => {
|
||||
requirements[it.id] = defaultAutomation
|
||||
}, infoRequests)
|
||||
|
||||
const requirementsOverrides = _.reduce((acc, override) => {
|
||||
return _.assign(acc, { [override.requirement]: override.automation })
|
||||
}, {}, overrides)
|
||||
const overrides = _.get('triggersConfig_overrides')(config)
|
||||
|
||||
return _.assign(requirements, requirementsOverrides)
|
||||
const requirementsOverrides = _.reduce((acc, override) => {
|
||||
return _.assign(acc, { [override.requirement]: override.automation })
|
||||
}, {}, overrides)
|
||||
|
||||
return _.assign(requirements, requirementsOverrides)
|
||||
})
|
||||
}
|
||||
|
||||
const splitGetFirst = _.compose(_.head, _.split('_'))
|
||||
|
|
|
|||
|
|
@ -73,7 +73,7 @@ function poll (req, res, next) {
|
|||
const pi = plugins(settings, deviceId)
|
||||
const hasLightning = checkHasLightning(settings)
|
||||
|
||||
const triggersAutomation = configManager.getTriggersAutomation(settings.config)
|
||||
const triggersAutomationPromise = configManager.getTriggersAutomation(settings.config)
|
||||
const triggersPromise = buildTriggers(configManager.getTriggers(settings.config))
|
||||
|
||||
const operatorInfo = configManager.getOperatorInfo(settings.config)
|
||||
|
|
@ -84,8 +84,8 @@ function poll (req, res, next) {
|
|||
|
||||
state.pids[operatorId] = { [deviceId]: { pid, ts: Date.now() } }
|
||||
|
||||
return Promise.all([pi.pollQueries(serialNumber, deviceTime, req.query, machineVersion, machineModel), triggersPromise])
|
||||
.then(([results, triggers]) => {
|
||||
return Promise.all([pi.pollQueries(serialNumber, deviceTime, req.query, machineVersion, machineModel), triggersPromise, triggersAutomationPromise])
|
||||
.then(([results, triggers, triggersAutomation]) => {
|
||||
const cassettes = results.cassettes
|
||||
|
||||
const reboot = pid && state.reboots?.[operatorId]?.[deviceId] === pid
|
||||
|
|
|
|||
16
migrations/1642518884925-manual-custom-info-requests.js
Normal file
16
migrations/1642518884925-manual-custom-info-requests.js
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
var db = require('./db')
|
||||
|
||||
exports.up = function (next) {
|
||||
var sql = [
|
||||
`ALTER TABLE customers_custom_info_requests DROP COLUMN approved`,
|
||||
`ALTER TABLE customers_custom_info_requests ADD COLUMN override verification_type NOT NULL DEFAULT 'automatic'`,
|
||||
`ALTER TABLE customers_custom_info_requests ADD COLUMN override_by UUID REFERENCES users(id)`,
|
||||
`ALTER TABLE customers_custom_info_requests ADD COLUMN override_at TIMESTAMPTZ`
|
||||
]
|
||||
|
||||
db.multi(sql, next)
|
||||
}
|
||||
|
||||
exports.down = function (next) {
|
||||
next()
|
||||
}
|
||||
|
|
@ -324,7 +324,6 @@ const CustomerData = ({
|
|||
]
|
||||
|
||||
R.forEach(it => {
|
||||
console.log('it', it)
|
||||
customRequirements.push({
|
||||
fields: [
|
||||
{
|
||||
|
|
@ -336,12 +335,13 @@ const CustomerData = ({
|
|||
],
|
||||
title: it.customInfoRequest.customRequest.name,
|
||||
titleIcon: <CardIcon className={classes.cardIcon} />,
|
||||
state: R.path(['override'])(it),
|
||||
authorize: () =>
|
||||
authorizeCustomRequest({
|
||||
variables: {
|
||||
customerId: it.customerId,
|
||||
infoRequestId: it.customInfoRequest.id,
|
||||
isAuthorized: true
|
||||
override: OVERRIDE_AUTHORIZED
|
||||
}
|
||||
}),
|
||||
reject: () =>
|
||||
|
|
@ -349,7 +349,7 @@ const CustomerData = ({
|
|||
variables: {
|
||||
customerId: it.customerId,
|
||||
infoRequestId: it.customInfoRequest.id,
|
||||
isAuthorized: false
|
||||
override: OVERRIDE_REJECTED
|
||||
}
|
||||
}),
|
||||
save: values => {
|
||||
|
|
|
|||
|
|
@ -95,7 +95,9 @@ const GET_CUSTOMER = gql`
|
|||
}
|
||||
customInfoRequests {
|
||||
customerId
|
||||
approved
|
||||
override
|
||||
overrideBy
|
||||
overrideAt
|
||||
customerData
|
||||
customInfoRequest {
|
||||
id
|
||||
|
|
@ -180,12 +182,12 @@ const SET_AUTHORIZED_REQUEST = gql`
|
|||
mutation setAuthorizedCustomRequest(
|
||||
$customerId: ID!
|
||||
$infoRequestId: ID!
|
||||
$isAuthorized: Boolean!
|
||||
$override: String!
|
||||
) {
|
||||
setAuthorizedCustomRequest(
|
||||
customerId: $customerId
|
||||
infoRequestId: $infoRequestId
|
||||
isAuthorized: $isAuthorized
|
||||
override: $override
|
||||
)
|
||||
}
|
||||
`
|
||||
|
|
|
|||
|
|
@ -53,12 +53,12 @@ const SET_AUTHORIZED_REQUEST = gql`
|
|||
mutation setAuthorizedCustomRequest(
|
||||
$customerId: ID!
|
||||
$infoRequestId: ID!
|
||||
$isAuthorized: Boolean!
|
||||
$override: String!
|
||||
) {
|
||||
setAuthorizedCustomRequest(
|
||||
customerId: $customerId
|
||||
infoRequestId: $infoRequestId
|
||||
isAuthorized: $isAuthorized
|
||||
override: $override
|
||||
)
|
||||
}
|
||||
`
|
||||
|
|
|
|||
|
|
@ -28,13 +28,34 @@ const GET_INFO = gql`
|
|||
}
|
||||
`
|
||||
|
||||
const GET_CUSTOM_REQUESTS = gql`
|
||||
query customInfoRequests {
|
||||
customInfoRequests {
|
||||
id
|
||||
customRequest
|
||||
enabled
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
const AdvancedTriggersSettings = memo(() => {
|
||||
const SCREEN_KEY = namespaces.TRIGGERS
|
||||
const [error, setError] = useState(null)
|
||||
const [isEditingDefault, setEditingDefault] = useState(false)
|
||||
const [isEditingOverrides, setEditingOverrides] = useState(false)
|
||||
|
||||
const { data } = useQuery(GET_INFO)
|
||||
const { data, loading: configLoading } = useQuery(GET_INFO)
|
||||
const { data: customInfoReqData, loading: customInfoLoading } = useQuery(
|
||||
GET_CUSTOM_REQUESTS
|
||||
)
|
||||
|
||||
const customInfoRequests =
|
||||
R.path(['customInfoRequests'])(customInfoReqData) ?? []
|
||||
const enabledCustomInfoRequests = R.filter(R.propEq('enabled', true))(
|
||||
customInfoRequests
|
||||
)
|
||||
|
||||
const loading = configLoading || customInfoLoading
|
||||
|
||||
const [saveConfig] = useMutation(SAVE_CONFIG, {
|
||||
refetchQueries: () => ['getData'],
|
||||
|
|
@ -67,42 +88,47 @@ const AdvancedTriggersSettings = memo(() => {
|
|||
const onEditingOverrides = (it, editing) => setEditingOverrides(editing)
|
||||
|
||||
return (
|
||||
<>
|
||||
<Section>
|
||||
<EditableTable
|
||||
title="Default requirement settings"
|
||||
error={error?.message}
|
||||
titleLg
|
||||
name="triggersConfig"
|
||||
enableEdit
|
||||
initialValues={requirementsDefaults}
|
||||
save={saveDefaults}
|
||||
validationSchema={defaultSchema}
|
||||
data={R.of(requirementsDefaults)}
|
||||
elements={getDefaultSettings()}
|
||||
setEditing={onEditingDefault}
|
||||
forceDisable={isEditingOverrides}
|
||||
/>
|
||||
</Section>
|
||||
<Section>
|
||||
<EditableTable
|
||||
error={error?.message}
|
||||
title="Overrides"
|
||||
titleLg
|
||||
name="overrides"
|
||||
enableDelete
|
||||
enableEdit
|
||||
enableCreate
|
||||
initialValues={overridesDefaults}
|
||||
save={saveOverrides}
|
||||
validationSchema={getOverridesSchema(requirementsOverrides)}
|
||||
data={requirementsOverrides}
|
||||
elements={getOverrides()}
|
||||
setEditing={onEditingOverrides}
|
||||
forceDisable={isEditingDefault}
|
||||
/>
|
||||
</Section>
|
||||
</>
|
||||
!loading && (
|
||||
<>
|
||||
<Section>
|
||||
<EditableTable
|
||||
title="Default requirement settings"
|
||||
error={error?.message}
|
||||
titleLg
|
||||
name="triggersConfig"
|
||||
enableEdit
|
||||
initialValues={requirementsDefaults}
|
||||
save={saveDefaults}
|
||||
validationSchema={defaultSchema}
|
||||
data={R.of(requirementsDefaults)}
|
||||
elements={getDefaultSettings()}
|
||||
setEditing={onEditingDefault}
|
||||
forceDisable={isEditingOverrides}
|
||||
/>
|
||||
</Section>
|
||||
<Section>
|
||||
<EditableTable
|
||||
error={error?.message}
|
||||
title="Overrides"
|
||||
titleLg
|
||||
name="overrides"
|
||||
enableDelete
|
||||
enableEdit
|
||||
enableCreate
|
||||
initialValues={overridesDefaults}
|
||||
save={saveOverrides}
|
||||
validationSchema={getOverridesSchema(
|
||||
requirementsOverrides,
|
||||
enabledCustomInfoRequests
|
||||
)}
|
||||
data={requirementsOverrides}
|
||||
elements={getOverrides(enabledCustomInfoRequests)}
|
||||
setEditing={onEditingOverrides}
|
||||
forceDisable={isEditingDefault}
|
||||
/>
|
||||
</Section>
|
||||
</>
|
||||
)
|
||||
)
|
||||
})
|
||||
|
||||
|
|
|
|||
|
|
@ -4,18 +4,29 @@ import * as Yup from 'yup'
|
|||
import Autocomplete from 'src/components/inputs/formik/Autocomplete.js'
|
||||
import { getView } from 'src/pages/Triggers/helper'
|
||||
|
||||
const advancedRequirementOptions = [
|
||||
{ display: 'Sanctions', code: 'sanctions' },
|
||||
{ display: 'ID card image', code: 'idCardPhoto' },
|
||||
{ display: 'ID data', code: 'idCardData' },
|
||||
{ display: 'Customer camera', code: 'facephoto' },
|
||||
{ display: 'US SSN', code: 'usSsn' }
|
||||
]
|
||||
const buildAdvancedRequirementOptions = customInfoRequests => {
|
||||
const base = [
|
||||
{ display: 'Sanctions', code: 'sanctions' },
|
||||
{ display: 'ID card image', code: 'idCardPhoto' },
|
||||
{ display: 'ID data', code: 'idCardData' },
|
||||
{ display: 'Customer camera', code: 'facephoto' },
|
||||
{ display: 'US SSN', code: 'usSsn' }
|
||||
]
|
||||
|
||||
const displayRequirement = code => {
|
||||
const custom = R.map(it => ({
|
||||
display: it.customRequest.name,
|
||||
code: it.id
|
||||
}))(customInfoRequests)
|
||||
|
||||
return R.concat(base, custom)
|
||||
}
|
||||
|
||||
const displayRequirement = (code, customInfoRequests) => {
|
||||
return R.prop(
|
||||
'display',
|
||||
R.find(R.propEq('code', code))(advancedRequirementOptions)
|
||||
R.find(R.propEq('code', code))(
|
||||
buildAdvancedRequirementOptions(customInfoRequests)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -29,7 +40,7 @@ const defaultSchema = Yup.object().shape({
|
|||
.required()
|
||||
})
|
||||
|
||||
const getOverridesSchema = values => {
|
||||
const getOverridesSchema = (values, customInfoRequests) => {
|
||||
return Yup.object().shape({
|
||||
id: Yup.string()
|
||||
.label('Requirement')
|
||||
|
|
@ -40,7 +51,8 @@ const getOverridesSchema = values => {
|
|||
if (R.find(R.propEq('requirement', requirement))(values)) {
|
||||
return this.createError({
|
||||
message: `Requirement ${displayRequirement(
|
||||
requirement
|
||||
requirement,
|
||||
customInfoRequests
|
||||
)} already overriden`
|
||||
})
|
||||
}
|
||||
|
|
@ -84,17 +96,20 @@ const getDefaultSettings = () => {
|
|||
]
|
||||
}
|
||||
|
||||
const getOverrides = () => {
|
||||
const getOverrides = customInfoRequests => {
|
||||
return [
|
||||
{
|
||||
name: 'requirement',
|
||||
header: 'Requirement',
|
||||
width: 196,
|
||||
size: 'sm',
|
||||
view: getView(advancedRequirementOptions, 'display'),
|
||||
view: getView(
|
||||
buildAdvancedRequirementOptions(customInfoRequests),
|
||||
'display'
|
||||
),
|
||||
input: Autocomplete,
|
||||
inputProps: {
|
||||
options: advancedRequirementOptions,
|
||||
options: buildAdvancedRequirementOptions(customInfoRequests),
|
||||
labelProp: 'display',
|
||||
valueProp: 'code'
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue