Skip to content
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

Open
wants to merge 11 commits into
base: master
Choose a base branch
from
Open

KYC Service Layer #35774

wants to merge 11 commits into from

Conversation

kaapstorm
Copy link
Contributor

@kaapstorm kaapstorm commented Feb 13, 2025

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

  • This PR can be reverted after deploy with no further considerations

Labels & Review

  • Risk label is set correctly
  • The set of people pinged as reviewers is appropriate for the level of risk of the change

@kaapstorm kaapstorm added the product/invisible Change has no end-user visible impact label Feb 13, 2025
@dimagimon dimagimon added the reindex/migration Reindex or migration will be required during or before deploy label Feb 16, 2025
@kaapstorm kaapstorm changed the base branch from master to ze/kyc-verify-report February 17, 2025 14:16
@kaapstorm kaapstorm marked this pull request as ready for review February 17, 2025 14:18
@kaapstorm
Copy link
Contributor Author

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 = {
Copy link
Contributor

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 ?

Copy link
Contributor Author

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):
Copy link
Contributor

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.
Copy link
Contributor

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)
Copy link
Contributor

@ajeety4 ajeety4 Feb 18, 2025

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',
Copy link
Contributor

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:
Copy link
Contributor

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.

Copy link
Contributor

@ajeety4 ajeety4 left a 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,
Copy link
Contributor

@Charl1996 Charl1996 Feb 18, 2025

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?

Copy link
Contributor Author

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.

@Charl1996
Copy link
Contributor

Just a note:

I see a lot of places where we check the user_data_store on the KycProviders config. This makes me think that something like the adapter pattern might come in handy here where the service makes use of the adapter to interact with the various underlying data store models. That way we could always just query the adapter for data-store-specific actions/data instead of having if-else blocks. The adapter pattern will also make is very easy to add new data stores, since we would only have to implement the new adapter with the various ways in which data can be read from/written to this potentially new data store without having to update if-else blocks.

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).

Base automatically changed from ze/kyc-verify-report to master February 18, 2025 10:45
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?
Copy link
Contributor

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.

Suggested change
'kyc_provider': config.provider.value, # TODO: Or config.provider.label?
'kyc_provider': config.provider, # TODO: Or config.provider.get_provider_display()?

Copy link
Contributor

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.

@kaapstorm
Copy link
Contributor Author

the adapter pattern might come in handy here

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
product/invisible Change has no end-user visible impact reindex/migration Reindex or migration will be required during or before deploy
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants