(20241217) Payment callback ready for Safaricom M-Pesa Express.
This commit is contained in:
+44
-12
@@ -172,13 +172,25 @@ class PaymentController:
|
||||
token_key = token_key
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
async def get_tokens(
|
||||
mongo_conn: AsyncMongo,
|
||||
token_keys: ObjectId | str = None,
|
||||
) -> List[CoreAuthTokenModel] | None:
|
||||
|
||||
# Simply call the core model:
|
||||
return await current_app.core_auth_token_controller.get_tokens(
|
||||
mongo_conn = mongo_conn,
|
||||
token_keys = token_keys
|
||||
)
|
||||
|
||||
# ┳┓ ┏┓
|
||||
# ┣┫┏┓┏┓┓┏┏┓┏╋ ┃┃┏┓┓┏┏┳┓┏┓┏┓╋┏
|
||||
# ┛┗┗ ┗┫┗┻┗ ┛┗ ┣┛┗┻┗┫┛┗┗┗ ┛┗┗┛
|
||||
# ┗ ┛
|
||||
|
||||
@staticmethod
|
||||
async def __request_from_safaricom_m_pesa_express(
|
||||
self,
|
||||
mongo_conn: AsyncMongo,
|
||||
http_client: httpx.AsyncClient,
|
||||
auth_token: CoreAuthTokenModel,
|
||||
@@ -214,7 +226,7 @@ class PaymentController:
|
||||
)
|
||||
|
||||
# Add this event to the payment's document:
|
||||
event_note_success = await current_app.core_payment_controller.add_event(
|
||||
event_note_success = await self.add_event_by_payment_id(
|
||||
mongo_conn = mongo_conn,
|
||||
payment_id = payment_id,
|
||||
event = PaymentEvent(
|
||||
@@ -223,14 +235,17 @@ class PaymentController:
|
||||
httpCode = client_response.httpCode,
|
||||
headers = await client_response.get_headers(),
|
||||
payload = await client_response.get_json()
|
||||
)
|
||||
),
|
||||
client_reference_id = client_response.referenceId
|
||||
)
|
||||
|
||||
# Done here:
|
||||
result.success = client_response.success and event_note_success
|
||||
result.message = "; ".join([
|
||||
"payment request successfully" if client_response.success else "payment request failed",
|
||||
"event noted successfully" if event_note_success else "payment event noting failed",
|
||||
"payment requested successfully" if client_response.success
|
||||
else f"payment request failed (PG: {client_response.message})",
|
||||
"event noted successfully" if event_note_success
|
||||
else "event noting failed",
|
||||
])
|
||||
return result
|
||||
|
||||
@@ -261,8 +276,9 @@ class PaymentController:
|
||||
tokenId = auth_token.authTokenId,
|
||||
amount = payment_request.amount,
|
||||
currencyCode = payment_request.currencyCode,
|
||||
metadata = payment_request.metadata,
|
||||
metadata = payment_request.metadata.model_dump(),
|
||||
tags = ["payment", "safaricom", "mPesaExpress", "kenya"],
|
||||
serviceType = "paymentGateway",
|
||||
client = auth_token.client,
|
||||
clientPaymentReferenceId = None,
|
||||
events = []
|
||||
@@ -281,7 +297,7 @@ class PaymentController:
|
||||
mongo_conn = mongo_conn,
|
||||
auth_token = auth_token,
|
||||
payment_request = payment_request,
|
||||
callback_url = f"https://api.thecaoffice.com/finstitutions/payments/callback/{payment_id}",
|
||||
callback_url = f"https://api.thecaoffice.com/finstitutions/payments/callback/safaricom/mpesaexpress",
|
||||
payment_id = payment_id
|
||||
)
|
||||
case _:
|
||||
@@ -310,7 +326,7 @@ class PaymentController:
|
||||
# Regardless of what additional filter is provided from outside,
|
||||
# we add a payment-selecting filter here:
|
||||
if additional_filter is None: additional_filter = {}
|
||||
additional_filter["serviceType"] = "paymentGateway"
|
||||
# additional_filter["serviceType"] = "paymentGateway"
|
||||
|
||||
# Simply call the core model:
|
||||
return await current_app.core_payment_controller.get_payment_previews(
|
||||
@@ -353,17 +369,33 @@ class PaymentController:
|
||||
# ┛
|
||||
|
||||
@staticmethod
|
||||
async def add_event(
|
||||
async def add_event_by_payment_id(
|
||||
mongo_conn: AsyncMongo,
|
||||
payment_id: ObjectId | str,
|
||||
event: PaymentEvent
|
||||
event: PaymentEvent,
|
||||
client_reference_id: str = None
|
||||
) -> bool:
|
||||
|
||||
# Simply call the core model:
|
||||
return await current_app.core_payment_controller.add_event(
|
||||
return await current_app.core_payment_controller.add_event_by_payment_id(
|
||||
mongo_conn = mongo_conn,
|
||||
payment_id = payment_id,
|
||||
event = event
|
||||
event = event,
|
||||
client_reference_id = client_reference_id
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
async def add_event_by_client_reference_id(
|
||||
mongo_conn: AsyncMongo,
|
||||
client_reference_id: str,
|
||||
event: PaymentEvent,
|
||||
) -> bool:
|
||||
|
||||
# Simply call the core model:
|
||||
return await current_app.core_payment_controller.add_event_by_client_reference_id(
|
||||
mongo_conn = mongo_conn,
|
||||
event = event,
|
||||
client_reference_id = client_reference_id
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
|
||||
@@ -293,7 +293,7 @@ class CorePaymentController(BaseModel):
|
||||
# We don't support updating payments themselves,
|
||||
# but we will allow updating fields like tags, adding events, etc.
|
||||
|
||||
async def add_event(
|
||||
async def add_event_by_payment_id(
|
||||
self,
|
||||
mongo_conn: AsyncMongo,
|
||||
payment_id: ObjectId | str,
|
||||
@@ -332,6 +332,43 @@ class CorePaymentController(BaseModel):
|
||||
raise_exception = True
|
||||
)
|
||||
|
||||
async def add_event_by_client_reference_id(
|
||||
self,
|
||||
mongo_conn: AsyncMongo,
|
||||
client_reference_id: str,
|
||||
event: PaymentEvent,
|
||||
) -> bool:
|
||||
|
||||
"""
|
||||
Add an event to an existing record of a payment detail.
|
||||
:param mongo_conn: The instance of the database connector to use for the operation.
|
||||
:param event: The event that occurred. This will typically be generated by the third-party client.
|
||||
: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: True if successfully noted, else False.
|
||||
"""
|
||||
|
||||
# Prepare the update document:
|
||||
update_json = {
|
||||
"$push": {
|
||||
"events": event.model_dump()
|
||||
},
|
||||
"$set": {
|
||||
"lastEventTs": date_time.get_current_ist_date_time(as_string = False),
|
||||
"lastPaymentStatus": event.paymentStatus
|
||||
}
|
||||
}
|
||||
if client_reference_id: update_json["$set"]["clientPaymentReferenceId"] = client_reference_id
|
||||
|
||||
# Try to update the existing record:
|
||||
return await mongo_conn.update_one(
|
||||
collection = self.PAYMENTS_COLLECTION,
|
||||
filter = {"clientPaymentReferenceId": client_reference_id},
|
||||
update = update_json,
|
||||
upsert = False,
|
||||
raise_exception = True
|
||||
)
|
||||
|
||||
async def update_tags(
|
||||
self,
|
||||
mongo_conn: AsyncMongo,
|
||||
|
||||
Reference in New Issue
Block a user