Enhance documentation, implement Twilio OTP delivery, and update payment gateway methods. Updated AGENTS.md and README.md for clarity on ExecPlans and architecture. Added Twilio as a dependency and implemented capture/refund methods in MoyasarGateway. Improved frontend routing with react-router-dom and added authentication context. Updated styles and localization files for better user experience.

This commit is contained in:
2026-02-28 15:33:50 +03:00
parent 86fd07c778
commit a1da918f95
37 changed files with 1645 additions and 277 deletions
+34 -6
View File
@@ -33,10 +33,12 @@ class BasePaymentGateway:
) -> PaymentInitResult:
raise NotImplementedError
def capture_payment(self, external_id: str) -> None:
def capture_payment(self, external_id: str, amount: Optional[int] = None) -> None:
"""Capture an authorized payment. Amount in minor units; omit for full capture."""
raise NotImplementedError
def refund_payment(self, external_id: str, amount: Optional[str] = None) -> None:
def refund_payment(self, external_id: str, amount: Optional[int] = None) -> None:
"""Refund a paid/captured payment. Amount in minor units; omit for full refund."""
raise NotImplementedError
@@ -101,10 +103,36 @@ class MoyasarGateway(BasePaymentGateway):
payload=data,
)
def capture_payment(self, external_id: str) -> None:
def capture_payment(self, external_id: str, amount: Optional[int] = None) -> None:
"""Capture an authorized payment. Amount in minor units; omit for full capture."""
self._assert_config()
raise NotImplementedError("Moyasar capture not implemented yet")
url = f"{self.base_url}/v1/payments/{external_id}/capture"
payload = {} if amount is None else {"amount": amount}
try:
response = requests.post(url, json=payload, auth=(self.secret_key, ""), timeout=10)
except requests.RequestException as exc:
raise PaymentGatewayError("Failed to reach Moyasar for capture") from exc
if response.status_code not in (200, 201):
data = response.json() if response.content else {}
raise PaymentGatewayError(
"Moyasar capture failed",
status_code=response.status_code,
payload=data,
)
def refund_payment(self, external_id: str, amount: Optional[str] = None) -> None:
def refund_payment(self, external_id: str, amount: Optional[int] = None) -> None:
"""Refund a paid/captured payment. Amount in minor units; omit for full refund."""
self._assert_config()
raise NotImplementedError("Moyasar refund not implemented yet")
url = f"{self.base_url}/v1/payments/{external_id}/refund"
payload = {} if amount is None else {"amount": amount}
try:
response = requests.post(url, json=payload, auth=(self.secret_key, ""), timeout=10)
except requests.RequestException as exc:
raise PaymentGatewayError("Failed to reach Moyasar for refund") from exc
if response.status_code not in (200, 201):
data = response.json() if response.content else {}
raise PaymentGatewayError(
"Moyasar refund failed",
status_code=response.status_code,
payload=data,
)