You are here:   Blog
Register   |  Login

 

Sep 1

Written by: Michael Washington
9/1/2013 8:59 PM  RssIcon

image

This example application shows how you can integrate a complex API such as PayPal Adaptive Payments with Visual Studio LightSwitch.

I recently had a challenge where I needed to create a marketplace where people can sell items. I did not want to collect the money and pass it from buyer to seller because I would get stuck with losses if the buyer reversed the charges (for example because their account was used without their permission) and I had already passed the money to the seller. The solution was to submit two charges, one directly from the buyer to the seller, and one as a fee that would go to me for hosting the marketplace. In addition, I did not want to release the item being sold (in this case a picture download) until the funds had cleared. For example, if a person pays with a check it can take days for the check to clear.

The Sample Application

You can test out the sample application at:

https://paypalstore.lightswitchhelpwebsite.com/HTMLClient/

(use your user name and password of your LightSwitchHelpWebsite.com account)

Note: All transactions are real and your PayPal account will be debited $2.00  (thank you for the support!). However, please  do not complete a transaction and then reverse the charges, that will cause me quite a hassle.

image

A user can browse the available pictures and purchase a copy by clicking the Buy a Copy button.

 

image

They are taken to a page where they can click the Buy Now button.

 

image

They are taken to the PayPal site where they can pay.

 

image

They can use a credit card (if the merchant account has that option), check, or their PayPal account.

 

image

After making payment they see a confirmation.

 

image

They are taken back to the application, to the My Purchases page.

 

image

Clicking on a purchase record will take them to a page where they can download the picture, if the payment has cleared.

If the payment has not cleared, it will say so and display any error messages. Once payment has cleared this page will allow them to download the picture.

 

image

Any user can upload their own pictures, indicate that they are a Merchant, and enter their PayPal account.

 

image

An administrator can see and diagnose all transactions. The administrator is defined when the application is published using the Visual Studio LightSwitch publishing wizard.

The administrator PayPal account is also configured in the web.config file (this is covered in the next section).

 

The PayPal API

Important Note: I must say up front that this code and example is very complicated. It is only provided to help programmers who can understand it. I posted the live example to prove that it works. however, it is very complicated because the PayPal API is complicated.

If you need help with any PayPal issues see: https://developer.paypal.com/webapps/developer/support

If you need help with any LightSwitch issues post to: http://social.msdn.microsoft.com/Forums/vstudio/en-US/home?forum=lightswitch

Also note, the PayPal IPN notifications will only work if the application has been published using the using the Visual Studio LightSwitch publishing wizard and is at a location that can be reached by the PayPal servers.

image

The code in the sample LightSwitch application uses the PayPal Adaptive Payments Classic API: https://developer.paypal.com/webapps/developer/docs/classic/adaptive-payments/gs_AdaptivePayments/. You can get a complete overview of PayPal Adaptive Payments at this link: https://developer.paypal.com/webapps/developer/docs/classic/adaptive-payments/integration-guide/APIntro/.

image

Specifically it uses the Pay API call to make a parallel payment: https://developer.paypal.com/webapps/developer/docs/classic/api/adaptive-payments/Pay_API_Operation/.

It also uses the PayPal IPN Classic API to determine when a payment has been completed: https://developer.paypal.com/webapps/developer/docs/classic/products/instant-payment-notification/.

 

Running The Sample Application

image

First you need a PayPal developer account: https://developer.paypal.com/webapps/developer/docs/classic/api/gs_PayPalAPIs/#account.

image

This page shows you how to get your API credentials: https://developer.paypal.com/webapps/developer/docs/classic/api/apiCredentials/.

You will need to put your values in the web.config of the sample LightSwitch application in the spots marked with a ***.

image

You will also need to go to: https://apps.paypal.com to create a PayPal Classic Application (this is because at the time of this writing the Adaptive Payments API is not available using the newer REST Services API).

image

Create a new application. This will create a Sandbox ID that you will need to also put in the web.config of the sample app.

image

When you create your application, use the settings in the image above.

image

You will need to create PayPal Sandbox test accounts: https://developer.paypal.com/webapps/developer/docs/classic/lifecycle/ug_sandbox/#accounts

The merchant test account will need to be entered in the web.config of the LightSwitch application.

The sample transactions will need three accounts and no two can be the same so you will need to create two additional test accounts (besides the test merchant account that will be created for you) to use to test the application.

 

