عنوان:

‫پَرباد - راهنمای اتصال و پیاده‌سازی درگاه‌های پرداخت اینترنتی (شبکه شتاب)


نویسنده: سینا سلطانی
تاریخ: ۱۳۹۷/۰۴/۱۸ ۲۳:۵۰
آدرس: www.dntips.ir

پَرباد چیست؟

همانطور که همه ما میدانیم، اتصال و راه اندازی درگاه‌های پرداخت اینترنتی (شبکه شتاب)، از همان ابتدا کاری مشکل و  پر دردسر برای برنامه نویسان بود. هر بانک، سیستم متفاوت و مخصوص به خود را دارد و این بدان معنا است که برنامه نویسان باید کدهای کاملا متفاوت و همچنین پیاده سازی‌های متفاوتی را از روی فایل‌های PDF راهنمای بانکی، که در نهایت منجر به بی نظمی در پروژه‌ها می‌شود، بنویسند و البته مشکل بزرگتر آن است که پس از پیاده سازی هم اطمینان کاملی از صحت کدهای نوشته شده وجود ندارد؛ چه بسا که واحد‌های پشتیبانی درگاه‌های پرداخت هم افراد حرفه‌ای و آشنا با توسعه نرم افزار نیستند و اکثر اوقات نمی‌توان به آنها تکیه کرد.
برای راحتی کار برنامه نویسان حوضه فریم ورک دات نت، سیستمی جامع، اوپن سورس و کاملا رایگان، بدون نیاز به اضافه کردن هیچ گونه وب سرویسی تهیه شده است که به برنامه نویسان اجازه می‌دهد تنها با نوشتن چند خط کد، وب سایت خود را به پرداخت اینترنتی مجهز کنند. لطفا پیشنهادات، بحث‌ها و نظرات خود را در صفحه مخصوص این پروژه ارسال کنید.  
این سیستم در حال حاضر متشکل از درگاه‌های پرداخت اینترنتی بانک‌های ملت، سامان، پارسیان، تجارت و پاسارگاد است.
همچنین این سیستم در قالب یک Nuget Package برای نصب راحت در اپلیکیشن آماده شده است.


آنچه که شما در این مطلب یاد خواهید گرفت:

  • طریقه نصب
  • ایجاد صورتحساب و ارسال کاربر به درگاه پرداخت
  • تایید صورتحساب
  • مردود کردن صورتحساب قبل از انتقال وجه از مشتری به فروشنده
  • برگشت وجه به حساب مشتری پس از تأیید صورتحساب
  • درگاه مجازی پرداخت (برای تست وب اپلیکیشن، بدون داشتن حساب واقعی در درگاه‌های بانکی)
  • تنظیمات
  • ذخیره سازی اطلاعات پرداخت


طریقه نصب

PM> Install-Package Parbad

برای وب سایت‌های بر پایه فریم ورک MVC

PM> Install-Package Parbad.MVC5


ایجاد صورتحساب و ارسال کاربر به درگاه پرداخت

ابتدا یک شیٔ صورتحساب را به صورت زیر ایجاد کنید
var invoice = new Invoice( [Order Number], [Amount], [Verify URL]);

- Order Number شماره صورتحساب است و باید همیشه یک عدد یکتا باشد (تکراری نباشد).
- Amount مبلغ قابل پرداخت به ریال است.
- Verify URL یک آدرس در وب سایت شما، برای بازگشت مشتری پس از پرداخت و تأیید صورتحساب است.
برای مثال:
var invoice = new Invoice(1, 30000, "http://www.mywebsite.com/payment/verify" );
سپس صورتحساب را به درگاه مورد نظر ارسال میکنیم.
var result = Payment.Request(Gateways.Mellat, invoice);

شیٔ result حاوی شماره یکتا رجوع و وضعیت درخواست (موفقیت یا عدم موفقیت درخواست) است.
if (result.Status == RequestResultStatus.Success)
{
    // این متد، کاربر را به سمت وب سایت درگاه پرداخت هدایت میکند
    result.Process(Context);
}
else
{
    // در صورت تمایل می‌توانید پیغام مورد نظر از درگاه پرداخت را نمایش دهید
    var msg = result.Message;
}

در وب سایت‌های MVC می‌توانید به روش زیر عمل کنید

if (result.Status == RequestResultStatus.Success)
{
   // کاربر را به سمت وب سایت درگاه پرداخت هدایت میکند 
   return new RequestActionResult(result);
}
else
{
   return View("Error");
}


تأیید صورتحساب

پس از بازگشت کاربر از وب سایت بانک، باید از پرداخت صورتحساب توسط کاربر اطمینان حاصل کنید. کد زیر را باید در آدرسی که هنگام ساخت صورتحساب ذکر کرده بودید، قرار دهید.
var result = Payment.Verify(System.Web.HttpContext.Current);

شیٔ result در اینجا حاوی اطلاعاتی مانند: درگاه بانکی (که کاربر در آن صورتحساب را پرداخت کرده)، شماره رجوع، شماره تراکنش یکتای بانکی، وضعیت پرداخت و پیام درگاه است.
شما می‌توانید با بررسی این شیٔ، تصمیمات لازم را بگیرید.
if(result.Status == VerifyResultStatus.Success)
{
    // کاربر، صورتحساب را پرداخت کرده است و شما میتوانید ادامه عملیات خرید را انجام دهید
}
else
{
    // کاربر بنا به دلایلی صورتحساب را پرداخت نکرده است
    // شما همچنین میتوانید علت را در قالب یک پیام از پراپرتی پیام مشاهده کنید

    // بنابراین شما میتوانید این صورتحساب را در پایگاه داده خود مردود اعلام کنید
}


مردود کردن صورتحساب قبل از انتقال وجه از مشتری به فروشنده

در بعضی شرایط، پس از پرداخت صورتحساب توسط مشتری، شما متوجه می‌شوید که باید عملیات را لغو کنید.  
سناریو زیر را در نظر بگیرید:
در زمانیکه مشتری در وب سایت بانکی، صورتحساب را پرداخت میکرده است،  موجودی کالای خریداری شده توسط او در فروشگاه شما، به پایان رسیده ! حال باید این وجه پرداخت شده را فورا مردود اعلام کنید.
برای این منظور متد تأیید صورتحساب را به روش زیر بازنویسی کنید



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


برگشت وجه به حساب مشتری پس از تأیید صورتحساب

var refundResult = Payment.Refund(new RefundInvoice([Order Number], [Amount]));
در اینجا، Order Number همان شماره سفارش صورتحساب و Amount مقداری از وجه و یا کل وجه برای برگشت به حساب مشتری است.
پس از آن شما می‌توانید نتیجه این عملیات را در شیٔ refundResult بررسی کنید.


درگاه مجازی پرداخت

درصورتیکه شما نیاز به تست عملکرد اپلیکیشن خود داشته باشید، نیازی به داشتن یک حساب واقعی در بانک‌های اینترنتی ندارید و می‌توانید اپلیکیشن خود را با یک درگاه مجازی بسیار ساده تست کنید. برای انجام این کار در هنگام ارسال صورتحساب، از میان درگاه‌های بانکی، درگاه مجازی پَرباد را انتخاب کنید.
var result = Payment.Request(Gateways.ParbadVirtualGateway, invoice);


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

اما قبل از کار با درگاه مجازی باید در فایل web.config وب اپلیکیشن خود، تنظیمات زیر را قرار دهید:
<system.webServer>
  <handlers>
   <add name="ParbadGatewayPage" verb="*" path="Parbad.axd" type="Parbad.Web.Gateway.ParbadVirtualGatewayHandler" />
  </handlers>
</system.webServer>
در اینجا، درگاه مجازی به عنوان یک HttpHandler معرفی شده است. مقداری که در مشخصه path ذکر شده، در واقع آدرس درگاه مجازی است که شما می‌توانید به دلخواه خود آن را وارد کنید. ما در این مثال از آدرس parbad.axd استفاده کرده ایم.
و در نهایت در وب اپلیکیشن خود، مسیر ذکر شده را به صورت زیر معرفی کنید:
ParbadConfiguration.Gateways.ConfigureParbadVirtualGateway(new ParbadVirtualGatewayConfiguration("Parbad.axd"));
در نتیجه در هنگام هدایت کاربر به درگاه مجازی، شما باید در نوار آدرس مرورگر خود، مقداری را که تنظیم کرده اید مشاهده کنید.


نکته مهم: فراموش نکنید، قبل از انتشار نهایی وب سایت بر روی سرور (نمایش عمومی)، تنظیمات HttpHandler مربوط به این درگاه مجازی را از درون فایل web.config حذف کنید. بدین صورت، این درگاه از دسترس عموم خارج خواهد بود.

تنظیمات پَرباد

بهترین مکان برای درج این تنظیمات در اپلیکیشن‌های ASP.NET WebForms فایل Global.asax.cs و در اپلیکیشن‌های ASP.NET MVC فایل Startup.cs است.
ASP.NET Web Forms
public class Global : HttpApplication
{
    void Application_Start(object sender, EventArgs e)
    {
        // configurations
    }
}

ASP.NET MVC
public class Startup
{
    public void Configuration(IAppBuilder app)
    {
        // configurations
    }
}

تنظیمات درگاه‌های پرداخت

قبل از ارتباط با درگاه‌های بانکی شبکه شتاب، باید مشخصات درگاه بانکی را که استفاده می‌کنید، تنظیم کنید.
برای مثال: تنظیم درگاه پرداخت بانک ملت


تنظیمات ذخیره سازی اطلاعات پرداخت

پَرباد برای ذخیره و بازیابی اطلاعات پرداخت، نیاز به یک منبع ذخیره سازی دارد.
منبع پیش فرض پَرباد، کلاس TemporaryMemoryStorage است که همانطور که از نام آن پیداست، اطلاعات را به صورت موقت در حافظه رَم سرور ذخیره میکند. اگر شما خودتان اطلاعات پرداخت را در پایگاه داده ذخیره میکنید، این منبع، گزینه مناسبی است به دلیل سرعت بسیار بالای حافظه رَم.
توجه: در نظر داشته باشید که اگر به هر دلیلی سرور و یا وب سایت شما، ری‌استارت شود، کلیه اطلاعات موجود در این منبع هم از بین خواهد رفت.
ذخیره و بازیابی توسط SQL Server
برای این منظور در قسمت تنظیمات، کد زیر را قرار داده و رشته اتصال و نام جدول پرداخت را معرفی کنید.
ParbadConfiguration.Storage = new SqlServerStorage("Connection String", "MyPaymentTableName");

فیلد‌های مورد نیاز در این جدول:

ذخیره و بازیابی اطلاعات توسط روش مورد نظر شما:
در صورتیکه مایلید ذخیره و بازیابی را به روش خود انجام دهید، کلاس Storage را پیاده سازی کنید
public class MyStorage : Storage
{
    // Implement methods here...
}

و کلاس مورد نظر را در تنظیمات به عنوان منبع، معرفی کنید.
ParbadConfiguration.Storage = new MyStorage();

