(20241228) Started making provisions for disabling payment gateway accounts when the gateway says that the credentials are invalid. Am stuck at one place, though.

This commit is contained in:
2024-12-28 18:10:27 +05:30
parent 696af7a167
commit a0ea7c45d6
5 changed files with 78 additions and 7 deletions
@@ -149,6 +149,7 @@ async def safaricom_m_pesa_express_callback(
# ┛┗┗┻┗┻ ┗┛┗┛┗ ┛┗┗ # ┛┗┗┻┗┻ ┗┛┗┛┗ ┛┗┗
client_response = await current_app.safaricom_mpesa_express_controller.handle_payment_callback( client_response = await current_app.safaricom_mpesa_express_controller.handle_payment_callback(
sql_conn = current_app.sql_writer,
mongo_data_conn = current_app.data_mongo, mongo_data_conn = current_app.data_mongo,
inbound_data = inbound_data, inbound_data = inbound_data,
inbound_headers = inbound_headers inbound_headers = inbound_headers
@@ -180,6 +180,7 @@ async def request_payment(
# For Safaricom's M-Pesa Express client: # For Safaricom's M-Pesa Express client:
if auth_token.client == "safaricomMPesaExpress": if auth_token.client == "safaricomMPesaExpress":
response = await current_app.safaricom_mpesa_express_controller.request_payment( response = await current_app.safaricom_mpesa_express_controller.request_payment(
sql_conn = current_app.sql_writer,
mongo_data_conn = current_app.data_mongo, mongo_data_conn = current_app.data_mongo,
auth_token = auth_token, auth_token = auth_token,
user_info = CoreUserInfoModel(**kwargs["session_info"]), user_info = CoreUserInfoModel(**kwargs["session_info"]),
@@ -139,6 +139,7 @@ class AllPaymentsController(PaymentsController):
async def request_payment( async def request_payment(
self, self,
sql_conn: AsyncMySQL,
mongo_data_conn: AsyncMongo, mongo_data_conn: AsyncMongo,
auth_token: CoreAuthTokenModel, auth_token: CoreAuthTokenModel,
user_info: CoreUserInfoModel, user_info: CoreUserInfoModel,
@@ -147,6 +148,8 @@ class AllPaymentsController(PaymentsController):
""" """
To request payment from someone through a payment gateway. To request payment from someone through a payment gateway.
:param sql_conn: Only needed when a payment gateway says that the credentials are invalid and the account needs
to be disabled.
:param mongo_data_conn: The database connection to use to perform this activity. :param mongo_data_conn: The database connection to use to perform this activity.
:param auth_token: The token that has to be used to fetch the data. :param auth_token: The token that has to be used to fetch the data.
:param user_info: The info. of your user, so that you can identify who requested the payment. :param user_info: The info. of your user, so that you can identify who requested the payment.
@@ -158,17 +161,21 @@ class AllPaymentsController(PaymentsController):
async def handle_payment_callback( async def handle_payment_callback(
self, self,
sql_conn: AsyncMySQL,
mongo_data_conn: AsyncMongo, mongo_data_conn: AsyncMongo,
inbound_data: dict inbound_data: dict,
): inbound_headers: dict
) -> PaymentRequestOneResult:
""" """
Whenever the payment gateway sends an update about a requested payment, we use this method to update our records Whenever the payment gateway sends an update about a requested payment, we use this method to update our records
as per the specification of the third-party payment gateway. as per the specification of the third-party payment gateway.
:param sql_conn: Only needed when a payment gateway says that the credentials are invalid and the account needs
to be disabled.
:param mongo_data_conn: The database connection to use to perform this activity. :param mongo_data_conn: The database connection to use to perform this activity.
:param inbound_data: The data sent by the payment gateway in their update. :param inbound_data: The data sent by the payment gateway in their update.
:param inbound_headers: The headers sent by the payment gateway in their update.
:return: ?? :return: A structured response about the process of updating the payment event.
""" """
raise NotImplementedError raise NotImplementedError
+41 -3
View File
@@ -47,7 +47,11 @@ from controllers_v2.core.auth_token import CoreAuthTokenController
from models.core.user import CoreUserInfoModel from models.core.user import CoreUserInfoModel
from models.core.auth_token import CoreAuthTokenModel from models.core.auth_token import CoreAuthTokenModel
from models.core.payment import CorePaymentModel, PaymentEvent, CustomerDetails from models.core.payment import CorePaymentModel, PaymentEvent, CustomerDetails
from models.api.finstitutions.payments.request import PGPaymentRequestData, PaymentRequestOneResult from models.api.finstitutions.payments.request import (
PGPaymentRequestData,
PaymentRequestOneResult,
PaymentCallbackResult
)
# To work with MongoDB: # To work with MongoDB:
from bson import ObjectId from bson import ObjectId
@@ -270,6 +274,34 @@ class PaymentsController(CoreAuthTokenController, ABC):
# we return it as our data model: # we return it as our data model:
return CorePaymentModel(**record) return CorePaymentModel(**record)
async def get_payment_by_client_reference_id(
self,
mongo_data_conn: AsyncMongo,
client_reference_id: str
) -> CorePaymentModel | None:
"""
Gets one payment detail if you know its payment id.
:param mongo_data_conn: The instance of the database connector to use for the operation.
:param client_reference_id: The way the client identifies this payment. You need to pass this only on the first
event. Typically, when you initiate the payment request.
:return: The contents of that one payment detail in a structured format.
"""
# We fetch the whole payload of that one message:
record = await mongo_data_conn.find_one(
collection = self.PAYMENTS_COLLECTION,
filter = {"clientPaymentReferenceId": client_reference_id},
raise_exception = True
)
# If no such message was found:
if record is None: return None
# If a record was found,
# we return it as our data model:
return CorePaymentModel(**record)
# ┳┳ ┓ ┏┓ # ┳┳ ┓ ┏┓
# ┃┃┏┓┏┫┏┓╋┏┓ ┃┃┏┓┓┏┏┳┓┏┓┏┓╋┏ # ┃┃┏┓┏┫┏┓╋┏┓ ┃┃┏┓┓┏┏┳┓┏┓┏┓╋┏
# ┗┛┣┛┗┻┗┻┗┗ ┣┛┗┻┗┫┛┗┗┗ ┛┗┗┛ # ┗┛┣┛┗┻┗┻┗┗ ┣┛┗┻┗┫┛┗┗┗ ┛┗┗┛
@@ -466,6 +498,7 @@ class PaymentsController(CoreAuthTokenController, ABC):
@abstractmethod @abstractmethod
async def request_payment( async def request_payment(
self, self,
sql_conn: AsyncMySQL,
mongo_data_conn: AsyncMongo, mongo_data_conn: AsyncMongo,
auth_token: CoreAuthTokenModel, auth_token: CoreAuthTokenModel,
user_info: CoreUserInfoModel, user_info: CoreUserInfoModel,
@@ -474,6 +507,8 @@ class PaymentsController(CoreAuthTokenController, ABC):
""" """
To request payment from someone through a payment gateway. To request payment from someone through a payment gateway.
:param sql_conn: Only needed when a payment gateway says that the credentials are invalid and the account needs
to be disabled.
:param mongo_data_conn: The database connection to use to perform this activity. :param mongo_data_conn: The database connection to use to perform this activity.
:param auth_token: The token that has to be used to fetch the data. :param auth_token: The token that has to be used to fetch the data.
:param user_info: The info. of your user, so that you can identify who requested the payment. :param user_info: The info. of your user, so that you can identify who requested the payment.
@@ -486,18 +521,21 @@ class PaymentsController(CoreAuthTokenController, ABC):
@abstractmethod @abstractmethod
async def handle_payment_callback( async def handle_payment_callback(
self, self,
sql_conn: AsyncMySQL,
mongo_data_conn: AsyncMongo, mongo_data_conn: AsyncMongo,
inbound_data: dict, inbound_data: dict,
inbound_headers: dict inbound_headers: dict
) -> None: ) -> PaymentCallbackResult:
""" """
Whenever the payment gateway sends an update about a requested payment, we use this method to update our records Whenever the payment gateway sends an update about a requested payment, we use this method to update our records
as per the specification of the third-party payment gateway. as per the specification of the third-party payment gateway.
:param sql_conn: Only needed when a payment gateway says that the credentials are invalid and the account needs
to be disabled.
:param mongo_data_conn: The database connection to use to perform this activity. :param mongo_data_conn: The database connection to use to perform this activity.
:param inbound_data: The data sent by the payment gateway in their update. :param inbound_data: The data sent by the payment gateway in their update.
:param inbound_headers: The headers sent by the payment gateway in their update. :param inbound_headers: The headers sent by the payment gateway in their update.
:return: ?? :return: A structured response about the process of updating the payment event.
""" """
pass pass
@@ -168,6 +168,7 @@ class SafaricomMPesaExpressPaymentsController(PaymentsController):
async def request_payment( async def request_payment(
self, self,
sql_conn: AsyncMySQL,
mongo_data_conn: AsyncMongo, mongo_data_conn: AsyncMongo,
auth_token: CoreAuthTokenModel, auth_token: CoreAuthTokenModel,
user_info: CoreUserInfoModel, user_info: CoreUserInfoModel,
@@ -176,6 +177,8 @@ class SafaricomMPesaExpressPaymentsController(PaymentsController):
""" """
To request payment from someone through a payment gateway. To request payment from someone through a payment gateway.
:param sql_conn: Only needed when a payment gateway says that the credentials are invalid and the account needs
to be disabled.
:param mongo_data_conn: The database connection to use to perform this activity. :param mongo_data_conn: The database connection to use to perform this activity.
:param auth_token: The token that has to be used to fetch the data. :param auth_token: The token that has to be used to fetch the data.
:param user_info: The info. of your user, so that you can identify who requested the payment. :param user_info: The info. of your user, so that you can identify who requested the payment.
@@ -249,6 +252,7 @@ class SafaricomMPesaExpressPaymentsController(PaymentsController):
async def handle_payment_callback( async def handle_payment_callback(
self, self,
sql_conn: AsyncMySQL,
mongo_data_conn: AsyncMongo, mongo_data_conn: AsyncMongo,
inbound_data: dict, inbound_data: dict,
inbound_headers: dict inbound_headers: dict
@@ -257,6 +261,8 @@ class SafaricomMPesaExpressPaymentsController(PaymentsController):
""" """
Whenever the payment gateway sends an update about a requested payment, we use this method to update our records Whenever the payment gateway sends an update about a requested payment, we use this method to update our records
as per the specification of the third-party payment gateway. as per the specification of the third-party payment gateway.
:param sql_conn: Only needed when a payment gateway says that the credentials are invalid and the account needs
to be disabled.
:param mongo_data_conn: The database connection to use to perform this activity. :param mongo_data_conn: The database connection to use to perform this activity.
:param inbound_data: The data sent by the payment gateway in their update. :param inbound_data: The data sent by the payment gateway in their update.
:param inbound_headers: The headers sent by the payment gateway in their update. :param inbound_headers: The headers sent by the payment gateway in their update.
@@ -334,6 +340,24 @@ class SafaricomMPesaExpressPaymentsController(PaymentsController):
client_reference_id = pg_reference_id client_reference_id = pg_reference_id
) )
# In case the payment collector's credentials have changed,
# we mark his account as disabled:
# if pg_result_code in [2001]:
# payment = await self.get_payment_by_client_reference_id(
# mongo_data_conn = mongo_data_conn,
# client_reference_id = pg_reference_id
# )
# auth_token = await self.get_token_from_id(
# mongo_data_conn = mongo_data_conn,
# token_id = payment.tokenId
# )
# auth_token.status = "disabled"
# await self.set_token(
# sql_conn = sql_conn,
# mongo_data_conn = mongo_data_conn,
# auth_token = auth_token
# )
# Done here: # Done here:
if event_note_success: if event_note_success:
result.success = True result.success = True