image

Open the sample LightSwitch application (available on the downloads page), switch to file view, and open the Web.config, and enter the values in the spaces marked ***.

The application should now work.

If it doesn’t work for you:

Also note: the PayPal IPN notifications will only work if the application has been published using the using the Visual Studio LightSwitch publishing wizard and is at a location that can be reached by the PayPal servers.

When the sample application was created, I used the PayPal Nuget package to install the needed binaries: https://www.nuget.org/packages/PayPalCoreSDK.

 

Exploring The Sample Application

image

The application starts with the code from the article:

LightSwitch HTML Picture Manager Using WCF RIA Services.

image 

The PayPal version adds additional tables and screens.

Note that important code is implemented to properly secure the PayPal tables:

 

       // PayPalPurchaseTransactions
        #region PayPalPurchaseTransactions
        partial void PayPalPurchaseTransactions_Filter(ref Expression<Func<PayPalPurchaseTransaction, bool>> filter)
        {
            // Only an Admin can see the entire table
            if (!(this.Application.User.HasPermission(Permissions.SecurityAdministration)))
            {
                // Users can see any Transction where they are the buyer or the seller
                filter = e => e.PurchaserUserName == this.Application.User.Identity.Name 
                    || e.SellerUserName == this.Application.User.Identity.Name;
            }
        }
        partial void PayPalPurchaseTransactions_Inserting(PayPalPurchaseTransaction entity)
        {
            // Set time and IP Address
            var context = System.Web.HttpContext.Current;
            entity.PurchaseTime = DateTime.Now;
            entity.PurchaseIPAddress = context.Request.UserHostAddress;
            // Payment Status is always set to Pending
            entity.payment_status = "Pending";
        }
        partial void PayPalPurchaseTransactions_Updating(PayPalPurchaseTransaction entity)
        {
            // An update can only be made by the orginal user
            if (!(entity.PurchaserUserName == this.Application.User.Identity.Name 
                || entity.SellerUserName == this.Application.User.Identity.Name
                || this.Application.User.HasPermission(Permissions.SecurityAdministration)))
            {
                throw new Exception(string.Format("Only buyer, seller or administrator can update!"));
            }
            // Payment Status is always set to Pending
            // IPN handler updated this value directly outside of oData
            entity.payment_status = "Pending";
        }
        partial void PayPalPurchaseTransactions_CanDelete(ref bool result)
        {
            // Only an Admin can access the table (.ashx file has an override)
            result = this.Application.User.HasPermission(Permissions.SecurityAdministration);
        }
        #endregion
        // PayPalIpnTransactions
        #region PayPalIpnTransactions
        partial void PayPalIpnTransactions_CanDelete(ref bool result)
        {
            // Only an Admin can access the table (.ashx file has an override)
            result = this.Application.User.HasPermission(Permissions.SecurityAdministration);
        }
        partial void PayPalIpnTransactions_CanInsert(ref bool result)
        {
            // Only an Admin can access the table (.ashx file has an override)
            result = this.Application.User.HasPermission(Permissions.SecurityAdministration);
        }
        partial void PayPalIpnTransactions_CanUpdate(ref bool result)
        {
            // Only an Admin can access the table (.ashx file has an override)
            result = this.Application.User.HasPermission(Permissions.SecurityAdministration);
        }
        partial void PayPalIpnTransactions_CanRead(ref bool result)
        {
            // Only an Admin can access the table (.ashx file has an override)
            result = this.Application.User.HasPermission(Permissions.SecurityAdministration);
        } 
        #endregion
        // PayPalTransactions
        #region PayPalTransactions
        partial void PayPalTransactions_CanDelete(ref bool result)
        {
            // Only an Admin can access the table (.ashx file has an override)
            result = this.Application.User.HasPermission(Permissions.SecurityAdministration);
        }
        partial void PayPalTransactions_CanInsert(ref bool result)
        {
            // Only an Admin can access the table (.ashx file has an override)
            result = this.Application.User.HasPermission(Permissions.SecurityAdministration);
        }
        partial void PayPalTransactions_CanRead(ref bool result)
        {
            // Only an Admin can access the table (.ashx file has an override)
            result = this.Application.User.HasPermission(Permissions.SecurityAdministration);
        }
        partial void PayPalTransactions_CanUpdate(ref bool result)
        {
            // Only an Admin can access the table (.ashx file has an override)
            result = this.Application.User.HasPermission(Permissions.SecurityAdministration);
        } 
        #endregion

 

