mirror of
https://github.com/i701/sarlink-portal-api.git
synced 2025-04-19 23:46:53 +00:00
Enhance VerifyPaymentView with user authorization check, streamline payment verification process, and improve response messages. Update settings.py for consistent formatting and clarity in PASSWORDLESS_AUTH configuration.
All checks were successful
Build and Push Docker Images / Build and Push Docker Images (push) Successful in 2m53s
All checks were successful
Build and Push Docker Images / Build and Push Docker Images (push) Successful in 2m53s
This commit is contained in:
parent
9595476569
commit
f8253d572d
@ -104,57 +104,57 @@ class VerifyPaymentView(StaffEditorPermissionMixin, generics.UpdateAPIView):
|
|||||||
lookup_field = "pk"
|
lookup_field = "pk"
|
||||||
|
|
||||||
def update(self, request, *args, **kwargs):
|
def update(self, request, *args, **kwargs):
|
||||||
|
# TODO: Fix check for success payment
|
||||||
|
payment = self.get_object()
|
||||||
data = request.data
|
data = request.data
|
||||||
user = request.user
|
user = request.user
|
||||||
|
if payment.user != user and not user.is_superuser:
|
||||||
|
return Response(
|
||||||
|
{"message": "You are not authorized to verify this payment."},
|
||||||
|
status=status.HTTP_403_FORBIDDEN,
|
||||||
|
)
|
||||||
method = data.get("method")
|
method = data.get("method")
|
||||||
payment_id = kwargs.get("pk")
|
|
||||||
if not method:
|
if not method:
|
||||||
return Response(
|
return Response(
|
||||||
{"message": "method is required. 'WALLET' or 'TRANSFER'"},
|
{"message": "method is required. 'WALLET' or 'TRANSFER'"},
|
||||||
status=status.HTTP_400_BAD_REQUEST,
|
status=status.HTTP_400_BAD_REQUEST,
|
||||||
)
|
)
|
||||||
if not payment_id:
|
|
||||||
return Response(
|
|
||||||
{"message": "payment_id is required."},
|
|
||||||
status=status.HTTP_400_BAD_REQUEST,
|
|
||||||
)
|
|
||||||
|
|
||||||
try:
|
|
||||||
payment = Payment.objects.get(id=payment_id)
|
|
||||||
devices = payment.devices.all()
|
devices = payment.devices.all()
|
||||||
|
payment_status = False
|
||||||
|
if method == "WALLET":
|
||||||
|
payment_status = self.process_wallet_payment(
|
||||||
|
user,
|
||||||
|
payment,
|
||||||
|
)
|
||||||
|
if method == "TRANSFER":
|
||||||
|
data = {
|
||||||
|
"benefName": f"{user.first_name} {user.last_name}",
|
||||||
|
"accountNo": user.acc_no,
|
||||||
|
"absAmount": payment.amount,
|
||||||
|
"time": (timezone.now() + timedelta(minutes=5)).strftime(
|
||||||
|
"%Y-%m-%d %H:%M"
|
||||||
|
),
|
||||||
|
}
|
||||||
|
payment_status = self.verify_transfer_payment(data, payment)
|
||||||
|
|
||||||
if data["type"] == "WALLET":
|
if payment_status:
|
||||||
print("processing WALLET payment")
|
|
||||||
self.process_wallet_payment(user, payment, float(data["abs_amount"]))
|
|
||||||
elif data["type"] == "TRANSFER":
|
|
||||||
self.verify_external_payment(data, payment)
|
|
||||||
|
|
||||||
# Update devices
|
# Update devices
|
||||||
expiry_date = timezone.now() + timedelta(days=30 * payment.number_of_months)
|
expiry_date = timezone.now() + timedelta(days=30 * payment.number_of_months)
|
||||||
devices.update(
|
devices.update(
|
||||||
is_active=True, expiry_date=expiry_date, has_a_pending_payment=False
|
is_active=True, expiry_date=expiry_date, has_a_pending_payment=False
|
||||||
)
|
)
|
||||||
|
|
||||||
return Response({"message": "Payment verified successfully."})
|
|
||||||
|
|
||||||
except Payment.DoesNotExist:
|
|
||||||
return Response(
|
return Response(
|
||||||
{"message": "Payment not found."}, status=status.HTTP_404_NOT_FOUND
|
{"message": f"Payment verified successfully using [{method}]."}
|
||||||
)
|
|
||||||
except InsufficientFundsError:
|
|
||||||
return Response(
|
|
||||||
{"message": "Insufficient funds in wallet."},
|
|
||||||
status=status.HTTP_400_BAD_REQUEST,
|
|
||||||
)
|
|
||||||
except Exception as e:
|
|
||||||
return Response(
|
|
||||||
{"message": str(e)}, status=status.HTTP_500_INTERNAL_SERVER_ERROR
|
|
||||||
)
|
)
|
||||||
|
|
||||||
def process_wallet_payment(self, user, payment, amount):
|
return Response({"message": "Payment verified successfully using [{method}]."})
|
||||||
print("processing wallet payment")
|
|
||||||
print(user, amount)
|
def process_wallet_payment(self, user, payment):
|
||||||
if user.wallet_balance < amount:
|
print("processing wallet payment...")
|
||||||
|
print(user, payment.amount)
|
||||||
|
if user.wallet_balance < payment.amount:
|
||||||
return Response(
|
return Response(
|
||||||
{"message": "Insufficient funds in wallet."},
|
{"message": "Insufficient funds in wallet."},
|
||||||
status=status.HTTP_400_BAD_REQUEST,
|
status=status.HTTP_400_BAD_REQUEST,
|
||||||
@ -165,10 +165,12 @@ class VerifyPaymentView(StaffEditorPermissionMixin, generics.UpdateAPIView):
|
|||||||
payment.method = "WALLET"
|
payment.method = "WALLET"
|
||||||
payment.save()
|
payment.save()
|
||||||
|
|
||||||
user.wallet_balance -= amount
|
user.wallet_balance -= payment.amount
|
||||||
user.save()
|
user.save()
|
||||||
|
return True
|
||||||
|
|
||||||
def verify_external_payment(self, data, payment):
|
def verify_transfer_payment(self, data, payment):
|
||||||
|
print("verifying transfer payment...")
|
||||||
response = requests.post(
|
response = requests.post(
|
||||||
f"{config('PAYMENT_VERIFY_BASE_URL')}/verify-payment",
|
f"{config('PAYMENT_VERIFY_BASE_URL')}/verify-payment",
|
||||||
json=data,
|
json=data,
|
||||||
@ -177,7 +179,11 @@ class VerifyPaymentView(StaffEditorPermissionMixin, generics.UpdateAPIView):
|
|||||||
response.raise_for_status()
|
response.raise_for_status()
|
||||||
print(response.json())
|
print(response.json())
|
||||||
if not response.json().get("success"):
|
if not response.json().get("success"):
|
||||||
raise Exception("Payment verification failed.")
|
return Response(
|
||||||
|
{"message": "MIB Payment verification failed."},
|
||||||
|
status=status.HTTP_400_BAD_REQUEST,
|
||||||
|
)
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
class DeletePaymentView(StaffEditorPermissionMixin, generics.DestroyAPIView):
|
class DeletePaymentView(StaffEditorPermissionMixin, generics.DestroyAPIView):
|
||||||
|
@ -1,79 +1,59 @@
|
|||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from rest_framework.settings import APISettings
|
from rest_framework.settings import APISettings
|
||||||
|
|
||||||
USER_SETTINGS = getattr(settings, 'PASSWORDLESS_AUTH', None)
|
USER_SETTINGS = getattr(settings, "PASSWORDLESS_AUTH", None)
|
||||||
|
|
||||||
DEFAULTS = {
|
DEFAULTS = {
|
||||||
# Allowed auth types, can be EMAIL, MOBILE, or both.
|
# Allowed auth types, can be EMAIL, MOBILE, or both.
|
||||||
'PASSWORDLESS_AUTH_TYPES': ['EMAIL'],
|
"PASSWORDLESS_AUTH_TYPES": ["EMAIL"],
|
||||||
|
|
||||||
# Amount of time that tokens last, in seconds
|
# Amount of time that tokens last, in seconds
|
||||||
'PASSWORDLESS_TOKEN_EXPIRE_TIME': 15 * 60,
|
"PASSWORDLESS_TOKEN_EXPIRE_TIME": 15 * 60,
|
||||||
|
|
||||||
# The user's email field name
|
# The user's email field name
|
||||||
'PASSWORDLESS_USER_EMAIL_FIELD_NAME': 'email',
|
"PASSWORDLESS_USER_EMAIL_FIELD_NAME": "email",
|
||||||
|
|
||||||
# The user's mobile field name
|
# The user's mobile field name
|
||||||
'PASSWORDLESS_USER_MOBILE_FIELD_NAME': 'mobile',
|
"PASSWORDLESS_USER_MOBILE_FIELD_NAME": "mobile",
|
||||||
|
|
||||||
# Marks itself as verified the first time a user completes auth via token.
|
# Marks itself as verified the first time a user completes auth via token.
|
||||||
# Automatically unmarks itself if email is changed.
|
# Automatically unmarks itself if email is changed.
|
||||||
'PASSWORDLESS_USER_MARK_EMAIL_VERIFIED': False,
|
"PASSWORDLESS_USER_MARK_EMAIL_VERIFIED": False,
|
||||||
'PASSWORDLESS_USER_EMAIL_VERIFIED_FIELD_NAME': 'email_verified',
|
"PASSWORDLESS_USER_EMAIL_VERIFIED_FIELD_NAME": "email_verified",
|
||||||
|
|
||||||
# Marks itself as verified the first time a user completes auth via token.
|
# Marks itself as verified the first time a user completes auth via token.
|
||||||
# Automatically unmarks itself if mobile number is changed.
|
# Automatically unmarks itself if mobile number is changed.
|
||||||
'PASSWORDLESS_USER_MARK_MOBILE_VERIFIED': False,
|
"PASSWORDLESS_USER_MARK_MOBILE_VERIFIED": False,
|
||||||
'PASSWORDLESS_USER_MOBILE_VERIFIED_FIELD_NAME': 'mobile_verified',
|
"PASSWORDLESS_USER_MOBILE_VERIFIED_FIELD_NAME": "mobile_verified",
|
||||||
|
|
||||||
# The email the callback token is sent from
|
# The email the callback token is sent from
|
||||||
'PASSWORDLESS_EMAIL_NOREPLY_ADDRESS': None,
|
"PASSWORDLESS_EMAIL_NOREPLY_ADDRESS": None,
|
||||||
|
|
||||||
# The email subject
|
# The email subject
|
||||||
'PASSWORDLESS_EMAIL_SUBJECT': "Your Login Token",
|
"PASSWORDLESS_EMAIL_SUBJECT": "Your Login Token",
|
||||||
|
|
||||||
# A plaintext email message overridden by the html message. Takes one string.
|
# A plaintext email message overridden by the html message. Takes one string.
|
||||||
'PASSWORDLESS_EMAIL_PLAINTEXT_MESSAGE': "Enter this token to sign in: %s",
|
"PASSWORDLESS_EMAIL_PLAINTEXT_MESSAGE": "Enter this token to sign in: %s",
|
||||||
|
|
||||||
# The email template name.
|
# The email template name.
|
||||||
'PASSWORDLESS_EMAIL_TOKEN_HTML_TEMPLATE_NAME': "passwordless_default_token_email.html",
|
"PASSWORDLESS_EMAIL_TOKEN_HTML_TEMPLATE_NAME": "passwordless_default_token_email.html",
|
||||||
|
|
||||||
# Your twilio number that sends the callback tokens.
|
# Your twilio number that sends the callback tokens.
|
||||||
'PASSWORDLESS_MOBILE_NOREPLY_NUMBER': None,
|
"PASSWORDLESS_MOBILE_NOREPLY_NUMBER": None,
|
||||||
|
|
||||||
# The message sent to mobile users logging in. Takes one string.
|
# The message sent to mobile users logging in. Takes one string.
|
||||||
'PASSWORDLESS_MOBILE_MESSAGE': "Use this code to log in: %s",
|
"PASSWORDLESS_MOBILE_MESSAGE": "Your SARLINK OTP is: %s \nPlease do not share this code with anyone.",
|
||||||
|
|
||||||
# Registers previously unseen aliases as new users.
|
# Registers previously unseen aliases as new users.
|
||||||
'PASSWORDLESS_REGISTER_NEW_USERS': False,
|
"PASSWORDLESS_REGISTER_NEW_USERS": False,
|
||||||
|
|
||||||
# Suppresses actual SMS for testing
|
# Suppresses actual SMS for testing
|
||||||
'PASSWORDLESS_TEST_SUPPRESSION': False,
|
"PASSWORDLESS_TEST_SUPPRESSION": False,
|
||||||
|
|
||||||
# Context Processors for Email Template
|
# Context Processors for Email Template
|
||||||
'PASSWORDLESS_CONTEXT_PROCESSORS': [],
|
"PASSWORDLESS_CONTEXT_PROCESSORS": [],
|
||||||
|
|
||||||
# The verification email subject
|
# The verification email subject
|
||||||
'PASSWORDLESS_EMAIL_VERIFICATION_SUBJECT': "Your Verification Token",
|
"PASSWORDLESS_EMAIL_VERIFICATION_SUBJECT": "Your Verification Token",
|
||||||
|
|
||||||
# A plaintext verification email message overridden by the html message. Takes one string.
|
# A plaintext verification email message overridden by the html message. Takes one string.
|
||||||
'PASSWORDLESS_EMAIL_VERIFICATION_PLAINTEXT_MESSAGE': "Enter this verification code: %s",
|
"PASSWORDLESS_EMAIL_VERIFICATION_PLAINTEXT_MESSAGE": "Enter this verification code: %s",
|
||||||
|
|
||||||
# The verification email template name.
|
# The verification email template name.
|
||||||
'PASSWORDLESS_EMAIL_VERIFICATION_TOKEN_HTML_TEMPLATE_NAME': "passwordless_default_verification_token_email.html",
|
"PASSWORDLESS_EMAIL_VERIFICATION_TOKEN_HTML_TEMPLATE_NAME": "passwordless_default_verification_token_email.html",
|
||||||
|
|
||||||
# The message sent to mobile users logging in. Takes one string.
|
# The message sent to mobile users logging in. Takes one string.
|
||||||
'PASSWORDLESS_MOBILE_VERIFICATION_MESSAGE': "Enter this verification code: %s",
|
"PASSWORDLESS_MOBILE_VERIFICATION_MESSAGE": "Enter this verification code: %s",
|
||||||
|
|
||||||
# Automatically send verification email or sms when a user changes their alias.
|
# Automatically send verification email or sms when a user changes their alias.
|
||||||
'PASSWORDLESS_AUTO_SEND_VERIFICATION_TOKEN': False,
|
"PASSWORDLESS_AUTO_SEND_VERIFICATION_TOKEN": False,
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
# List of settings that may be in string import notation.
|
# List of settings that may be in string import notation.
|
||||||
IMPORT_STRINGS = (
|
IMPORT_STRINGS = (
|
||||||
'PASSWORDLESS_EMAIL_TOKEN_HTML_TEMPLATE',
|
"PASSWORDLESS_EMAIL_TOKEN_HTML_TEMPLATE",
|
||||||
'PASSWORDLESS_CONTEXT_PROCESSORS',
|
"PASSWORDLESS_CONTEXT_PROCESSORS",
|
||||||
)
|
)
|
||||||
|
|
||||||
api_settings = APISettings(USER_SETTINGS, DEFAULTS, IMPORT_STRINGS) #type: ignore
|
api_settings = APISettings(USER_SETTINGS, DEFAULTS, IMPORT_STRINGS) # type: ignore
|
||||||
|
Loading…
x
Reference in New Issue
Block a user