لازم به ذکر است که این کلاس شامل متد‌های synchronous و همچنین asynchronous است. بنابراین در صورتیکه برای مثال در هنگام ارسال درخواست به بانک، از متد‌های async استفاده می‌کنید، نیازی به پیاده سازی کردن متد‌های synchronous نیست.
در صورتیکه هر گونه پیشنهاد یا انتقاد نسبت به کارکرد این سیستم دارید، صمیمانه منتظر شنیدن آن در راستای توسعه این سیستم هستم.
همچنین در صورت تمایل به توسعه آن، می‌توانید آن را در گیت هاب دنبال کنید و یا لطفا پیشنهادات، بحث‌ها و نظرات خود را در صفحه مخصوص این پروژه ارسال کنید. 
با تشکر.

نظرات

  • محسن قشقایی در ۱۳۹۷/۰۴/۱۹ ۸:۱۳
    با تشکر از مطالب مفید شما
    فقط یک سوال اینجا پیش میاد اطلاعات شماره درگاه و نام کاربری و کلمه عبور عملا در این روش کاربردی نداره ؟
    احراز اطلاعات پذیرنده به چه صورتیه ؟
    امنیت استفاده از این پکیج را هم ممنون میشم توضیح بفرمائید
    • مصطفی وکیلی در ۱۳۹۷/۰۴/۱۹ ۱۰:۳۰
      مگه میشه که کاربردی نداشته باشه, شماره درگاه و نام کاربری, رمز عبور برای این هستش که شما توسط شبکه پرداختی تایید هویت بشین و وجه مربوط به خرید اینترنتی به حساب شما تسویه بشه, 
      توی بخش مربوط به تنظیمات درگاه پرداخت توی تصویر اگه دقت کنی این خط کد رو میتونی ببینی:
      ParbodConfiguration.Gateways.ConfigureMellat 
    • سینا سلطانی در ۱۳۹۷/۰۴/۱۹ ۱۳:۴۷
      در مورد ثبت اطلاعات همونطور که دوستمون گفتن برای نمونه ثبت مشخصات بانک ملت مثال زده شده.
      در مورد امنیت، این پروژه اوپن سورس هست لینک گیت هاب هم در توضیحات موجوده.
      حتی در صورتیکه شخصی نسبت به امنیت اطلاعاتشون تردید داشته باشه، باید این رو در نظر داشته باشه که به هیچ وجه شخص دیگری با این اطلاعات کاری نمیتواند انجام دهد، به دو دلیل:
      ۱) کلیه عملیات بانکی فقط و فقط از جانب آی پی سرور یا وب سایت فروشنده (صاحب وب سایت) قابل دریافت هست که این آی پی در هنگام سفارش درگاه پرداخت توسط صاحب وب سایت، به بانک ارائه شده است.
      ۲) هیچ عملیاتی مانند انتقال وجه از یک حساب به حساب دیگه وجود نداره و این عملیات صرفا سه حالت اصلی و عمده، ثبت، تایید و برگشت هست.
  • دادگر در ۱۳۹۷/۰۴/۱۹ ۱۰:۴۲
    سلام
    با تشکر از پروژه و توضیحات خوبتون،
    token و... که از طرف بانک می‌گیریم را کجا باید تنظیم کنیم؟
    • سینا سلطانی در ۱۳۹۷/۰۴/۱۹ ۱۳:۴۱
      کلیه مشخصات و اطلاعاتی که از بانک دریافت میکنید را باید در قسمت تنظیمات درگاه‌ها وارد کنید.
      به مثال تنظیم درگاه بانک ملت توجه کنید.
  • ابراهیم زارعی در ۱۳۹۷/۰۴/۱۹ ۱۴:۴۰
    با تشکر از مطلب مفید شما
    این کتابخانه در برنامه نویسی موبایل  زامارین اندروید هم کاربرد داره ؟
    • علی یگانه مقدم در ۱۳۹۷/۰۴/۱۹ ۱۵:۱۴
      در برنامه نویسی موبایل درگاه ابتدا باید در سمت وب پیاده گردد و سپس در برنامه نویسی موبایل پیاده سازی شود و ارتباط با سرویس وب برقرار شود.
       این نسخه برای وب نوشته شده است و همانطور که میبینید نیاز به پردازش httpcontext دارد.
    • محسن خان در ۱۳۹۷/۰۴/۱۹ ۱۵:۴۲
      نیاز به کامپایل پروژه برای NET Standard. هست که در نگارش‌های جدید Xamarin از آن پشتیبانی می‌شود (علاوه بر برنامه‌های مخصوص NET Core.).
      • سینا سلطانی در ۱۳۹۷/۰۴/۱۹ ۱۶:۵۶
        متاسفانه فقط برای Net Standard. نسخه ۲ و بعد از ۲ میشه یک نگارش تهیه کرد چون در نگارش‌های قبل از دو، تمامی امکانات دات نت فریم ورک موجود نیست و ناقص هست. برای مثال XmlDocument در نسخه قبل از ۲ وجود نداره.
        ضمن اینکه در این پروژه هیچگونه وابستگی به سایر کتابخانه‌های (Nuget) غیر رسمی مایکروسافت وجود نداره، به این علت که هدف تولید یک پروژه کاملا مستقل و بسیار ساده بدون هیچگونه وابستگی هست. به این صورت استفاده کننده‌ها میتونن راحت نصب و استفاده کنن.
        البته میشه به قول معروف بیخیال نسخه‌های قبلی شد و استفاده کنندگان ملزم به داشتن دات نت استاندارد حداقل نسخه ۲ باشند.
  • ابوالفضل بهاری س در ۱۳۹۷/۰۴/۱۹ ۲۰:۲۷
    سلام
    ممنون بابت مطلب مفیدتون
    میخواستم بدونم با استفاده از این سیستم نیازی به افزودن ادرس وب سرویس‌ها در فایل webconfig هست؟
    • سینا سلطانی در ۱۳۹۷/۰۴/۱۹ ۲۱:۴۶
      سلام.
      خیر نیاز به هیچگونه وب سرویسی نیست. یکی از دلایل ساخت این پروژه، درگیر نبودن با همین وب سرویس‌ها بود :)
      • ابوالفضل بهاری س در ۱۳۹۷/۰۴/۲۰ ۹:۴۰
        ممنون از راهنمایی
        میخواستم بدونم امنیت در این پروژه به چه نحوی مدیریت میشه؟
        منظورم این هست که برای ارسال اطلاعات تنظیمات درگاه توسط یک کلید که خود کاربر ارسال میکند اطلاعات رو Enc , Dec کرد تا امنیت بیشتری وجود داشته باشه
        • سینا سلطانی در ۱۳۹۷/۰۴/۲۰ ۱۳:۴۲
          منظورتون رو از ارسال اطلاعات درگاه متوجه نمیشم. اگر منظورتون ارسال به درگاه بانک هست، که خب چنین موردی نباید انجام بشه چون اونوقت درگاه بانک چطور میخواد اطلاعات رو دیکد کنه. در واقع روش ارسال رو ما تعیین نمیکنیم. بانک تعیین میکنه.
        • محسن خان در ۱۳۹۷/۰۴/۲۰ ۱۴:۱۱
          هر بانکی بر اساس مستنداتی که ارائه می‌کنه، مشخص خواهد کرد که دیتا را باید با چه فرمتی به سمت آن ارسال کنید (و با چه فرمتی اطلاعات نهایی را دریافت خواهید کرد). این قسمت همیشه برای آن بانک ثابت است و در این کتابخانه پیاده سازی شده. بنابراین بهترین امنیتی را که در این بین می‌توانید برقرار کنید، پیاده سازی SSL در سایت خودتان است تا رفت و برگشت اطلاعات رمزنگاری شده و در بین راه قابل شنود نباشد.
  • سینا سلطانی در ۱۳۹۷/۰۴/۲۰ ۱۴:۱۲
    مثال‌های کامل برای پروژه‌های WebForm و MVC به سورس گیت هاب اضافه شد
  • ابوالفضل بهاری س در ۱۳۹۷/۰۵/۰۶ ۱۶:۷
    یه سوال داشتم
    برای باشگاه مشتریان بانک ملت از متد bpCumulativeDynamicPayRequest  استفاده میکنم که از پارامتر additionalData استفاده می‌شود آیا امکان اضافه کردن این متد هست؟ و نحوه افزودن پارامتر اضافی
    و یه نکته دیگه اینکه کد سفارش باید یکتا باشد؟ برای تمامی بانک ها؟
    با تشکر
    • سینا سلطانی در ۱۳۹۷/۰۵/۰۶ ۱۶:۳۹
      در حال حاضر برای کلیه درگاه‌ها، فقط سه حالت اصلی: درخواست، تایید و برگشت وجود داره.
      سعی میکنم به زودی امکانات اختصاصی هر درگاه رو هم پیاده سازی کنم.
      کد سفارش بله باید یکتا باشد طبق دستورالعمل کلیه بانک‌ها.
      در ضمن در صورت استفاده از این پکیج، حتما به آخرین نسخه به روز رسانی کنید. مشکلات اخیر درگاه ملت رفع شده.
      • ابوالفضل بهاری س در ۱۳۹۷/۰۵/۰۶ ۱۶:۴۸
        سپاس از شما
        پس منتظر ساختار جدید برای بانک ملت هستم این نمونه ای هست که پیاده سازی کردم
                            payRequest = _melatServiceReference.bpCumulativeDynamicPayRequest(
                                bankServiceViewModel.MerchantId.ToLong(),
                                bankServiceViewModel.Username,
                                bankServiceViewModel.Password,
                                alternativeOrderCode,
                                payableAmount,
                                DateTime.Now.DateToString(),
                                DateTime.Now.TimeToString("HHMMss"),
                                $"{systemshareMechentId},{systemShareAmount},;{customemembershareId},{merchantShareAmount},;",
                                bankTokenRequestViewModel.CallBackUrl);
        ممنون از شما
        کد باشگاه مشتریان systemshareMechentId
        کد کاربری ما در باشگاه customemembershareId 
        • سینا سلطانی در ۱۳۹۷/۰۵/۲۴ ۲۰:۳۰
          لطفا در صورتیکه شما با باشگاه مشتریان کار کرده اید و براتون مقدور هست، موارد زیر را در صفحه این پروژه پاسخ بدید.
          ۱) آیا فایل راهنما برای متدهای باشگاه مشتریان موجود هست؟ (بنده در مستندات، هیچ توضیحی در مورد این متد پیدا نکردم)
          ۲) آیا در قسمت additionaldata ، فرمت داده باید دقیقا حالتی که شما اینجا مثال زدید باشد یا اینکه حالات دیگری هم امکان پذیر هست؟
          ۳) متد دیگری هم به نام bpDynamicPayRequest موجود هست. فرق این دو متد چیست؟
          تشکر.
  • ابوالفضل بهاری س در ۱۳۹۷/۰۵/۰۸ ۲:۳۷
    برای بانک ملت این خطا صادر میشود:
    <?xml version="1.0" encoding="UTF-8"?>
    
    -<Log xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    
    <Type>Error</Type>
    
    <Gateway>Mellat</Gateway>
    
    <OrderNumber>636685148523361974</OrderNumber>
    
    <Amount>72000</Amount>
    
    <Message>The remote server returned an error: (500) Internal Server Error.</Message>
    
    <CreatedOn>2018-07-30T02:34:12.4425676+04:30</CreatedOn>
    
    </Log>
    ولی بانک سامان بدون مشکل اجرا می‌شود
    مشکل از کجاست؟
    مشکلی با تعریف چندین بانک که نیست؟
    • ابوالفضل بهاری س در ۱۳۹۷/۰۵/۰۸ ۳:۱
      مشکل برطرف شد.
      نکته: در اکشن Verify پارامتر ارسال میکردم که بانک ملت خطا میگرفت
      • سینا سلطانی در ۱۳۹۷/۰۵/۰۸ ۱۴:۴۶
        متوجه منظورتون نشدم دقیقا.
        مشکل از پَرباد بود یا بانک ملت؟
        منظورتون از "در اکشن Verify پارامتر ارسال میکردم" چی هست؟
        • ابوالفضل بهاری س در ۱۳۹۷/۰۵/۰۹ ۲۰:۴۷
          در اکشن Verify پارامتر trackingCode بود که زمانی که بانک ملت رو از پرباد درخواست میکردم خطا صادر میشد. ولی برای سایر بانک‌ها مشکل خاصی نبود
          زمانی که پارامتر‌ها رو برداشتم مشکل برطرف شد
          ممنون از این کامپوننت فقط ممنون میشم متد bpCumulativeDynamicPayRequest   در سرویس بانک ملت رو زودتر اماده کنید
          با تشکر منتظر خبر شما هستم
  • ابوالفضل بهاری س در ۱۳۹۷/۰۵/۲۰ ۲۳:۳۲
    در بانک ملت SaleReferenceId در کدام فیلد در لاگ قرار میگیرد؟
    این فیلد برای من فقط عدد هست و میتونم از طریق پنل بانک ملت پیگیری کنم پرداختی کاربر اما در لاگ شما حرف و عدد هست
    <?xml version="1.0" encoding="utf-8"?>
    <Log xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
      <Type>Verify</Type>
      <Gateway>Mellat</Gateway>
      <OrderNumber>636687181261995054</OrderNumber>
      <Amount>40000</Amount>
      <ReferenceId>691EF56C920E61EC</ReferenceId>
      <TransactionId />
      <Status>Failed</Status>
      <Message>کاربر از انجام تراکنش منصرف شده است</Message>
      <CreatedOn>2018-08-01T11:02:11.8155948+04:30</CreatedOn>
    </Log>
    • سینا سلطانی در ۱۳۹۷/۰۵/۲۱ ۰:۲۱
      SaleReferenceId در بانک ملت معادل فیلد TransactionID در پَرباد هست.
      دو مورد اصلی که در هر تراکنش بانکی وجود داره:
      ۱) شماره رجوع ( در سیستم پَرباد معادل فیلد ReferenceID )
      ۲) شماره تراکنش ( در سیستم پَرباد معادل فیلد TransactionID )
      این دو مورد در بانک‌های مختلف، هر کدام به شکل مختلفی نامگزاری شدن.
      شماره رجوع در زمان ارسال درخواست برای پرداخت تعلق میگیره. شماره تراکنش پس از پرداخت برای اون تراکنش تعلق میگیره.
      طبق لاگی که شما اینجا قرار دادین، تراکنش موفق نبوده. بنابراین شماره تراکنش (SaleReferenceID) هم وجود نداره.
      • ابوالفضل بهاری س در ۱۳۹۷/۰۵/۲۱ ۱:۱۷
        ممنون از راهنمایی
        این لاگ رو ببینید
        <?xml version="1.0" encoding="utf-8"?>
        <Log xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
          <Type>Request</Type>
          <Gateway>Mellat</Gateway>
          <OrderNumber>636687184847922187</OrderNumber>
          <Amount>1770000</Amount>
          <ReferenceId>51833F8D2D0C78A2</ReferenceId>
          <TransactionId />
          <Status>Success</Status>
          <Message>تراکنش با موفقیت انجام شد</Message>
          <CreatedOn>2018-08-01T11:08:05.0821891+04:30</CreatedOn>
        </Log>
        اینجا موفق بوده اما TransactionID خالی هست؟
        باید در برگشت یعنی Verify پرداخت موفق باشه تا  TransactionID   دیتا داشته باشد؟
        • ابوالفضل بهاری س در ۱۳۹۷/۰۵/۲۱ ۱:۲۶
          درست شد
          در صورت پرداخت موفق فیلد TransactionID  اطلاعاتش پر می‌شود
          <?xml version="1.0" encoding="utf-8"?>
          <Log xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
            <Type>Verify</Type>
            <Gateway>Mellat</Gateway>
            <OrderNumber>636696338698017740</OrderNumber>
            <Amount>50000</Amount>
            <ReferenceId>63610A4322A08FDD</ReferenceId>
            <TransactionId>139032371054</TransactionId>
            <Status>Success</Status>
            <Message>تراکنش با موفقیت انجام شد</Message>
            <CreatedOn>2018-08-12T01:25:31.1869631+04:30</CreatedOn>
          </Log>


        • سینا سلطانی در ۱۳۹۷/۰۵/۲۱ ۱:۲۷
          ممنون از اطلاع رسانی. در واقع متن Message اینجا  صحیح نیست و باید برای مثال چیزی معادل "درخواست با موفقیت ارسال شد" باشه.
          نوع درخواست رو دقت کنید. از نوع Request هست. یعنی شما الان فقط به بانک درخواست پرداخت رو ارسال کردید. بانک در جواب به شما یک شماره رجوع (ReferenceId) ارسال کرده که با این شماره بتونیم به درگاه بریم و پرداخت رو انجام بدیم.
          در نتیجه طبق کامنت قبلی که دادم، شماره تراکنش (TransactionID) فقط در صورت یک پرداخت موفق به شما اختصاص داده میشه.
          • ابوالفضل بهاری س در ۱۳۹۷/۰۵/۲۱ ۱:۴۶
            سپاس از شما که با این کامپوننت کار رو خیلی خیلی ساده کردید.
            منتظر بروزرسانی جدید شما هستم برای بانک ملت bpCumulativeDynamicPayRequest که برای پرداخت‌های اشتراکی هست
            تشکر فراوان از شما
            • سینا سلطانی در ۱۳۹۷/۰۵/۲۱ ۱:۵۰
              خواهش میکنم.
              در حال ارتقاء و کار بر روی نسخه جدید هستم. در صورت انتشار حتما همینجا اطلاع میدم.
  • ابوالفضل بهاری س در ۱۳۹۷/۰۵/۲۲ ۳:۳۹
    نکته : در زمانی که ذخیره و بازیابی اطلاعات توسط روش مورد نظر  انجام می‌شود پس از Verify کردن متد Update فراخوای می‌شود.
    به نظرم باید متد Insert فراخوانی شود که لاگ روند تغییرات رو داشته باشیم که بتونیم به کاربر نمایش دهیم در این حالت اطلاعاتی مثل Status بروزرسانی می‌شود و دیگر نمی‌توان اطلاعات روند قبلی رو نمایش داد.
    به عنوان مثال :
    1. ارسال درخواست
    2. انصراف از خرید
    3. تایید درخواست
    باتوجه به یکتا بودن شماره درخواست باید در زمان ارسال مجدد درخواست ، هم فیلد Id و هم فیلد orderNumber همانند به صورت درخواست اولیه باشد یعنی فیلد Id جدید و OrderNumber هم براساس شماره درخواست جدید باشد.
    نظر شما در این مورد چیست؟
    نکته دیگر اینکه با توجه به یکتا بودن شماره سفارش تابع SelectByOrderNumberAsync  عملا همیشه مقدار null برمیگرداند
    فیلد Message که در فایل XML موجود هست در مدل موجود نمی‌باشد.
    • سینا سلطانی در ۱۳۹۷/۰۵/۲۲ ۴:۱۳
      در مورد تابع SelectByOrderNumberAsync ، خیر همیشه null نیست. اگر همیشه null بود، امکان تشخیص و صدور خطای تکراری بودن به کاربر وجود نداشت. در واقع درسته که منطق سیستم گفته شماره سفارش باید یکتا باشد، ولی به کاربر نمیشه اعتماد کرد و باید یک عملیات چک کردن وجود داشته باشه که در صورت اشتباه کاربر، به اون اعلام کنه که تکراری هست.
      فیلد Message باید اضافه بشه ممنون بابت گزارش.
      و در مورد پیشنهادی که دادید، پیشنهاد خوب و صحیحی هست. سعی میکنم در همین آپدیت جدید پیاده سازیش کنم.
      تشکر.
      • ابوالفضل بهاری س در ۱۳۹۷/۰۵/۲۲ ۴:۱۶
        تابع SelectByIdAsync  با شرایط جدید آیا لازم می‌باشد؟ 
        به نظرتون کی آپدیت جدید آماده میشه؟ چون من میخواستم از این پکیج استفاده کنم 
        با سپاس از شما بابت همراهی خوبتون
        • سینا سلطانی در ۱۳۹۷/۰۵/۲۲ ۴:۲۷
          تابع SelectByIdAsync  بله ضروری هست. علت اینه که در هنگام بازگشت کاربر از بانک، سیستم، تراکنش مورد نظر رو از روی ID تشخیص میده نه از شماره سفارش. علت هم مربوط به امنیت هست. شماره سفارش میتونه توسط هر شخصی بالا و پایین بشه و به وب سایت ارسال بشه جهت خرابکاری و اینجور مسائل. ولی ID یک کد GUID هست که خب قطعا غیر قابل حدس هست و عدد نیست که با بالا و پایین کردن بشه تغییرش داد.
          آپدیت جدید شامل موارد خیلی زیادی هست که پیاده سازی شده و در حال پیاده سازی هست. به همین دلیل زمان دقیق و مشخصی نمیتونم اعلام کنم. ولی فکر میکنم تا کمتر از دو هفته آماده بشه.
  • سینا سلطانی در ۱۳۹۷/۰۵/۲۳ ۴:۰
    جهت اطلاع
    لطفا پیشنهادات، بحث‌ها و نظرات خود را در صفحه مخصوص این پروژه ارسال کنید.
  • ابوالفضل بهاری س در ۱۳۹۷/۰۵/۲۶ ۱۷:۵۲
    در زمان اجرا میشه تنظیمات مربوط به درگاه‌ها رو تغییر داد؟
    چون ممکنه بانک جدیدی در زمان اجرا اضافه شود که نیاز به restart کردن iis نباشد
    • سینا سلطانی در ۱۳۹۷/۰۵/۲۶ ۲۰:۲۵
      بله تنظیمات را در هر زمان میتوان تغییر داد. فقط کافیست مرحله تنظیمات درگاه را در هر نقطه ای که میخواهید تکرار کنید. به اینصورت، تنظیمات جدید جایگزین قبلی خواهد شد.
      دو حالت جدید هم در نسخه جدید در حال پیاده‌سازی هست:
      1. تنظیم از طریق خواندن فایل
      2. تنظیم توسط "روش مورد نظر کاربر در زمان آینده"
      لطفا بحث‌ها، نظر‌ها و پیشنهاد‌ها رو در صفحه پروژه عنوان کنید.
      تشکر.
  • زهره وند در ۱۳۹۷/۰۶/۱۹ ۱۸:۱۲

      وقت بخیر؛ سوالی در خصوص پیاده سازی درگاه پرداخت اینترنتی در پروژه‌های SPA دارم. بنده سمت کلاینت از انگیولار و سمت بک اند از Web Api 2 استفاده میکنم. مشکلی که وجود داره اینه که بعد از تکمیل خرید، ریسپانس رو به redirectUrl قراره Post بشه. پس من قاعدتا redirectUrl رو نمیتونم برابر با Route خاصی در برنامه‌ی انگیولار قرار بدم. چون پشت مسیرهای انگیولار هیچگونه اکشنی وجود نداره که من بخوام HttpVerb این مسیر خاص را روی Post قرار بدم. اگه ریسپانس رو توسط Get توی Url میفرستاد قضیه فرق میکرد و میشد مقادیر را از Url خواند. پس redirectUrl رو برابر با آدرس یک Api قرار دادم که HttpVerb آن  Post هست. ریسپانس رو در این Api میگیرم و فعالیتهای مورد نیاز رو در سمت بک اند میتونم انجام بدم. اما تکلیف نمایش نتیجه‌ی پرداخت به کاربر چی میشه؟
    نکته‌ی دیگری که وجود داره اینه که سرویس‌ها و برنامه انگیولار در 2 آدرس متفاوت هستند؛ یعنی
    Api ‌ها رو Azure هاست هستن و انگیولار جایی دیگه. در اینجا باز هم به همان دلیل که امکان Post Request به Route‌های انگیولار وجود نداره نکته‌ی چشم گیری نیست.

    اگه کسی در پروژه‌های SPA درگاه پرداخت اینترنتی استفاده کرده ممنون میشم  به این سوال پاسخ بده. اگه درگاه بانک سامان استفاده کرده باشه که چه بهتر...

    • محسن خان در ۱۳۹۷/۰۶/۱۹ ۱۸:۲۴
      می‌تونی از SignalR برای اطلاع رسانی نتیجه‌ی عملیات سمت سرور به کلاینت‌ها استفاده کنی (این مورد یک مثال کلاسیک SignalR هست). چون هاست‌ها هم یکی نیست، باید CORS رو فعال کنی تا بشود بین این دو تبادل اطلاعات کرد.
      • زهره وند در ۱۳۹۷/۰۶/۱۹ ۲۲:۲۴
        تشکر از راهنماییتون 
        اما نکته ای که وجود داره اینه که پارامتر redirectUrl که داره میگیره الزاما  باید قابلیت Post شدن داشته باشه ! من حتی نمیتونم فقط آدرس یه کامپوننت را بهش بدم چون در اینصورت باز خطا میده میگه نمیتونه به این مسیر Post کنه .
        دنبال یه راه ساده‌تر میگردم ، اگه راهی پیدا نکنم مجبورم درگاه از بانک دیگری بگیرم.
        • محسن خان در ۱۳۹۷/۰۶/۱۹ ۲۲:۴۰
          شما مسیر یک اکشن متد سمت سرور را برای Redirect به آن بدهید. پس از پایان کار آن (با هر روشی که هست؛ POST یا GET)، برنامه‌ی Angular باید از صفر load شود (این Redirect همان برنامه‌ی قبلی را که باز بوده نمایش نمی‌دهد و سبب بارگذاری مجدد کل برنامه می‌شود). در اینجا در متد ngOnInit از نتیجه‌ی کار کوئری بگیرید و آن‌را نمایش دهید.
        • سینا سلطانی در ۱۳۹۷/۰۶/۱۹ ۲۲:۵۰
          شما با هر درگاهی که کار کنید هیچ فرقی در مشکل فعلی شما به وجود نمیاره چون redirecturl برای تمامی درگاه‌های پرداخت مورد نیاز هست.
          برای این نوع پرداخت، روش‌های مختلفی وجود داره.
          آدرس بازگشتی باید حتما یک آدرس در سمت سرور باشه نه کلاینت. هنگامیکه کاربر پرداخت رو انجام میده، توسط درگاه بانکی، به آدرس بازگشتی شما در سرور هدایت میشه و شما در اون مرحله عملیات تایید تراکنش رو انجام میدید. برای اینکه سمت کلاینت از تمام شدن پرداخت با خبر بشید، میتونید اون فرمی رو که در مرحله اول به سمت درگاه سامان پست کرده بودید رو به صورت یک popup window توسط جاوا اسکریپت باز کنید. زمانیکه یک شی window درست میکنید، میتونید event هم برای اون اختصاص بدید. رخدادی که شما احتیاج دارید onbeforeunload هست. توسط این رخداد میتونید متوجه بشید که پنجره پرداخت بسته شده و شما برای مثال یک سرویس در سمت سرور رو جهت دریافت اطلاعات تراکنش صدا بزنید.
          توجه داشته باشید که پنجره پرداخت هنگامی که کاربر به سرور شما اومد میتونه توسط جاوا اسکریپت بسته بشه.
    • سینا سلطانی در ۱۳۹۷/۰۶/۱۹ ۲۱:۵۶
      سعی میکنم به زودی مطلب آموزشی در رابطه با پرداخت در Angular قرار بدم.
      • زهره وند در ۱۳۹۷/۰۶/۱۹ ۲۲:۲۵
        تشکر میکنم .
        اما اگه راه حلی برای این مسئله به ذهنتون رسید ممنون میشم سرنخی ازش بهم بدید .
  • ابوالفضل بهاری س در ۱۳۹۷/۰۶/۱۹ ۲۰:۱۴
    جناب مهندس کی نسخه جدید اماده میشه؟ برای پرداخت باشگاه مشتریان
    سپاس از شما
    • سینا سلطانی در ۱۳۹۷/۰۶/۱۹ ۲۰:۳۸
      فکر میکنم در همین هفته به اتمام برسه.
  • محمد احمدی نیا در ۱۳۹۷/۰۷/۰۳ ۱۱:۵۷
    با سلام
    جهت implement کردن کلاس storage اشاره دقیقی نشده است، و در پروژه sample mvc نیز از آن استفاده ای نشده است. بهترین روش برای کار با این بخش به چه صورت می‌باشد.
    با تشکر.
    • سینا سلطانی در ۱۳۹۷/۰۷/۰۳ ۱۴:۳۰
      implement کردن کلاس Storage کاملا بستگی به پیاده‌سازی خود کاربر داره.
      برای مثال شما میخواهید دیتابیس شما به صورت فایل XML باشه. پس بنابراین کلاس Storage رو Implement میکنید و ساختار مربوط به خواندن و نوشتن فایل XML رو پیاده‌سازی میکنید.
      - البته در نسخه جدید که بین این هفته و هفته آینده منتشر میشه، دیگه نیازی به درگیری با این مساله ندارید.
  • محمد احمدی نیا در ۱۳۹۷/۰۷/۰۳ ۱۲:۲
    با تشکر ویژه از ارائه پروژه پرکاربرد درگاه‌های بانکی، درصورت امکان درگاه بانک ملی سداد را نیز در این پروژه پیاده سازی کنید.
  • رضا چونک در ۱۳۹۷/۰۹/۰۴ ۲۳:۴۱
    آیا در net core هم میشه از این کامپوننت استفاده کرد؟
    حساب‌های چند پرداختی هم مثل باشگاه مشتریان بانک ملت هم میشه استفاده کرد؟
    • سینا سلطانی در ۱۳۹۷/۰۹/۰۵ ۰:۵۲
      خیر.  ورژن جدیدی در حال توسعه هست که قابلیت استفاده در NetCore. رو داره.
      امکانات هر درگاه (مثل باشگاه مشتریان) هم از قابلیت‌های ورژن جدید هست.
  • دادگر در ۱۳۹۷/۰۹/۰۵ ۱۷:۱۵
    قابلیت استفاده از سایت‌های واسطی مثل زرین پال و... هم می‌تونه برای کار مفید باشد
    با تشکر از پروژه خوبتان
  • سینا سلطانی در ۱۳۹۷/۱۰/۰۶ ۱۸:۴۰
    درگاه بانک ملی (سداد)  به صورت نسخه تست  به پرداخت اینترنتی افزوده شد.
    پذیرنده‌هایی که درگاه ملی سداد را در اختیار دارن، در صورت تمایل، میتوانند نسخه جدید را امتحان کنند و نتیجه عملکرد را در صفحه پروژه اعلام کنند.
    نحوه نصب:
    Install-Package Parbad -Version 1.3.0-beta1

    نسخه نهایی پس از موفق بودن تست منتشر خواهد شد.
    • رضا چونک در ۱۳۹۷/۱۰/۱۸ ۱۵:۳۸
      در نسخه 1.2.1 آیا ویژگی جدیدی اضافه شده است؟
      • سینا سلطانی در ۱۳۹۷/۱۰/۱۸ ۱۹:۵۷
        ویژگی خیر. باگ مربوط به SQL Query رفع شده.
        در بخش Release Notes هر نسخه، میتونید تغییرات اون نسخه رو مشاهده کنید.
        • رضا چونک در ۱۳۹۷/۱۰/۲۰ ۸:۱۹
          متاسفانه نمیشه به نسخه 1.2.1 آپدیت کرد و اینکه مشکل در آپدیت پکیج مربوط به MVC هم هست
          • وحید نصیری در ۱۳۹۷/۱۰/۲۰ ۸:۵۷
            لطفا پیشنهادات، بحث‌ها و نظرات خود را با جزئیات بیشتر در صفحه مخصوص این پروژه ارسال کنید.  
          • سینا سلطانی در ۱۳۹۷/۱۰/۲۰ ۱۱:۴۲
            حداقل نسخه مورد نیاز برای MVC رو، معادل آخرین نسخه Parbad قرار دادم (نسخه بتا) که متقابلا این نسخه دانلود بشه و دوستان محبت کنن نسخه بتا رو تست کنن و عملکرد صحیح نسخه بتا رو اطلاع بدن. متاسفانه خیلی‌ها نصب میکنن استفاده میکنن و اگر عملکرد صحیح باشه اطلاعی نمیدن. در نتیجه نسخه Stable ممکنه حتی چند ماه زمان ببره تا ارائه بشه.
            در هر صورت بهتره شما همیشه از آخرین نسخه استفاده کنید. نسخه بتا فعلی، با نسخه‌های قبل از لحاظ درگاه‌های بانکی هیچ تفاوت خاصی نداره و فقط درگاه ملی سداد جهت تست اضافه شده.
            ابتدا Parbad رو آپدیت کنید به آخرین نسخه. سپس Mvc رو آپدیت کنید
  • سینا سلطانی در ۱۳۹۷/۱۰/۲۶ ۱۸:۴۳
    نسخه 1.3.0 منتشر شد.
    تغییرات:
    درگاه بانک ملی (سداد) افزوده شد.
    HttpContextBase جهت اهداف تست افزوده شد.
    درگاه بانک تجارت منسوخ شد. (از درگاه «ایران کیش» استفاده شود)
    لطفا هر گونه نظر در رابطه با این نسخه را در صفحه پروژه ارسال کنید.
  • سینا سلطانی در ۱۳۹۸/۰۱/۰۹ ۱۴:۳۹
    مقاله و نسخه جدید با قابلیت پشتیبانی از NETCORE. را در این لینک دنبال کنید