(20241217) Payment callback ready for Safaricom M-Pesa Express.
This commit is contained in:
@@ -0,0 +1,181 @@
|
||||
"""
|
||||
|
||||
AUTHOR:
|
||||
|
||||
Khushal P Soonderji
|
||||
|
||||
DATE:
|
||||
|
||||
Tuesday, 17th Dec., 2024.
|
||||
|
||||
OBJECTIVE:
|
||||
|
||||
To provide a structure to list payments records that are already present in our database.
|
||||
|
||||
REFERENCES:
|
||||
|
||||
N/A
|
||||
|
||||
DOWNLOADS:
|
||||
|
||||
N/A
|
||||
|
||||
"""
|
||||
|
||||
|
||||
# *****************************************************************************************************************
|
||||
# ***** ****
|
||||
# *** IMPORT ***
|
||||
# ***** ****
|
||||
# *****************************************************************************************************************
|
||||
|
||||
|
||||
# To make sibling directories accessible for imports:
|
||||
import sys
|
||||
sys.path.append(".")
|
||||
sys.path.append("..")
|
||||
|
||||
# For making data behaviour_models:
|
||||
from pydantic import BaseModel, Field, field_validator, PastDatetime
|
||||
from typing import Optional, Literal, Union, List, Any
|
||||
|
||||
# My utils:
|
||||
from utils_v2.string import regex
|
||||
from utils_v2.date_time import date_time
|
||||
|
||||
# Models:
|
||||
from models.core.payment import CorePaymentModel
|
||||
|
||||
# To work with date and time:
|
||||
import datetime
|
||||
|
||||
# To work with MongoDB:
|
||||
from bson.objectid import ObjectId
|
||||
|
||||
# To work with currencies:
|
||||
import pycountry
|
||||
|
||||
|
||||
# *****************************************************************************************************************
|
||||
# ***** ****
|
||||
# *** MACROS / ONE-TIME INIT ***
|
||||
# ***** ****
|
||||
# *****************************************************************************************************************
|
||||
|
||||
|
||||
# RegEx Patterns:
|
||||
REGEX_SESSION_TOKEN = r"^[a-f0-9]{8}-[a-f0-9]{4}-[1-5][a-f0-9]{3}-[89ab][a-f0-9]{3}-[a-f0-9]{12}$"
|
||||
|
||||
|
||||
# *****************************************************************************************************************
|
||||
# ***** ****
|
||||
# *** VARIABLES ***
|
||||
# ***** ****
|
||||
# *****************************************************************************************************************
|
||||
|
||||
|
||||
# --- Nothing Yet
|
||||
|
||||
|
||||
# *****************************************************************************************************************
|
||||
# ***** ****
|
||||
# *** FUNCTIONS ***
|
||||
# ***** ****
|
||||
# *****************************************************************************************************************
|
||||
|
||||
|
||||
class PGPaymentListHeaders(BaseModel):
|
||||
|
||||
sessionToken: str = Field(
|
||||
description = "the session token of the user who is requesting the service",
|
||||
pattern = REGEX_SESSION_TOKEN,
|
||||
frozen = True,
|
||||
alias = "X-Session-Token"
|
||||
)
|
||||
|
||||
# ┏┓ ┏•
|
||||
# ┃ ┏┓┏┓╋┓┏┓
|
||||
# ┗┛┗┛┛┗┛┗┗┫
|
||||
# ┛
|
||||
|
||||
class Config:
|
||||
extra = "allow"
|
||||
|
||||
def model_dump(self, *args, **kwargs):
|
||||
return super().model_dump(*args, by_alias = True, **kwargs)
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
class PGPaymentListData(BaseModel):
|
||||
|
||||
tokenKeys: str | List[str] = Field(
|
||||
description = "the token identifier(s) that tell you which auth-tokens were used for fetching those records",
|
||||
frozen = True,
|
||||
)
|
||||
|
||||
count: int = Field(
|
||||
description = "the no. of records to list",
|
||||
default = 25,
|
||||
ge = 1,
|
||||
le = 500,
|
||||
frozen = True
|
||||
)
|
||||
|
||||
fromCount: int = Field(
|
||||
description = "the no. of records to skip before picking mails to list; useful for pagination",
|
||||
ge = 0,
|
||||
default = 0,
|
||||
frozen = True
|
||||
)
|
||||
|
||||
tags: List[Any] | None = Field(
|
||||
description = "any no. of tags that you want to filter by",
|
||||
default = None
|
||||
)
|
||||
|
||||
paymentStatus: List[Literal[
|
||||
"queued", # ....... When the UI sends a payment request, but the payment gateway (PG) hasn't received it yet.
|
||||
"initFailed", # ... When we tried to initiate the request, but the PG rejected it.
|
||||
"initiated", # .... When we made a successful payment request, or the customer initiated one from the PG.
|
||||
"failed", # ....... When the customer tried paying, but it failed (e.g.: because of an incorrect pin).
|
||||
"rejected", # ..... When the customer explicitly rejected the payment.
|
||||
"authorized", # ... When the customer made the payment (but it hasn't been settled in your account yet).
|
||||
"settled", # ...... When the PG sends the money to your account.
|
||||
"refunded", # ..... When the money was refunded to the client.
|
||||
"unknown" # ....... When integrating a new gateway and some specific status is not known.
|
||||
]] | None = Field(
|
||||
description = "one or more status filters to apply when listing records",
|
||||
frozen = False,
|
||||
default = None
|
||||
)
|
||||
|
||||
# ┏┓ ┏•
|
||||
# ┃ ┏┓┏┓╋┓┏┓
|
||||
# ┗┛┗┛┛┗┛┗┗┫
|
||||
# ┛
|
||||
|
||||
class Config:
|
||||
extra = "forbid"
|
||||
|
||||
# ┓┏ ┓• ┓ •
|
||||
# ┃┃┏┓┃┓┏┫┏┓╋┓┏┓┏┓
|
||||
# ┗┛┗┻┗┗┗┻┗┻┗┗┗┛┛┗
|
||||
|
||||
@field_validator("tokenKeys", "tags", "paymentStatus", mode = "before")
|
||||
def ensure_list(cls, value):
|
||||
if not isinstance(value, list): value = [value]
|
||||
return value
|
||||
|
||||
|
||||
# *****************************************************************************************************************
|
||||
# ***** ****
|
||||
# *** MAIN PROGRAM ***
|
||||
# ***** ****
|
||||
# *****************************************************************************************************************
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
pass
|
||||
@@ -108,6 +108,30 @@ class PGPaymentRequestHeaders(BaseModel):
|
||||
# ---------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
class PaymentRequestMetadata(BaseModel):
|
||||
|
||||
idClient: str | int = Field(
|
||||
description = "account master id for the user's customer",
|
||||
frozen = True
|
||||
)
|
||||
|
||||
inAccount: str | int = Field(
|
||||
description = "account master id for the user's bank account",
|
||||
frozen = True
|
||||
)
|
||||
|
||||
# ┏┓ ┏•
|
||||
# ┃ ┏┓┏┓╋┓┏┓
|
||||
# ┗┛┗┛┛┗┛┗┗┫
|
||||
# ┛
|
||||
|
||||
class Config:
|
||||
extra = "allow"
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
class PGPaymentRequestData(BaseModel):
|
||||
|
||||
tokenKey: ObjectId = Field(
|
||||
@@ -163,7 +187,7 @@ class PGPaymentRequestData(BaseModel):
|
||||
frozen = True
|
||||
)
|
||||
|
||||
metadata: dict = Field(
|
||||
metadata: PaymentRequestMetadata = Field(
|
||||
description = "any extra information about this payment",
|
||||
frozen = True
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user