The Screen

image

The Main screen is the screen customers use to search for and purchase copies of pictures.

The following code shows the Buy a Copy button if the person who uploaded the picture is a Merchant:

 

myapp.Main.isMerchant_render = function (element, contentItem) {
    // Show button if isMerchant
    if (contentItem.value == true) {
        // Get the UserPicture
        var objUserPicture = contentItem.parent;
        element.innerHTML =
            "<button type='button'>Buy a Copy</button>";
    };
};

 

When the Buy a Picture button is clicked the following code runs that calls the Adaptive Payments handler that contacts PayPal to generate a PayKey:

 

myapp.Main.UserPictures_ItemTap_execute = function (screen) {
    // Get the selected Picture
    var objUserPicture = screen.UserPictures.selectedItem;
    // Get selected selectedPictureId
    selectedPictureId = screen.UserPictures.selectedItem.Id;
    // Show the UserPicture
    myapp.showPurchaseItem(objUserPicture, {
        beforeShown: function (PurchaseItemScreen) {
            msls.promiseOperation(CallAdaptivePaymentsHandler)
                .then(function PromiseSuccess(AdaptivePaymentsHandlerResult) {
                    // Parse the JSON returned
                    var objPayPalResponse = jQuery.parseJSON(AdaptivePaymentsHandlerResult);
                    // Set the PayPal response
                    PurchaseItemScreen.PayPalRedirectUrl = objPayPalResponse.PayPalRedirectUrl
                        + "_ap-payment&paykey="
                        + objPayPalResponse.PayPalPaykey;
                    PurchaseItemScreen.PayPalPaykey = objPayPalResponse.PayPalPaykey;
                    PurchaseItemScreen.PayPalPaymentExecStatus = objPayPalResponse.PayPalPaymentExecStatus;
                    PurchaseItemScreen.PayPalError = objPayPalResponse.PayPalError;
                    PurchaseItemScreen.PayPalErrorMessage = objPayPalResponse.PayPalErrorMessage;
                });
        }
    });
};

 

The following code is the Adaptive Payments handler that contacts PayPal and returns a PayKey:

 

