-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #50 from dimagi/sr/payments
Capture Payment Phone numbers
- Loading branch information
Showing
14 changed files
with
381 additions
and
30 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
from django.apps import AppConfig | ||
|
||
|
||
class PaymentsConfig(AppConfig): | ||
default_auto_field = 'django.db.models.BigAutoField' | ||
name = 'payments' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
# Generated by Django 4.1.7 on 2024-11-09 10:16 | ||
|
||
from django.conf import settings | ||
from django.db import migrations, models | ||
import django.db.models.deletion | ||
import phonenumber_field.modelfields | ||
|
||
|
||
class Migration(migrations.Migration): | ||
|
||
initial = True | ||
|
||
dependencies = [ | ||
migrations.swappable_dependency(settings.AUTH_USER_MODEL), | ||
] | ||
|
||
operations = [ | ||
migrations.CreateModel( | ||
name='PaymentProfile', | ||
fields=[ | ||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), | ||
('phone_number', phonenumber_field.modelfields.PhoneNumberField(max_length=128, region=None)), | ||
('owner_name', models.TextField(max_length=150, blank=True)), | ||
('telecom_provider', models.CharField(blank=True, max_length=50, null=True)), | ||
('is_verified', models.BooleanField(default=False)), | ||
('status', models.CharField(choices=[('pending', 'Pending'), ('approved', 'Approved'), ('rejected', 'Rejected')], default='pending', max_length=10)), | ||
('created_at', models.DateTimeField(auto_now_add=True)), | ||
('updated_at', models.DateTimeField(auto_now=True)), | ||
('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='payment_profile', to=settings.AUTH_USER_MODEL)), | ||
], | ||
), | ||
] |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
from django.db import models | ||
|
||
from phonenumber_field.modelfields import PhoneNumberField | ||
from users.models import ConnectUser | ||
|
||
|
||
class PaymentProfile(models.Model): | ||
PENDING = 'pending' | ||
APPROVED = 'approved' | ||
REJECTED = 'rejected' | ||
|
||
STATUS_CHOICES = [ | ||
(PENDING, 'Pending'), | ||
(APPROVED, 'Approved'), | ||
(REJECTED, 'Rejected'), | ||
] | ||
|
||
user = models.OneToOneField( | ||
ConnectUser, | ||
on_delete=models.CASCADE, | ||
related_name='payment_profile' | ||
) | ||
phone_number = PhoneNumberField() | ||
owner_name = models.TextField(max_length=150, blank=True) | ||
telecom_provider = models.CharField(max_length=50, blank=True, null=True) | ||
# whether the number is verified using OTP | ||
is_verified = models.BooleanField(default=False) | ||
status = models.CharField( | ||
max_length=10, | ||
choices=STATUS_CHOICES, | ||
default=PENDING, | ||
) | ||
created_at = models.DateTimeField(auto_now_add=True) | ||
updated_at = models.DateTimeField(auto_now=True) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
import base64 | ||
import pytest | ||
|
||
from django.urls import reverse | ||
from rest_framework import status | ||
|
||
from messaging.tests import APPLICATION_JSON | ||
from payments.models import PaymentProfile | ||
from users.factories import UserFactory | ||
|
||
|
||
@pytest.mark.parametrize( | ||
"data, expected_status, expected_user1_status, expected_user2_status, result", | ||
[ | ||
# Scenario 1: Update both statuses successfully | ||
( | ||
[ | ||
{"username": "user1", "status": "approved"}, | ||
{"username": "user2", "status": "rejected"}, | ||
], | ||
status.HTTP_200_OK, | ||
"approved", | ||
"rejected", | ||
{"approved": 1, "rejected": 1, "pending": 0} | ||
), | ||
# Scenario 2: No change in status | ||
( | ||
[ | ||
{"username": "user2", "status": "approved"}, | ||
], | ||
status.HTTP_200_OK, | ||
"pending", # Should remain unchanged | ||
"approved", # Should remain unchanged | ||
{"approved": 0, "rejected": 0, "pending": 0} | ||
), | ||
# Scenario 3: Invalid user (user doesn't exist) | ||
( | ||
[ | ||
{"username": "nonexistent_user", "status": "rejected"}, | ||
], | ||
status.HTTP_404_NOT_FOUND, | ||
"pending", # No change | ||
"approved", # No change | ||
{} | ||
), | ||
# Scenario 4: Multiple users, one invalid | ||
( | ||
[ | ||
{"username": "user1", "status": "approved"}, | ||
{"username": "nonexistent_user", "status": "rejected"}, | ||
], | ||
status.HTTP_404_NOT_FOUND, | ||
"pending", # No change | ||
"approved", # No change | ||
{} | ||
), | ||
] | ||
) | ||
def test_validate_phone_numbers(authed_client, data, expected_status, expected_user1_status, expected_user2_status, result): | ||
user1 = UserFactory(username="user1") | ||
user2 = UserFactory(username="user2") | ||
PaymentProfile.objects.create(user=user1, phone_number="12345", status="pending") | ||
PaymentProfile.objects.create(user=user2, phone_number="67890", status="approved") | ||
|
||
url = reverse("validate_payment_phone_numbers") | ||
|
||
response = authed_client.post(url, {"updates": data}, content_type=APPLICATION_JSON) | ||
|
||
assert response.status_code == expected_status | ||
|
||
profile1 = PaymentProfile.objects.get(user=user1) | ||
profile2 = PaymentProfile.objects.get(user=user2) | ||
|
||
assert profile1.status == expected_user1_status | ||
assert profile2.status == expected_user2_status | ||
if response.status_code == 200: | ||
assert response.json()["result"] == result | ||
|
||
|
||
def test_fetch_phone_numbers(authed_client): | ||
user1 = UserFactory(username="user1") | ||
user2 = UserFactory(username="user2") | ||
PaymentProfile.objects.create(user=user1, phone_number="12345", status="pending") | ||
PaymentProfile.objects.create(user=user2, phone_number="67890", status="approved") | ||
|
||
url = reverse("fetch_payment_phone_numbers") | ||
|
||
response = authed_client.get(url, {"usernames": ["user1", "user2"]}) | ||
assert len(response.json()['found_payment_numbers']) == 2 | ||
|
||
response = authed_client.get(url, {"usernames": ["user1", "user2"], "status": "pending"}) | ||
assert len(response.json()['found_payment_numbers']) == 1 | ||
|
||
response = authed_client.get(url, {"usernames": ["user1"], "status": "approved"}) | ||
assert len(response.json()['found_payment_numbers']) == 0 |
Oops, something went wrong.