-
-
Notifications
You must be signed in to change notification settings - Fork 221
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
KYC Service Layer #35774
base: master
Are you sure you want to change the base?
KYC Service Layer #35774
Conversation
da063e7
to
171bf21
Compare
1dd08f4
to
6e02dc4
Compare
Form validation still works because it is a ModelForm.
6e02dc4
to
65f119b
Compare
65f119b
to
143f16c
Compare
To avoid confusion, please don't merge until #35765 has been merged. |
@@ -1172,6 +1172,14 @@ def _pkce_required(client_id): | |||
# used by periodic tasks that delete soft deleted data older than PERMANENT_DELETION_WINDOW days | |||
PERMANENT_DELETION_WINDOW = 30 # days | |||
|
|||
# Used by `corehq.apps.integration.kyc`. Override in localsettings.py | |||
MTN_KYC_CONNECTION_SETTINGS = { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(I am probably behind on recent updates with MTN )
What is the rationale for having a common connection settings ? With this not be project specific ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It turns out that the API service provider will have a contract with the platform provider (i.e. Dimagi), and will grant access to them, and not to each project ...
... which has just made me think that saving the ConnectionSettings instance is not a good idea. Projects/users can't read the secrets of ConnectionSettings instances, but they can change them. So either we need to have a way to write-protect ConnectioinSettings, or we need to create them on the fly without persisting them.
@@ -52,6 +53,21 @@ class Meta: | |||
models.UniqueConstraint(fields=['domain', 'provider'], name='unique_domain_provider'), | |||
] | |||
|
|||
def clean(self): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Cool 👍
def verify_users(user_objs, config): | ||
# TODO: An endpoint to verify a group of users does not seem to be | ||
# available using Chenosis. If we have to do this with | ||
# multiple calls, consider using Celery gevent workers. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💯
for user_obj in user_objs: | ||
is_verified = verify_user(user_obj, config) | ||
save_result(user_obj, config, is_verified) | ||
results.append(is_verified) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I feel like having just verification results is not very helpful to the caller. Consider adding an identifier (e.g. user_id
) along with the verification result.
results.append(
{
'user_id': 'abc',
'is_verified': True,
}
)
config.domain, | ||
case.case_id, | ||
case_properties=update, | ||
device_id='corehq.apps.integration.kyc.services.save_result', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: Consider using device_id=__name__ + '.save_result'
@@ -18,6 +20,9 @@ class UserDataStore(object): | |||
|
|||
|
|||
class KycProviders(models.TextChoices): | |||
# When adding a new provider: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It would be good to have a short documentation for steps to add a new provider.
Could be done in the follow up work along with TODOs.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks Norman for working on this.
This is looking quite good. Left some minor queries and suggestions.
|
||
# TODO: Determine what thresholds we want | ||
required_thresholds = { | ||
'firstName': 100, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@kaapstorm How do these scores function?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It looks like a percentage of how close the value that was submitted is to the value that MTN has on record. We haven't been able to test this yet, because we don't (yet) have credentials we can use for testing.
Just a note: I see a lot of places where we check the That said, I think the approach in this PR is OK as is since I don't think this particular feature will see new data stores being added frequently (if ever). |
If a field is in a user's usercase, or custom user data, then use that, otherwise fall back to a CommCareUser property. Only allow safe properties.
|
||
def save_result(user_obj, config, is_verified): | ||
update = { | ||
'kyc_provider': config.provider.value, # TODO: Or config.provider.label? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
config.provider.value
does not work as provider is the actual string value.
'kyc_provider': config.provider.value, # TODO: Or config.provider.label? | |
'kyc_provider': config.provider, # TODO: Or config.provider.get_provider_display()? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am bit inclined towards storing the value here in case we want to make a conditional check on this later.
I think this is a good idea. It might be out of scope for this PR, but worth looking at in a follow-up PR. |
Technical Summary
Jira: SC-4128, SC-4139
Base branch: #35765
This change adds a service layer to the KYC integration that makes API calls and parses the responses.
Feature Flag
KYC_VERIFICATION
Safety Assurance
Safety story
We are unable to test API calls yet. We are waiting for a service provider to grant us access to the API.
Automated test coverage
Tests included. More tests to follow once we have settled on return values.
Rollback instructions
Labels & Review