using System;
using System.Data;
using System.Web;
using System.Collections;
using System.Web.Services;
using System.Collections.Generic;
using System.Collections.Specialized;
using PayPal;
using PayPal.Exception;
using PayPal.Util;
using PayPal.AdaptivePayments;
using System.Configuration;
using PayPal.AdaptivePayments.Model;
using System.Linq;
using Microsoft.LightSwitch.Server;
namespace LightSwitchApplication
{
    [Serializable]
    public class PayPalResponse
    {
        public string PayPalRedirectUrl { get; set; }
        public string PayPalPaykey { get; set; }
        public string PayPalPaymentExecStatus { get; set; }
        public bool PayPalError { get; set; }
        public string PayPalErrorMessage { get; set; }
    }
    public class adaptivepaymentshandler : IHttpHandler
    {
        public void ProcessRequest(HttpContext context)
        {
            Pay(context);
        }
        public bool IsReusable
        {
            get
            {
                return false;
            }
        }
        /// <summary>
        /// Handle Pay API calls
        /// </summary>
        /// <param name="context"></param>
        private void Pay(HttpContext context)
        {
            // Get the PictureID
            int UserPicturesId = Convert.ToInt32(context.Request.Params["UserPicturesId"]);
            // Global values
            int PayPalPurchaseTransactionId = -1;
            string PayPalRedirectUrl = ConfigurationManager.AppSettings["PAYPAL_REDIRECT_URL"];
            string SellerPayPalEmail = "";
            string SellerUserName = "";
            // Instantiate PayPalResponse class
            PayPalResponse objPayPalResponse = new PayPalResponse();
            objPayPalResponse.PayPalPaykey = " ";
            objPayPalResponse.PayPalPaymentExecStatus = " ";
            objPayPalResponse.PayPalRedirectUrl = PayPalRedirectUrl;
            objPayPalResponse.PayPalErrorMessage = " ";
            objPayPalResponse.PayPalError = false;
            using (var serverContext =
                ServerApplicationContext.CreateContext()
                )
            {
                // Insert a record in the Transaction table
                var objPayPalTransaction =
                    serverContext.DataWorkspace.ApplicationData.PayPalPurchaseTransactions.AddNew();
                // Get the Picture
                var objPicture = (from Pictures in serverContext.DataWorkspace.ApplicationData
                                      .Pictures.GetQuery().Execute()
                                  where Pictures.Id == UserPicturesId
                                  select Pictures).FirstOrDefault();
                if (objPicture == null)
                {
                    // No Picture found
                    objPayPalResponse.PayPalError = true;
                    objPayPalResponse.PayPalErrorMessage =
                        string.Format("UserPicturesId {0} not found.", UserPicturesId);
                }
                else
                {
                    // Get the Merchant
                    var objUserProfiles = (from UserProfiles in serverContext.DataWorkspace.ApplicationData
                                               .UserProfiles.GetQuery().Execute()
                                           where UserProfiles.UserName == objPicture.UserName
                                           select UserProfiles).FirstOrDefault();
                    if (objUserProfiles == null)
                    {
                        // No Seller Found
                        objPayPalResponse.PayPalError = true;
                        objPayPalResponse.PayPalErrorMessage =
                            string.Format("UserName {0} does not have a UserProfile record.", objPicture.UserName);
                    }
                    else
                    {
                        // Set SellerUserName
                        SellerUserName = objUserProfiles.UserName;
                        if (objUserProfiles.PayPalEmail.Length < 5)
                        {
                            // Seller does not have a PayPal Email set
                            objPayPalResponse.PayPalError = true;
                            objPayPalResponse.PayPalErrorMessage =
                                string.Format("UserName {0} does not have a PayPal Email set.", objPicture.UserName);
                        }
                        else
                        {
                            // Get values needed to construct PayPal request
                            SellerPayPalEmail = objUserProfiles.PayPalEmail;
                            objPayPalTransaction.payment_status = "Pending";
                            objPayPalTransaction.PayPalError = false;
                            objPayPalTransaction.PayPalRedirectUrl = PayPalRedirectUrl;
                            objPayPalTransaction.PurchaserUserName = Application.Current.User.Name;
                            objPayPalTransaction.SellerPayPalEmail = SellerPayPalEmail;
                            objPayPalTransaction.SellerUserName = objUserProfiles.UserName;
                            // Associate the Picture to the PayPalTransaction
                            objPayPalTransaction.Picture = objPicture;
                            // Save the record so we get a Id to use in the PayPal request
                            serverContext.DataWorkspace.ApplicationData.SaveChanges();
                            // set PayPalPurchaseTransactionId
                            PayPalPurchaseTransactionId = objPayPalTransaction.Id;
                        }
                    }
                }
                // Proceed if no errors
                if (!objPayPalResponse.PayPalError)
                {
                    string currentPath = 
                        System.Web.HttpContext.Current.Request.Url.OriginalString
                        .Replace(@"/PayPal/adaptivepaymentshandler.ashx", "");
                    ReceiverList receiverList = new ReceiverList();
                    receiverList.receiver = new List<Receiver>();
                    string strActionType = "PAY";
                    string currencyCode = "USD";
                    string cancelUrl = string.Format(@"{0}/HTMLClient/?mode=cancel", currentPath);
                    string returnUrl = String.Format(@"{0}/HTMLClient/?mode=return", currentPath);
                    string IpnURL = String.Format(@"{0}/PayPal/IPNListener.aspx", currentPath);
                    Receiver Receiver1 = new Receiver(Decimal.Parse("1.0"));
                    Receiver1.email = SellerPayPalEmail;
                    Receiver1.primary = false;
                    Receiver1.paymentType = "SERVICE";
                    receiverList.receiver.Add(Receiver1);
                    Receiver Receiver2 = new Receiver(Decimal.Parse("1.0"));
                    Receiver2.email = ConfigurationManager.AppSettings["PAYPAL_MERCHANT_EMAIL"];
                    Receiver2.primary = false;
                    Receiver2.paymentType = "SERVICE";
                    receiverList.receiver.Add(Receiver2);
                    PayRequest req = new PayRequest(new RequestEnvelope("en_US"),
                        strActionType,
                        cancelUrl,
                        currencyCode,
                        receiverList,
                        returnUrl);
                    // IPN Url (only enable with a published internet accessable application)
                    req.ipnNotificationUrl = IpnURL;
                    // set optional parameters
                    //(Optional) Whether to reverse parallel payments if an error occurs with a payment. 
                    //Allowable values are:
                    //true – Each parallel payment is reversed if an error occurs
                    //false – Only incomplete payments are reversed (default)
                    req.reverseAllParallelPaymentsOnError = true;
                    //(Optional) A unique ID that you specify to track the payment.
                    //Note: You are responsible for ensuring that the ID is unique.
                    //Maximum length: 127 characters 
                    req.trackingId = PayPalPurchaseTransactionId.ToString();
                    // (Optional) The payer of PayPal fees. Allowable values are:
                    //    SENDER – Sender pays all fees (for personal, implicit simple/parallel payments; 
                    //    do not use for chained or unilateral payments)
                    //    PRIMARYRECEIVER – Primary receiver pays all fees (chained payments only)
                    //    EACHRECEIVER – Each receiver pays their own fee (default, personal and unilateral payments)
                    //    SECONDARYONLY – Secondary receivers pay all fees 
                    //    (use only for chained payments with one secondary receiver)
                    // req.feesPayer = "EACHRECEIVER";
                    // Calll PayPal to get PayKey           
                    AdaptivePaymentsService service = new AdaptivePaymentsService();
                    PayResponse resp = null;
                    try
                    {
                        resp = service.Pay(req);
                    }
                    catch (System.Exception e)
                    {
                        objPayPalResponse.PayPalError = true;
                        objPayPalResponse.PayPalErrorMessage = e.Message;
                        // Write to the database ********
                        objPayPalTransaction.PayPalError = true;
                        objPayPalTransaction.PayPalErrorMessage = e.Message;
                        serverContext.DataWorkspace.ApplicationData.SaveChanges();
                        OutputResponse(context, objPayPalResponse);
                    }
                    // Check for errors
                    if ((resp.responseEnvelope.ack == AckCode.FAILURE) ||
                        (resp.responseEnvelope.ack == AckCode.FAILUREWITHWARNING))
                    {
                        string strError = "";
                        objPayPalResponse.PayPalError = true;
                        foreach (var error in resp.error)
                        {
                            strError = strError + " " + error.message;
                        }
                        objPayPalResponse.PayPalErrorMessage = strError;
                        // Write to the database ********
                        objPayPalTransaction.PayPalError = true;
                        objPayPalTransaction.PayPalErrorMessage = strError;
                        serverContext.DataWorkspace.ApplicationData.SaveChanges();
                    }
                    else
                    {
                        objPayPalResponse.PayPalPaykey = resp.payKey;
                        objPayPalResponse.PayPalPaymentExecStatus = resp.paymentExecStatus;
                        // Write to the database ********
                        objPayPalTransaction.PayPalPaykey = resp.payKey;
                        objPayPalTransaction.PayPalPaymentExecStatus = resp.paymentExecStatus;
                        serverContext.DataWorkspace.ApplicationData.SaveChanges();
                    }
                }
            }
            // Return Response
            OutputResponse(context, objPayPalResponse);
        }
        private static void OutputResponse(HttpContext context, PayPalResponse objPayPalResponse)
        {
            // Create JavaScriptSerializer
            System.Web.Script.Serialization.JavaScriptSerializer jsonSerializer =
                new System.Web.Script.Serialization.JavaScriptSerializer();
            // Output as JSON
            context.Response.Write(jsonSerializer.Serialize(objPayPalResponse));
            return;
        }
    }
}

 

