diff --git a/lib/customers.js b/lib/customers.js
index 1f15dc91..a9e57ef8 100644
--- a/lib/customers.js
+++ b/lib/customers.js
@@ -121,7 +121,8 @@ async function updateCustomer (id, data, userToken) {
'us_ssn_override',
'sanctions_override',
'front_camera_override',
- 'suspended_until'
+ 'suspended_until',
+ 'phone_override'
],
_.mapKeys(_.snakeCase, data))
@@ -169,6 +170,7 @@ function edit (id, data, userToken) {
const filteredData = _.pick(defaults, _.mapKeys(_.snakeCase, _.omitBy(_.isNil, data)))
if (_.isEmpty(filteredData)) return getCustomerById(id)
const formattedData = enhanceEditedPhotos(enhanceEditedFields(filteredData, userToken))
+
const defaultDbData = {
customer_id: id,
created: new Date(),
@@ -688,18 +690,18 @@ function getCustomersList (phone = null, name = null, address = null, id = null)
function getCustomerById (id) {
const passableErrorCodes = _.map(Pgp.as.text, TX_PASSTHROUGH_ERROR_CODES).join(',')
const sql = `SELECT id, authorized_override, days_suspended, is_suspended, front_camera_path, front_camera_at, front_camera_override,
- phone, sms_override, id_card_data_at, id_card_data, id_card_data_override, id_card_data_expiration,
+ phone, phone_at, phone_override, sms_override, id_card_data_at, id_card_data, id_card_data_override, id_card_data_expiration,
id_card_photo_path, id_card_photo_at, id_card_photo_override, us_ssn_at, us_ssn, us_ssn_override, sanctions, sanctions_at,
sanctions_override, total_txs, total_spent, LEAST(created, last_transaction) AS last_active, fiat AS last_tx_fiat,
- fiat_code AS last_tx_fiat_code, tx_class AS last_tx_class, subscriber_info, custom_fields, notes, is_test_customer
+ fiat_code AS last_tx_fiat_code, tx_class AS last_tx_class, subscriber_info, subscriber_info_at, custom_fields, notes, is_test_customer
FROM (
SELECT c.id, c.authorized_override,
greatest(0, date_part('day', c.suspended_until - now())) AS days_suspended,
c.suspended_until > now() AS is_suspended,
c.front_camera_path, c.front_camera_override, c.front_camera_at,
- c.phone, c.sms_override, c.id_card_data, c.id_card_data_at, c.id_card_data_override, c.id_card_data_expiration,
+ c.phone, c.phone_at, c.phone_override, c.sms_override, c.id_card_data, c.id_card_data_at, c.id_card_data_override, c.id_card_data_expiration,
c.id_card_photo_path, c.id_card_photo_at, c.id_card_photo_override, c.us_ssn, c.us_ssn_at, c.us_ssn_override, c.sanctions,
- c.sanctions_at, c.sanctions_override, c.subscriber_info, c.is_test_customer, c.created, t.tx_class, t.fiat, t.fiat_code, t.created as last_transaction, cn.notes,
+ c.sanctions_at, c.sanctions_override, c.subscriber_info, c.subscriber_info_at, c.is_test_customer, c.created, t.tx_class, t.fiat, t.fiat_code, t.created as last_transaction, cn.notes,
row_number() OVER (PARTITION BY c.id ORDER BY t.created DESC) AS rn,
sum(CASE WHEN t.id IS NOT NULL THEN 1 ELSE 0 END) OVER (PARTITION BY c.id) AS total_txs,
sum(CASE WHEN error_code IS NULL OR error_code NOT IN ($1^) THEN t.fiat ELSE 0 END) OVER (PARTITION BY c.id) AS total_spent, ccf.custom_fields
diff --git a/lib/new-admin/graphql/types/customer.type.js b/lib/new-admin/graphql/types/customer.type.js
index bf099647..ee85541c 100644
--- a/lib/new-admin/graphql/types/customer.type.js
+++ b/lib/new-admin/graphql/types/customer.type.js
@@ -33,6 +33,7 @@ const typeDef = gql`
lastTxClass: String
transactions: [Transaction]
subscriberInfo: JSONObject
+ phoneOverride: String
customFields: [CustomerCustomField]
customInfoRequests: [CustomRequestData]
notes: [CustomerNote]
@@ -63,12 +64,14 @@ const typeDef = gql`
lastTxClass: String
suspendedUntil: Date
subscriberInfo: Boolean
+ phoneOverride: String
}
input CustomerEdit {
idCardData: JSONObject
idCardPhoto: UploadGQL
usSsn: String
+ subscriberInfo: JSONObject
}
type CustomerNote {
diff --git a/lib/plugins/wallet/mock-wallet/mock-wallet.js b/lib/plugins/wallet/mock-wallet/mock-wallet.js
index f8eb7a7f..5850fefc 100644
--- a/lib/plugins/wallet/mock-wallet/mock-wallet.js
+++ b/lib/plugins/wallet/mock-wallet/mock-wallet.js
@@ -3,7 +3,6 @@ const _ = require('lodash/fp')
const BN = require('../../../bn')
const E = require('../../../error')
const { utils: coinUtils } = require('lamassu-coins')
-const consoleLogLevel = require('console-log-level')
const NAME = 'FakeWallet'
const BATCHABLE_COINS = ['BTC']
diff --git a/migrations/1641482376890-add-overrides-to-subscriber-info.js b/migrations/1641482376890-add-overrides-to-subscriber-info.js
new file mode 100644
index 00000000..192c7e20
--- /dev/null
+++ b/migrations/1641482376890-add-overrides-to-subscriber-info.js
@@ -0,0 +1,17 @@
+var db = require('./db')
+
+exports.up = function (next) {
+ var sql = [
+ `ALTER TABLE customers
+ ADD COLUMN phone_override VERIFICATION_TYPE NOT NULL DEFAULT 'automatic',
+ ADD COLUMN phone_override_by UUID,
+ ADD COLUMN phone_override_at TIMESTAMPTZ
+ `
+ ]
+
+ db.multi(sql, next)
+}
+
+exports.down = function (next) {
+ next()
+}
diff --git a/new-lamassu-admin/src/components/buttons/Button.js b/new-lamassu-admin/src/components/buttons/Button.js
index 6bd24a71..5945170a 100644
--- a/new-lamassu-admin/src/components/buttons/Button.js
+++ b/new-lamassu-admin/src/components/buttons/Button.js
@@ -7,8 +7,15 @@ import styles from './Button.styles'
const useStyles = makeStyles(styles)
const ActionButton = memo(
- ({ size = 'lg', children, className, buttonClassName, ...props }) => {
- const classes = useStyles({ size })
+ ({
+ size = 'lg',
+ children,
+ className,
+ buttonClassName,
+ backgroundColor,
+ ...props
+ }) => {
+ const classes = useStyles({ size, backgroundColor })
return (
+
)
}
+const RetrieveDataDialog = ({
+ setRetrieve,
+ retrieveAdditionalData,
+ open,
+ props
+}) => {
+ const classes = useStyles()
+
+ return (
+
+ )
+}
+
export default CustomerData
diff --git a/new-lamassu-admin/src/pages/Customers/CustomerData.styles.js b/new-lamassu-admin/src/pages/Customers/CustomerData.styles.js
index 373e2f0c..9a4e2871 100644
--- a/new-lamassu-admin/src/pages/Customers/CustomerData.styles.js
+++ b/new-lamassu-admin/src/pages/Customers/CustomerData.styles.js
@@ -1,4 +1,4 @@
-import { offColor } from 'src/styling/variables'
+import { offColor, spacer } from 'src/styling/variables'
export default {
header: {
@@ -45,5 +45,26 @@ export default {
left: '100%',
marginLeft: 15
}
+ },
+ closeButton: {
+ display: 'flex',
+ padding: [[spacer * 2, spacer * 2, 0, spacer * 2]],
+ paddingRight: spacer * 1.5,
+ justifyContent: 'end'
+ },
+ dialogTitle: {
+ margin: [[0, spacer * 2, spacer, spacer * 4 + spacer]]
+ },
+ dialogContent: {
+ width: 615,
+ marginLeft: 16
+ },
+ dialogActions: {
+ padding: spacer * 4,
+ paddingTop: spacer * 2
+ },
+ cancelButton: {
+ marginRight: 8,
+ padding: 0
}
}
diff --git a/new-lamassu-admin/src/pages/Customers/CustomerProfile.js b/new-lamassu-admin/src/pages/Customers/CustomerProfile.js
index 5a0d2314..1d44c02c 100644
--- a/new-lamassu-admin/src/pages/Customers/CustomerProfile.js
+++ b/new-lamassu-admin/src/pages/Customers/CustomerProfile.js
@@ -69,6 +69,8 @@ const GET_CUSTOMER = gql`
daysSuspended
isSuspended
isTestCustomer
+ subscriberInfo
+ phoneOverride
customFields {
id
label
@@ -138,6 +140,7 @@ const SET_CUSTOMER = gql`
lastTxFiatCode
lastTxClass
subscriberInfo
+ phoneOverride
}
}
`
@@ -438,6 +441,16 @@ const CustomerProfile = memo(() => {
}
})
+ const retrieveAdditionalData = () =>
+ setCustomer({
+ variables: {
+ customerId,
+ customerInput: {
+ subscriberInfo: true
+ }
+ }
+ })
+
const onClickSidebarItem = code => setClickedItem(code)
const configData = R.path(['config'])(customerResponse) ?? []
@@ -558,25 +571,6 @@ const CustomerProfile = memo(() => {
}>
{`${blocked ? 'Authorize' : 'Block'} customer`}
-
- setCustomer({
- variables: {
- customerId,
- customerInput: {
- subscriberInfo: true
- }
- }
- })
- }>
- {`Retrieve information`}
-
@@ -628,6 +622,7 @@ const CustomerProfile = memo(() => {
{isCustomerData && (
{
deleteEditedData={deleteEditedData}
updateCustomRequest={setCustomerCustomInfoRequest}
authorizeCustomRequest={authorizeCustomRequest}
- updateCustomEntry={updateCustomEntry}>
+ updateCustomEntry={updateCustomEntry}
+ retrieveAdditionalData={retrieveAdditionalData}>
)}
{isNotes && (
diff --git a/new-lamassu-admin/src/pages/Customers/components/EditableCard.js b/new-lamassu-admin/src/pages/Customers/components/EditableCard.js
index 23f3ffec..e83daa23 100644
--- a/new-lamassu-admin/src/pages/Customers/components/EditableCard.js
+++ b/new-lamassu-admin/src/pages/Customers/components/EditableCard.js
@@ -23,6 +23,8 @@ import { ReactComponent as EditReversedIcon } from 'src/styling/icons/action/edi
import { ReactComponent as AuthorizeIcon } from 'src/styling/icons/button/authorize/white.svg'
import { ReactComponent as BlockIcon } from 'src/styling/icons/button/block/white.svg'
import { ReactComponent as CancelReversedIcon } from 'src/styling/icons/button/cancel/white.svg'
+import { ReactComponent as DataReversedIcon } from 'src/styling/icons/button/data/white.svg'
+import { ReactComponent as DataIcon } from 'src/styling/icons/button/data/zodiac.svg'
import { ReactComponent as ReplaceReversedIcon } from 'src/styling/icons/button/replace/white.svg'
import { ReactComponent as SaveReversedIcon } from 'src/styling/icons/circle buttons/save/white.svg'
import { comet } from 'src/styling/variables'
@@ -67,6 +69,13 @@ const fieldStyles = {
fontSize: 14
}
}
+ },
+ readOnlyLabel: {
+ color: comet,
+ margin: [[3, 0, 3, 0]]
+ },
+ readOnlyValue: {
+ margin: 0
}
}
@@ -105,6 +114,23 @@ const EditableField = ({ editing, field, value, size, ...props }) => {
)
}
+const ReadOnlyField = ({ field, value, ...props }) => {
+ const classes = fieldUseStyles()
+ const classNames = {
+ [classes.field]: true,
+ [classes.notEditing]: true
+ }
+
+ return (
+ <>
+
+
{field.label}
+
{value}
+
+ >
+ )
+}
+
const EditableCard = ({
fields,
save,
@@ -117,7 +143,9 @@ const EditableCard = ({
children,
validationSchema,
initialValues,
- deleteEditedData
+ deleteEditedData,
+ retrieveAdditionalData,
+ hasAdditionalData = true
}) => {
const classes = useStyles()
@@ -174,7 +202,7 @@ const EditableCard = ({
setEditing(false)
setError(false)
}}>
- {({ values, touched, errors, setFieldValue }) => (
+ {({ setFieldValue }) => (