Parsian Shaparak Payment Gateway¶
This example demonstrates how to use the Parsian Shaparak payment gateway adapter to process online payments in Iran.
Configuration¶
First, configure the Parsian Shaparak settings in your environment or configuration file:
from pydantic import BaseModel
from archipy.configs.base_config import BaseConfig
from archipy.configs.config_template import ParsianShaparakConfig
class MyAppConfig(BaseConfig):
# Other configuration settings
# Parsian Shaparak Configuration
PARSIAN_SHAPARAK: ParsianShaparakConfig = ParsianShaparakConfig(
LOGIN_ACCOUNT="your_merchant_login_account",
# Optionally specify custom WSDL URLs if needed
# PAYMENT_WSDL_URL="https://custom.url/to/payment/wsdl",
# CONFIRM_WSDL_URL="https://custom.url/to/confirm/wsdl",
# REVERSAL_WSDL_URL="https://custom.url/to/reversal/wsdl",
# Optionally specify proxy settings
# PROXIES={"http": "http://proxy:port", "https": "https://proxy:port"}
)
Initializing the Adapter¶
from archipy.adapters.internet_payment_gateways.ir.parsian.adapters import (
ParsianShaparakPaymentAdapter,
PaymentRequestDTO,
ConfirmRequestDTO,
ConfirmWithAmountRequestDTO,
ReverseRequestDTO
)
# Initialize the payment adapter
payment_adapter = ParsianShaparakPaymentAdapter()
Processing Payments¶
Initiating a Payment¶
To start a payment transaction:
# Create payment request
payment_request = PaymentRequestDTO(
amount=10000, # Amount in IRR (10,000 Rials)
order_id=12345, # Your unique order ID
callback_url="https://your-app.com/payment/callback", # URL to redirect after payment
additional_data="Optional additional data", # Optional
originator="Optional originator info" # Optional
)
# Send payment request
payment_response = payment_adapter.initiate_payment(payment_request)
# Check response
if payment_response.status == 0: # 0 means success in Parsian API
# Redirect user to payment page
payment_url = f"https://pec.shaparak.ir/NewIPG/?Token={payment_response.token}"
# Use this URL to redirect the user to the payment gateway
else:
# Handle error
print(f"Payment initiation failed: {payment_response.message}")
Confirming a Payment¶
After the user completes the payment and returns to your callback URL, confirm the payment:
# Get the token from query parameters in your callback handler
token = 123456789 # This would come from the callback request
# Create confirm request
confirm_request = ConfirmRequestDTO(token=token)
# Confirm payment
confirm_response = payment_adapter.confirm_payment(confirm_request)
if confirm_response.status == 0: # 0 means success
# Payment successful
reference_number = confirm_response.rrn
masked_card = confirm_response.card_number_masked
# Process the successful payment in your system
print(f"Payment confirmed! Reference: {reference_number}, Card: {masked_card}")
else:
# Handle failed confirmation
print(f"Payment confirmation failed with status: {confirm_response.status}")
Confirming with Amount Verification¶
For enhanced security, you can confirm with amount verification:
# Create confirm with amount request
confirm_with_amount_request = ConfirmWithAmountRequestDTO(
token=123456789,
order_id=12345,
amount=10000
)
# Confirm payment with amount verification
confirm_response = payment_adapter.confirm_payment_with_amount(confirm_with_amount_request)
if confirm_response.status == 0: # 0 means success
# Payment successful with amount verification
print(f"Payment confirmed with amount verification!")
else:
# Handle failed confirmation
print(f"Payment confirmation failed with status: {confirm_response.status}")
Reversing a Payment¶
If needed, you can reverse (refund) a successful payment:
# Create reverse request
reverse_request = ReverseRequestDTO(token=123456789)
# Request payment reversal
reverse_response = payment_adapter.reverse_payment(reverse_request)
if reverse_response.status == 0: # 0 means success
# Reversal successful
print(f"Payment reversal successful!")
else:
# Handle failed reversal
print(f"Payment reversal failed: {reverse_response.message}")
Error Handling¶
The adapter uses ArchiPy's error system to provide consistent error handling:
from archipy.models.errors import UnavailableError, InternalError
try:
payment_response = payment_adapter.initiate_payment(payment_request)
except UnavailableError as e:
# Handle service unavailable error
print(f"Payment service unavailable: {e}")
except InternalError as e:
# Handle unexpected error
print(f"Unexpected error: {e}")
Complete Example¶
Here's a complete example integrating the payment flow into a FastAPI application:
from fastapi import FastAPI, Request, Depends, HTTPException, status
from fastapi.responses import RedirectResponse
from pydantic import BaseModel
from typing import Annotated
from archipy.adapters.internet_payment_gateways.ir.parsian.adapters import (
ParsianShaparakPaymentAdapter,
PaymentRequestDTO,
ConfirmRequestDTO
)
from archipy.models.errors import UnavailableError, InternalError
app = FastAPI()
payment_adapter = ParsianShaparakPaymentAdapter()
# Create order model
class OrderCreate(BaseModel):
amount: int
order_id: int
description: str = None
# Payment routes
@app.post("/payments/create")
async def create_payment(order: OrderCreate):
try:
payment_request = PaymentRequestDTO(
amount=order.amount,
order_id=order.order_id,
callback_url=f"https://your-app.com/payments/callback",
additional_data=order.description
)
response = payment_adapter.initiate_payment(payment_request)
if response.status != 0:
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail=f"Payment initiation failed: {response.message}"
)
# Return payment URL or token
return {
"token": response.token,
"payment_url": f"https://pec.shaparak.ir/NewIPG/?Token={response.token}"
}
except UnavailableError as e:
raise HTTPException(
status_code=status.HTTP_503_SERVICE_UNAVAILABLE,
detail="Payment service unavailable"
)
except InternalError as e:
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="Internal server error"
)
@app.get("/payments/callback")
async def payment_callback(token: int, request: Request):
try:
confirm_request = ConfirmRequestDTO(token=token)
confirm_response = payment_adapter.confirm_payment(confirm_request)
if confirm_response.status == 0:
# Payment successful - update your database
return {
"status": "success",
"reference_number": confirm_response.rrn,
"card": confirm_response.card_number_masked
}
else:
return {
"status": "failed",
"message": "Payment verification failed"
}
except Exception as e:
return {
"status": "error",
"message": str(e)
}