image

When the user clicks the Buy Now button they are taken to PayPal with the PayKey that has all the details of the transaction.

When the payment has been processed the following code listens for the IPN notification (that was set in the Adaptive Payments handler):

 

try
    {
        byte[] parameters = Request.BinaryRead(HttpContext.Current.Request.ContentLength);
        if (parameters.Length > 0)
        {
            IPNMessage ipn = new IPNMessage(parameters);
            bool isIpnValidated = ipn.Validate();
            string transactionType = ipn.TransactionType;
            NameValueCollection map = ipn.IpnMap;
            if (isIpnValidated)
            {
                string connString =
                System.Web.Configuration.WebConfigurationManager
                .ConnectionStrings["_IntrinsicData"].ConnectionString;
                // Connect to the database
                PayPalTransactionsDataContext db = new LinqToSQL.PayPalTransactionsDataContext(connString);
                // Log the PayPal data received
                var objPayPalIpnTransaction = new LinqToSQL.PayPalIpnTransaction();
                string PayPalPayKey = ipn.IpnValue("pay_key"); ;
                string PayPalStatus = ipn.IpnValue("status");
                objPayPalIpnTransaction.transaction_type = ipn.IpnValue("transaction_type");
                objPayPalIpnTransaction.status = ipn.IpnValue("status");
                objPayPalIpnTransaction.sender_email = ipn.IpnValue("sender_email");
                objPayPalIpnTransaction.action_type = ipn.IpnValue("action_type");
                objPayPalIpnTransaction.payment_request_date = ipn.IpnValue("payment_request_date");
                objPayPalIpnTransaction.reverse_all_parallel_payments_on_error = 
                    ipn.IpnValue("reverse_all_parallel_payments_on_error");
                objPayPalIpnTransaction.return_url = ipn.IpnValue("return_url");
                objPayPalIpnTransaction.cancel_url = ipn.IpnValue("cancel_url");
                objPayPalIpnTransaction.ipn_notification_url = ipn.IpnValue("ipn_notification_url");
                objPayPalIpnTransaction.pay_key = ipn.IpnValue("pay_key");
                objPayPalIpnTransaction.memo = ipn.IpnValue("memo");
                objPayPalIpnTransaction.fees_payer = ipn.IpnValue("fees_payer");
                objPayPalIpnTransaction.trackingId = ipn.IpnValue("trackingId");
                objPayPalIpnTransaction.preapproval_key = ipn.IpnValue("preapproval_key");
                objPayPalIpnTransaction.reason_code = ipn.IpnValue("reason_code");
                objPayPalIpnTransaction.currencyCode = ipn.IpnValue("currencyCode");
                objPayPalIpnTransaction.approved = ipn.IpnValue("approved");
                objPayPalIpnTransaction.charset = ipn.IpnValue("charset");
                objPayPalIpnTransaction.transaction_0_id = ipn.IpnValue("transaction[0].id");
                objPayPalIpnTransaction.transaction_0_status = ipn.IpnValue("transaction[0].status");
                objPayPalIpnTransaction.transaction_0_id_for_sender = ipn.IpnValue("transaction[0].id_for_sender");
                objPayPalIpnTransaction.transaction_0_status_for_sender_txn = 
                    ipn.IpnValue("transaction[0].status_for_sender_txn");
                objPayPalIpnTransaction.transaction_0_refund_id = ipn.IpnValue("transaction[0].refund_id");
                objPayPalIpnTransaction.transaction_0_refund_amount = 
                    ipn.IpnValue("transaction[0].refund_amount");
                objPayPalIpnTransaction.transaction_0_refund_account_charged = 
                    ipn.IpnValue("transaction[0].refund_account_charged");
                objPayPalIpnTransaction.transaction_0_receiver = ipn.IpnValue("transaction[0].receiver");
                objPayPalIpnTransaction.transaction_0_invoiceId = ipn.IpnValue("transaction[0].invoiceId");
                objPayPalIpnTransaction.transaction_0_amount = ipn.IpnValue("transaction[0].amount");
                objPayPalIpnTransaction.transaction_0_is_primary_receiver = ipn.IpnValue("transaction[0].is_primary_receiver");
                objPayPalIpnTransaction.transaction_1_id = ipn.IpnValue("transaction[1].id");
                objPayPalIpnTransaction.transaction_1_status = ipn.IpnValue("transaction[1].status");
                objPayPalIpnTransaction.transaction_1_id_for_sender = ipn.IpnValue("transaction[1].id_for_sender");
                objPayPalIpnTransaction.transaction_1_status_for_sender_txn = ipn.IpnValue("transaction[1].status_for_sender_txn");
                objPayPalIpnTransaction.transaction_1_refund_id = ipn.IpnValue("transaction[1].refund_id");
                objPayPalIpnTransaction.transaction_1_refund_amount = ipn.IpnValue("transaction[1].refund_amount");
                objPayPalIpnTransaction.transaction_1_refund_account_charged = ipn.IpnValue("transaction[1].refund_account_charged");
                objPayPalIpnTransaction.transaction_1_receiver = ipn.IpnValue("transaction[1].receiver");
                objPayPalIpnTransaction.transaction_1_invoiceId = ipn.IpnValue("transaction[1].invoiceId");
                objPayPalIpnTransaction.transaction_1_amount = ipn.IpnValue("transaction[1].amount");
                objPayPalIpnTransaction.transaction_1_is_primary_receiver = ipn.IpnValue("transaction[1].is_primary_receiver");
                // Save the record
                db.PayPalIpnTransactions.InsertOnSubmit(objPayPalIpnTransaction);
                db.SubmitChanges();
                // Only do the following if the status is COMPLETED
                if (PayPalStatus == "COMPLETED")
                {
                    // Start a Transaction log record
                    var objPayPalTransaction = new LinqToSQL.PayPalTransaction();
                    // Search for related PayPalPurchaseTransaction
                    var result = (from PayPalPurchaseTransactions in db.PayPalPurchaseTransactions
                                    where PayPalPurchaseTransactions.PayPalPaykey == PayPalPayKey
                                    select PayPalPurchaseTransactions).FirstOrDefault();
                    if (result != null)
                    {
                        // Update PayPalPurchaseTransaction
                        result.payment_status = "COMPLETED";
                        // Make a log entry                                
                        objPayPalTransaction.LogDateTime = DateTime.Now;
                        objPayPalTransaction.pay_key = PayPalPayKey;
                        objPayPalTransaction.LogData = String.Format(
                            "IPN Received for pay_key: {0} - Updated payment to COMPLETED", PayPalPayKey);
                    }
                    else
                    {
                        // Make a log entry                                
                        objPayPalTransaction.LogDateTime = DateTime.Now;
                        objPayPalTransaction.pay_key = PayPalPayKey;
                        objPayPalTransaction.LogData = String.Format(
                            "IPN Received for pay_key: {0} - Associated payment not found!", PayPalPayKey);
                    }
                    // Save the record
                    db.PayPalTransactions.InsertOnSubmit(objPayPalTransaction);
                    db.SubmitChanges();
                }
            }
        }
    }
    catch (System.Exception ex)
    {
        string connString =
            System.Web.Configuration.WebConfigurationManager
            .ConnectionStrings["_IntrinsicData"].ConnectionString;
        // Connect to the database
        PayPalTransactionsDataContext db = new LinqToSQL.PayPalTransactionsDataContext(connString);
        // Start a Transaction log record
        var objPayPalTransaction = new LinqToSQL.PayPalTransaction();
        // Make a log entry                                
        objPayPalTransaction.LogDateTime = DateTime.Now;
        objPayPalTransaction.pay_key = "";
        objPayPalTransaction.LogData = String.Format(
            "Error in {0} : {1}", this.GetType().Name, ex.Message);
        // Save the record
        db.PayPalTransactions.InsertOnSubmit(objPayPalTransaction);
        db.SubmitChanges();
        return;
    }

 

