Skip to content

Commit

Permalink
Likhith/87594/trigger onfido checks for high risk client (binary-com#…
Browse files Browse the repository at this point in the history
…7646)

* feat: added onfido check for high risk client

* feat: ⚡ Incorporated POA for Labuan when status is idv_photoid

* fix: failing testcase

* feat: reverted the change

* feat: added missing config

* feat: added POA

* feat: ✨ added POA trigger for IDV+photot status

* fix: ♻️ incorporated review comments

* chore: incorporated review comments

* feat: ✨ incorporated IDV revoked status

* refactor: ♻️ refactored code

* refactor: ♻️ incorporated review comments

* feat: ♻️ incorporated review comments

* feat: resolved issue with POA

* fix: 🐛 Trigger POA only in user is idv+photo verified for labuan

* fix: ✨ incorporated Resubmission triggers

* feat: incorporated testcases

* chore: trigger rebuild

* fix: resolved issue with POA trigger for idv+photo clients

* chore: 💚 trigger build

* fix: 🐛 resolved bugs regd high risk DBVI account

* Likhith/incorporate deriv hooks (#42)

* feat: ✨ installed deriv-hooks

* feat: ✨ incorporated a new hook

* fix: ✅ added testcase

* feat: incorporated hook

* fix: 🎨 reverted changes of hooks implementation

* fix: ⚡ added testcases

---------

Co-authored-by: Matin shafiei <matin@deriv.com>
  • Loading branch information
likhith-deriv and matin-deriv committed Jul 26, 2023
1 parent 0553c82 commit 5d6150f
Show file tree
Hide file tree
Showing 15 changed files with 336 additions and 65 deletions.
1 change: 1 addition & 0 deletions packages/account/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
"@binary-com/binary-document-uploader": "^2.4.7",
"@deriv/api-types": "^1.0.94",
"@deriv/components": "^1.0.0",
"@deriv/hooks": "^1.0.0",
"@deriv/shared": "^1.0.0",
"@deriv/stores":"^1.0.0",
"@deriv/translations": "^1.0.0",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
type TPoaStatusCodes = Readonly<Record<'none' | 'pending' | 'rejected' | 'verified' | 'expired' | 'suspected', string>>;
import { TVerificationStatus } from 'Types';

export const poa_status_codes: TPoaStatusCodes = {
export const poa_status_codes: TVerificationStatus = {
none: 'none',
pending: 'pending',
rejected: 'rejected',
Expand Down
4 changes: 4 additions & 0 deletions packages/account/src/Types/common-prop.type.ts
Original file line number Diff line number Diff line change
Expand Up @@ -149,3 +149,7 @@ export type TPersonalDetailsForm = {
} & FormikProps<FormikValues>;

export type TInputFieldValues = Record<string, string>;

export type TVerificationStatus = Readonly<
Record<'none' | 'pending' | 'rejected' | 'verified' | 'expired' | 'suspected', string>
>;
76 changes: 60 additions & 16 deletions packages/appstore/src/components/cfds-listing/index.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
import React from 'react';
import { observer } from 'mobx-react-lite';
import { Text, StaticUrl } from '@deriv/components';
import { isMobile, formatMoney, getAuthenticationStatusInfo, Jurisdiction } from '@deriv/shared';
import { localize, Localize } from '@deriv/translations';
import ListingContainer from 'Components/containers/listing-container';
import './cfds-listing.scss';
import { useStores } from 'Stores/index';
import { observer } from 'mobx-react-lite';
import AddOptionsAccount from 'Components/add-options-account';
import { isMobile, formatMoney } from '@deriv/shared';
import TradingAppCard from 'Components/containers/trading-app-card';
import { AvailableAccount, TDetailsOfEachMT5Loginid } from 'Types';
import PlatformLoader from 'Components/pre-loader/platform-loader';
import GetMoreAccounts from 'Components/get-more-accounts';
import { Actions } from 'Components/containers/trading-app-card-actions';
import { getHasDivider } from 'Constants/utils';
import { useStores } from 'Stores/index';
import { AvailableAccount, TDetailsOfEachMT5Loginid } from 'Types';
import './cfds-listing.scss';

type TDetailedExistingAccount = AvailableAccount &
TDetailsOfEachMT5Loginid &
Expand Down Expand Up @@ -55,18 +55,57 @@ const CFDsListing = () => {
} = traders_hub;

const { toggleCompareAccountsModal, setAccountType } = cfd;
const { is_landing_company_loaded, real_account_creation_unlock_date } = client;
const { is_landing_company_loaded, real_account_creation_unlock_date, account_status } = client;
const { setAppstorePlatform } = common;
const { openDerivRealAccountNeededModal, setShouldShowCooldownModal } = ui;
const has_no_real_account = !has_any_real_account;
const accounts_sub_text =
!is_eu_user || is_demo_low_risk ? localize('Compare accounts') : localize('Account Information');

const getMT5AccountAuthStatus = (current_acc_status: string) => {
if (current_acc_status === 'proof_failed') {
return 'failed';
} else if (current_acc_status === 'verification_pending') {
return 'pending';
const { poi_pending_for_bvi_labuan, poi_resubmit_for_bvi_labuan, poa_resubmit_for_labuan, is_idv_revoked } =
getAuthenticationStatusInfo(account_status);

const getAuthStatus = (status_list: boolean[]) => status_list.some(status => status);

const getMT5AccountAuthStatus = (current_acc_status: string, jurisdiction?: string) => {
if (jurisdiction) {
switch (jurisdiction) {
case Jurisdiction.BVI: {
if (
getAuthStatus([
is_idv_revoked,
poi_resubmit_for_bvi_labuan,
current_acc_status === 'proof_failed',
])
) {
return 'failed';
} else if (
getAuthStatus([poi_pending_for_bvi_labuan, current_acc_status === 'verification_pending'])
) {
return 'pending';
}
return null;
}
case Jurisdiction.LABUAN: {
if (
getAuthStatus([
poa_resubmit_for_labuan,
is_idv_revoked,
poi_resubmit_for_bvi_labuan,
current_acc_status === 'proof_failed',
])
) {
return 'failed';
} else if (
getAuthStatus([poi_pending_for_bvi_labuan, current_acc_status === 'verification_pending'])
) {
return 'pending';
}
return null;
}
default:
return null;
}
}
return null;
};
Expand Down Expand Up @@ -137,12 +176,17 @@ const CFDsListing = () => {
</Text>
</div>
{is_landing_company_loaded ? (
<>
<React.Fragment>
{combined_cfd_mt5_accounts.map((existing_account: TDetailedExistingAccount, index: number) => {
const list_size = combined_cfd_mt5_accounts.length;
const has_mt5_account_status = existing_account.status
? getMT5AccountAuthStatus(existing_account.status)
: null;
const has_mt5_account_status =
existing_account.status || is_idv_revoked
? getMT5AccountAuthStatus(
existing_account.status,
existing_account?.short_code_and_region?.toLowerCase()
)
: null;

return (
<TradingAppCard
action_type={existing_account.action_type}
Expand Down Expand Up @@ -202,7 +246,7 @@ const CFDsListing = () => {
description={localize('Get more Deriv MT5 account with different type and jurisdiction.')}
/>
)}
</>
</React.Fragment>
) : (
<PlatformLoader />
)}
Expand Down
1 change: 1 addition & 0 deletions packages/cfd/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@
"@deriv/api-types": "^1.0.94",
"@deriv/components": "^1.0.0",
"@deriv/deriv-api": "^1.0.11",
"@deriv/hooks": "^1.0.0",
"@deriv/shared": "^1.0.0",
"@deriv/stores": "^1.0.0",
"@deriv/translations": "^1.0.0",
Expand Down
36 changes: 24 additions & 12 deletions packages/cfd/src/Components/cfd-poa.tsx
Original file line number Diff line number Diff line change
@@ -1,24 +1,25 @@
import { Field, Formik, FieldProps, FormikHelpers, FormikProps, FormikErrors } from 'formik';
import React from 'react';
import { Field, FieldProps, Formik, FormikErrors, FormikHelpers, FormikProps } from 'formik';
import { AccountStatusResponse, GetSettings, StatesList } from '@deriv/api-types';
import {
AutoHeightWrapper,
FormSubmitButton,
ThemedScrollbars,
DesktopWrapper,
Div100vhContainer,
Dropdown,
FormSubmitButton,
Loading,
Div100vhContainer,
MobileWrapper,
Modal,
SelectNative,
DesktopWrapper,
MobileWrapper,
useStateCallback,
Text,
ThemedScrollbars,
useStateCallback,
} from '@deriv/components';
import { FileUploaderContainer, FormSubHeader, PoaStatusCodes } from '@deriv/account';
import { localize } from '@deriv/translations';
import { isDesktop, isMobile, validAddress, validLength, validLetterSymbol, validPostCode, WS } from '@deriv/shared';
import { WS, isDesktop, isMobile, validAddress, validLength, validLetterSymbol, validPostCode } from '@deriv/shared';
import { InputField } from './cfd-personal-details-form';
import { GetSettings, StatesList, AccountStatusResponse } from '@deriv/api-types';
import { TJurisdiction } from '../../types';

type TErrors = {
code: string;
Expand Down Expand Up @@ -79,19 +80,29 @@ export type TCFDPOAProps = {
onSubmit: (index: number, value: TFormValues) => void;
refreshNotifications: () => void;
form_error: string;
get_settings: GetSettings;
account_settings: GetSettings;
height: string;
states_list: StatesList;
storeProofOfAddress: TStoreProofOfAddress;
value: TFormValue;
jurisdiction_selected_shortcode: TJurisdiction;
is_authenticated_with_idv_photoid: boolean;
};
type TUpload = {
upload: () => void;
};

let file_uploader_ref: React.RefObject<HTMLElement & TUpload>;

const CFDPOA = ({ onSave, index, onSubmit, refreshNotifications, ...props }: TCFDPOAProps) => {
const CFDPOA = ({
onSave,
index,
onSubmit,
refreshNotifications,
jurisdiction_selected_shortcode,
is_authenticated_with_idv_photoid,
...props
}: TCFDPOAProps) => {
const form = React.useRef<FormikProps<TFormValues> | null>(null);

const [is_loading, setIsLoading] = React.useState(true);
Expand Down Expand Up @@ -259,7 +270,8 @@ const CFDPOA = ({ onSave, index, onSubmit, refreshNotifications, ...props }: TCF
} = props;
const { form_error, poa_status } = form_state;

const is_form_visible = !is_loading && poa_status !== PoaStatusCodes.verified;
const is_form_visible =
!is_loading && (poa_status !== PoaStatusCodes.verified || is_authenticated_with_idv_photoid);

return (
<Formik
Expand Down
Original file line number Diff line number Diff line change
@@ -1,23 +1,44 @@
import React from 'react';
import { fireEvent, render, screen } from '@testing-library/react';
import { render, screen } from '@testing-library/react';
import CFDFinancialStpRealAccountSignup from '../cfd-financial-stp-real-account-signup';
import CFDProviders from '../../cfd-providers';
import { mockStore } from '@deriv/stores';
import { getAuthenticationStatusInfo } from '@deriv/shared';

jest.mock('@deriv/account', () => ({
...jest.requireActual('@deriv/account'),
FormSubHeader: () => <div>FormSubHeader</div>,
}));

jest.mock('../../Components/cfd-poa', () => jest.fn(() => <div> CFDPOA</div>));
const MockComponent = ({ prevStep, nextStep }) => (
<div>
<button onClick={prevStep}>Prev Step</button>
<button onClick={() => nextStep(0, {})}>Next Step</button>
</div>
);

jest.mock('../../Components/cfd-poa', () =>
jest.fn(({ onCancel, onSubmit }) => (
<div>
CFDPOA
<MockComponent prevStep={onCancel} nextStep={onSubmit} />
</div>
))
);
jest.mock('../../Components/cfd-poi', () =>
jest.fn(({ onSubmit }) => (
<div data-testid='poa-form' onClick={() => onSubmit(0, {})}>
jest.fn(({ onCancel, onSubmit }) => (
<div>
CFDPOI
<MockComponent prevStep={onCancel} nextStep={onSubmit} />
</div>
))
);

jest.mock('@deriv/shared', () => ({
...jest.requireActual('@deriv/shared'),
getAuthenticationStatusInfo: jest.fn().mockReturnValue({}),
}));

const getByTextFn = (text, should_be) => {
if (should_be) {
expect(screen.getByText(text)).toBeInTheDocument();
Expand All @@ -26,14 +47,6 @@ const getByTextFn = (text, should_be) => {
}
};

const toHavaClassFn = (item, class_name, should_have) => {
if (should_have) {
expect(item).toHaveClass(class_name);
} else {
expect(item).not.toHaveClass(class_name);
}
};

const testAllStepsFn = (steps, step_no) => {
steps.map((step, index) => {
if (index === step_no) {
Expand Down Expand Up @@ -181,6 +194,7 @@ describe('<CFDFinancialStpRealAccountSignup />', () => {
});

it('should render properly for the first step content', () => {
getAuthenticationStatusInfo.mockReturnValueOnce({ need_poi_for_bvi_labuan: true });
render(<CFDFinancialStpRealAccountSignup />, {
wrapper: ({ children }) => <CFDProviders store={mockStore(mockRootStore)}>{children}</CFDProviders>,
});
Expand All @@ -189,14 +203,51 @@ describe('<CFDFinancialStpRealAccountSignup />', () => {
});

it('should render properly for the second step content', () => {
getAuthenticationStatusInfo.mockReturnValueOnce({ poa_resubmit_for_labuan: true });
const { getByTestId } = render(<CFDFinancialStpRealAccountSignup />, {
wrapper: ({ children }) => <CFDProviders store={mockStore(mockRootStore)}>{children}</CFDProviders>,
});

const div = getByTestId('poa-form');
testAllStepsFn(steps, 1);
});

fireEvent.click(div);
it('should check for POI status when Jurisdiction is Vanuatu or maltainvest', () => {
const new_mock_store = {
...mockRootStore,
modules: {
...mockRootStore.modules,
cfd: {
...mockRootStore.modules.cfd,
jurisdiction_selected_shortcode: 'vanuatu',
},
},
};

getAuthenticationStatusInfo.mockReturnValueOnce({ need_poi_for_vanuatu_maltainvest: true });

render(<CFDFinancialStpRealAccountSignup />, {
wrapper: ({ children }) => <CFDProviders store={mockStore(new_mock_store)}>{children}</CFDProviders>,
});
testAllStepsFn(steps, 0);
});

it('should check for POA status when Jurisdiction is Labuan and resubmit status is set to true', () => {
const new_mock_store = {
...mockRootStore,
modules: {
...mockRootStore.modules,
cfd: {
...mockRootStore.modules.cfd,
jurisdiction_selected_shortcode: 'labuan',
},
},
};

getAuthenticationStatusInfo.mockReturnValueOnce({ need_poi_for_vanuatu_maltainvest: true });

render(<CFDFinancialStpRealAccountSignup />, {
wrapper: ({ children }) => <CFDProviders store={mockStore(new_mock_store)}>{children}</CFDProviders>,
});
testAllStepsFn(steps, 1);
});
});
Loading

0 comments on commit 5d6150f

Please sign in to comment.