امید پاکدل
امید پاکدل
خواندن ۵ دقیقه·۴ سال پیش

پیاده سازی درگاه پرداخت بانک ملی (سداد) در پایتون

عکس از گوگل
عکس از گوگل

سلام، تو یکی از پروژه ها که با پایتون و جنگو رست بود قرار بود درگاه پرداخت پیاده سازی کنم که یکم دردسر داشت چون که خود بانک چیزی نداشت براش و پکیج اقای زاهدی که تو گیت هابشون هم بود اون چیزی نبود اما خیلی کمکم کرد.

یادتون نره اگر خواستین ازین درگاه پرداخت استفاده کنین حتما علاوه بر درگاه پرداختی که برای خودتون میگیرین یه درگاه پرداخت تست هم بگیرین. چون ایپی و پورت میگیرن برای تست کردن شاید به مشکل بخورین. زنگ بزنین پشتیبانیشون به ایمیلتون یه درگاه پرداخت تست میدن و هرچقدرم پرداخت داشته باشین بهش برگشت داده میشه. داکیومنتی هم که خدا بانک داره یجوریه ( حداقل برای من ) و خودم برای گرفتن تاییدیه پرداخت یک صفحه از داکیومنت رو بالغ بر ۲۰ بار خوندم.

بگذریم این مسیری هست که من رفتم گفتم شاید برای یکی مفید باشه بتونه ازش استفاده کنه و دردسر کمتری براش داشته باشه. کاری که من کردم دوتا ویو نوشتم یکی از سمت کلاینت صدا زده میشد و یک url ساخته میشد که اون رو میدادم به بچه های فرانتمون و کاربر رو پاس میدادن بهش (هرچند خودمم میتونستم ریدایرکت کنم.) و پرداختش رو کاربر انجام میداد و بعدش اون ویو دومیه از سمت بانک صدا زده میشد و تاییدیه پرداخت رو میگرفت از بانک و بعدش اینجا من به یه صفحه ای ریدایرکت میکردم که جزيیات پرداخت رو نشون میداد.

از نوشتن ویو ها صرف نظر میکنم و فقط متود های کار رو نشون میدم.

خب اول از همه شما باید برای پرداختتون یک شماره سفارش بسازین ( اینطور که بانک میگه نباید تکراری باشه ) من اول اومدم از تابع رندوم پایتون یه عدد ۱۰ رقمی ساختم بعد پکیج اقای زاهدی ( قبلن بهش اشاره کردم‌) نگاه کردم چیکار کردن و بنظرم بهتر اومد که اینطوری شماره سفارش ساخته میشه.

import uuid
tracking_code = int(str(uuid.uuid4().int)[-1 * 16:])

من اینجا عدد ذخیره کردم اما شما میتونید اون int اول رو بردارید و همونطوری استرینگ ذخیره کنید.

بعدش باید این عدد رو با مبلغ سفارش و شماره ترمینال ( ۳ پارامتر‌ ) رمزنگاری کنید.

def pad(text, pad_size=16): text_length = len(text) last_block_size = text_length % pad_size remaining_space = pad_size - last_block_size text = text + (remaining_space * chr(remaining_space)) return text def encrypt_des3(text): secret_key_bytes = base64.b64decode(&quotTERMINAL ID&quot) text = _pad(text, 8) cipher = DES3.new(secret_key_bytes, DES3.MODE_ECB) cipher_text = cipher.encrypt(str.encode(text)) return base64.b64encode(cipher_text).decode(&quotutf-8&quot)

این متودای رمزنگاری که برای بانک استفاده کردم که خب بکمک پکیج اقای زاهدی بوده. با متود پایینی پارامتر SignData که از ورودی های درخواست اولیه بانک هستش رو میسازم.

def encrypt_request_payment_data(terminal_id, tracking_code, amount): text = terminal_id + ';' + str(tracking_code) + ';' + str(amount) sign_data = encrypt_des3(text) return sign_data

حالا که رمز نگاری بانک رو هم انجام دادیم باید دیتا رو اماده کنیم تا به بانک بفرستیم.