Linq to Sql is used because the call from PayPal is unauthenticated and the LightSwitch application is running under forms authentication. Entity Framework or ADO .Net could have also been used.

 

Download Code

The LightSwitch project is available at http://lightswitchhelpwebsite.com/Downloads.aspx

(you must have Visual Studio 2012 (or higher) installed to run the code)

2 comment(s) so far...


Gravatar

Re: Integrating PayPal With Visual Studio LightSwitch

Dear Michael,

Hi this is Cliff again, the one discussed the ASP.NET self-register issues last time. This time I would like to ask you a question.

With regard to API credentials, I have found that I was successful in using adaptive payment within the sandbox account, and as per mentioned in your article the redirect url for the button returning from PayPal is "https://www.sandbox.paypal.com/webscr?cmd=_ap-payment&paykey=". However, how can I get into the live one? I have searched the PayPal website but could not find the redirect url from live. When I remove the "sandbox" word from the above url I was redirected to other one's payment.

If possible would you please post up your live code (without the web.config) for download, I feel really frustrated about the lack of such an important piece of information from PayPal.

Cliff

By Cliff Lo on   1/17/2014 12:48 AM
Gravatar

Re: Integrating PayPal With Visual Studio LightSwitch

@Cliff Lo - The setting I am using in the web.config is: key="PAYPAL_REDIRECT_URL" value="https://www.paypal.com/webscr&cmd="

By Michael Washington on   1/17/2014 9:04 AM

Your name:
Gravatar Preview
Your email:
(Optional) Email used only to show Gravatar.
Your website:
Title:
Comment:
Security Code
CAPTCHA image
Enter the code shown above in the box below
Add Comment   Cancel 

Microsoft Visual Studio is a registered trademark of Microsoft Corporation / LightSwitch is a registered trademark of Microsoft Corporation