class PaymentRequestInput: def __init__(self, merchant_id, terminal_id, amount, order_id, date, return_url, sign_data, additional_data, mobile, ): self.MerchantId = merchant_id self.TerminalId = terminal_id self.Amount = amount self.OrderId = order_id self.LocalDateTime = date self.ReturnUrl = return_url self.SignData = sign_data self.AdditionalData = additional_data self.UserId = mobile def to_json(self): return json.dumps(self, default=lambda o: o.__dict__) پارامترا مشخصه چی باید باشن یه ابجکت که از کلاس ساختین اخرش یه to_json() بزنید کار تمومه

آدرس بازگشت ( یا ReturnUrl ) همون ادرسیه که بانک بعد از پرداخت چه موفق چه ناموفق به همراه یک سری اطاعات بهش درخواست میزنه ( POST ) من برای این پارامتر ویو دومی که نوشتم رو بهش پاس دادم. بعد ازین نوبته ارسال درخواست به بانکه که توکن برای ما بسازه تا بتونیم پرداخت انجام بدیم. از پکیج requests استفاده کردم.

&quothttps://sadad.shaparak.ir/api/v0/Request/PaymentRequest&quot response = requests.post(&quotURL&quot, data=data, headers={'Content-Type': 'application/json'})

و اینو هرجا خواستم به بانک درخواست بزنم صداش زدم. بعد ازین که به بانک درخواست زدین اگر درخواستتون اوکی بشه، بهتون تو رسپانس

ResCode = '0'
Token = ' *** '

که اون سه تا ستاره یه توکن طولانیه که باید برای پرداخت ازش استفاده کنین.

https://sadad.shaparak.ir/Purchase?Token=***

کاربر رو به این صفحه انتقالش میدید اگر پرداخت رو انجام میده حالا چه پرداخت موفقیت امیز باشه چه نباشه برمیگرده به اون ReturnUrl که تو ریکوست اول پرش کردیم. ( **جالبیه این قسمت اینه که اگه یادتون باشه یه شماره سفارش اول کار ساختیم بانک به ما یه شماره سفارش دیگه برمیگردونه، نمیدونم شاید این درسته و من اشتباه میکنم ولی عجیب بود برام ) وقتی برگرده به اون ReturnUrl یه سری مقدار همراهش هست که توی اون ها ResCode و token و OrderId از همه مهم ترن. اولی که نتیجه تراکنشه اگر صفر باشه ینی پرداخت انجام شده اگر -۱ ( منهای یک باشه ) ینی پرداخت انجام نشده.

ResCode == '0' یا ResCode == '-1'

شما بعد اینجا میتونین به بانک درخواست بزنید و از صحت پرداخت مطمين بشید. فقط لازم توکن دریافتی از بانک چه تو مرحله اول چه تو بازگشت از بانک رو به بانک درخواست بزنید تا بهتون اطلاعات رو بده برای درخواستش هم به این شکله :

sign_data = _encrypt_verify_data(token=self.token) data = { 'Token': token, 'SignData': sign_data, } &quothttps://sadad.shaparak.ir/api/v0/Advice/Verify&quot response = requests.post(&quotURL&quot, data=data, headers={'Content-Type': 'application/json'})

اگر پرداخت انجام شده باشه همون پارامتر ResCode مثه دفه های قبل '0' برمیگرده و بهمراهش یه سری دیتا مثه شماره کارت، شماره پیگیری، شماره مرجع تراکنش برمیگرده اگر پرداخت انجام نشده باشه مقدار '-1' به همراه نال (null) برای مقادیری که گفتم پر میشه.

امیدوارم کمکتون کنه. سوالی بود درخدمتم. اگر هم جاییش ابهام یا مشکل داشت بهم بگید رفعش کنم. ممنون ازتون.

امید پاکدل

اسفند ۹۹

برنامه نویسیدرگاه پرداخت بانک ملیپایتونسدادجنگورست
توسعه دهنده نرم افزار
شاید از این پست‌ها خوشتان بیاید