Vaadin and Paypal (or other payment gateways!)

Hi,
I have added to my application billing in order to have users purchase subscriptions based on their needs, however, now the only way of payment is through bank transfer.
Has anyone successfully created a paypal integration so that when the user presses the “Buy” button he automatically is redirected to the Paypal page with all the fields filled in (such as price etc)…

Hi Nick,

the details of such integration are not that much related to Vaadin framework. You should look into instructions provided by PayPal and create a proper URL to forward the user for payment. When you have such a URL created, you can easily redirect the user by calling Page.setLocation() method in your Vaadin application.

https://vaadin.com/api/7.4.4/com/vaadin/server/Page.html#setLocation(java.lang.String)

Often these kind of payment gateways redirect the user to a “success URL” after the payment. This might be easiest to implement as a simple Servlet and there just store the payment details into a database before forwarding back to your Vaadin application.

True, I just thought that someone has successfully created a plugin of some sort or has some code to guide me.

Anyhow, long story short, the way I’ve implemented it is to use the Page.setLocation, redirect to paypal, have the paypal get back to Vaadin requesting a specific view. I am using a ViewChangeListener in my main application, so capturing the class of the specificView requested was fairly easy and then I checkd the event.getNewView().getParameters() to see whether the have paypal tokens etc inside or not.
Note that my application is PreserveOnRefresh so it works out of the box without an external Servlet. Also you need to have a database table that holds the Token and other information, in order to execute the final payment to paypal.

A ‘rough’ code is listed below for anyone who might need it in the future:

Note that I’ve used the code from http://paypal-nvp.sourceforge.net/index.htm in order to make my life easier in dissasembling and assembling the paypal request/responses (The proxy server is not needed,I had to implement proxy support though you can remove it). I also have configuration file for most parameters, the application doesn’t logout the user unless requested or timeout.

Request:

LogManager.debug(logger, "Starting the Paypal Transaction");
        
        Profile user = new BaseProfile.Builder(
InitialApplicationSettingsLoader.paypal_username,
                InitialApplicationSettingsLoader.paypal_password).signature(
                        InitialApplicationSettingsLoader.paypal_signature).build();
        
        PayPal pp = new PayPal(user, Environment.SANDBOX);
        
        PaymentItem item1 = new PaymentItem();
        
        item1.setAmount(moneyFormat.format(subscription.getSubscriptionPrice() + transactionFees));
        item1.setName(subscription.getSubscriptionName());
        item1.setDescription(logged_user.getUsername());
        
        PaymentItem[] items  = {item1};
        
        Payment payment = new Payment(items);
        payment.setCurrency(Currency.EUR);
        payment.setNote(logged_user.getUsername());
        
        SetExpressCheckout setEC = new SetExpressCheckout(payment,
                "http://localhost:8080/application/#!/user-subscriptions/PAYPALCANCEL/",
                "http://localhost:8080/application/#!/user-subscriptions/PAYPALSUCCESS/");

        setEC.setNoShipping(true);
        
        LogManager.debug(logger, "Trying to send request:" + setEC.toString());
        
        Proxy proxy = null;
        if(InitialApplicationSettingsLoader.application_proxy_server.length() >0){
            try{
                proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(InitialApplicationSettingsLoader.application_proxy_server,
                                                                         InitialApplicationSettingsLoader.application_proxy_port));    
            }catch(Exception e){
                LogManager.error(logger, "Proxy could not be setup", e);
            }
        }
        
        pp.setResponse(setEC,proxy);
        
        Map<String, String> response = setEC.getNVPResponse();
        
        LogManager.debug(logger, "Received Paypal Reply:" + response.toString());
        
        String token = "";
        boolean success = false;
        
        for (Map.Entry<String, String> entry : response.entrySet())
        {
            if(entry.getKey().equalsIgnoreCase("ACK")){
                if(entry.getValue().equalsIgnoreCase("Success")){
                    success = true;
                }
            }else if (entry.getKey().equalsIgnoreCase("TOKEN")){
                token = entry.getValue();
            }
        }
        
        if(success){
            //Save the token and the order..
            try {
                DatabaseHelperPaypalPayments.insertNewOrder(.logged_user.getID(),
                                                            (int)subscription.getSubscriptionID(),
                                                            subscription.getSubscriptionName(),
                                                            subscription.getSubscriptionPrice()+ transactionFees,
                                                            token);
            } catch (Throwable e) {
                Notification.show("ERROR", "Error in inserting order to database. Contact administrator", Notification.Type.ERROR_MESSAGE);
                LogManager.error(logger, "Error in adding to database", e);
                return;
            }
        }else{
            Notification.show("ERROR", "There was an error in the Paypal Request. Administrators will be notified", Notification.Type.ERROR_MESSAGE);
            return;
        }
        InsurancemanagerUI.getCurrent().getUI().getPage().setLocation("https://www.sandbox.paypal.com/cgi-bin/webscr?cmd=_express-checkout&token=" + token);

After Paypal finishes with the request we have to identify for whom the request is from and do all the stuff (like give subscription etc)…

 nav.addViewChangeListener(new ViewChangeListener() {

                @Override
                public boolean beforeViewChange(ViewChangeEvent event) {
                    
                    if(logged_user != null){
                        
                        //Block the pages for User Role.
                        boolean valid_page = false;
                        if(event.getNewView() == null){
                            valid_page = false;
                        }else{
                            //Check if paypal returned anything
                            if(event.getNewView().getClass().equals(UserSubscriptionsManagementView.class)){
                                //Check to see if the parameters are ok
                                if(event.getParameters().length() > 0){
                                    LogManager.info(logger, "Processing request, probably from PAYPAL");
                                    
                                    if (event.getParameters().contains("PAYPALCANCEL")){
                                        //We need to delete the token request and produce and error message
                                        String response = event.getParameters().substring(event.getParameters().indexOf('?')+1);
                                        
                                        Map<String, String> responseMap = new HashMap<String, String>();
                                        
                                        try{
                                            String[] pairs = response.split("&");
                                            for(String pair: pairs){
                                                String[] nvp = pair.split("=");
                                                responseMap.put(nvp[0]
, URLDecoder.decode(nvp[1]
, "UTF-8"));
                                                LogManager.debug(logger, "KEY:" + nvp[0]
 + " VALUE:" + URLDecoder.decode(nvp[1]
, "UTF-8"));
                                            }
                                        }catch (UnsupportedEncodingException ex) {
                                            LogManager.error(logger, "Error receiving response from Paypal.Wrong Encoding", ex);
                                        }
                                        
                                        try {
                                            DatabaseHelperPaypalPayments.deleteOpenPaypalPaymentForToken(responseMap.get("token"));
                                        } catch (Throwable e) {
                                            LogManager.error(logger, "Could not delete open PaypalPayment", e);
                                        }
                                    }else if (event.getParameters().contains("PAYPALSUCCESS")){
                                        //We need to process this request.
                                        LogManager.info(logger, "Processing confirmed request from PAYPAL");
                                        
                                        String response = event.getParameters().substring(event.getParameters().indexOf('?')+1);
                                        LogManager.debug(logger, "Paypal Response:" + response);
                                        
                                        Map<String, String> responseMap = new HashMap<String, String>();
                                        
                                        try{
                                            String[] pairs = response.split("&");
                                            for(String pair: pairs){
                                                String[] nvp = pair.split("=");
                                                responseMap.put(nvp[0]
, URLDecoder.decode(nvp[1]
, "UTF-8"));
                                                LogManager.debug(logger, "KEY:" + nvp[0]
 + " VALUE:" + URLDecoder.decode(nvp[1]
, "UTF-8"));
                                            }
                                        }catch (UnsupportedEncodingException ex) {
                                            LogManager.error(logger, "Error receiving response from Paypal.Wrong Encoding", ex);
                                        }
                                        
                                        //Create a paypal transaction in order to verify this action...
                                        PaypalPaymentObject pobj = null;
                                        try {
                                            pobj = DatabaseHelperPaypalPayments.getOpenPaypalPaymentForToken(responseMap.get("token"));
                                        } catch (Throwable e1) {
                                            LogManager.error(logger, "Could not retrieve Open Paypal Payment", e1);
                                            e1.printStackTrace();
                                        }
                                        
                                        if (pobj == null){
                                            LogManager.error(logger, "The Paypal order was not found");
                                        }else{
                                            Profile user = new BaseProfile.Builder(
                                                    InitialApplicationSettingsLoader.paypal_username,
                                                    InitialApplicationSettingsLoader.paypal_password).signature(
                                                        InitialApplicationSettingsLoader.paypal_signature).build();
                                
                                            PayPal pp = new PayPal(user, Environment.SANDBOX);
                                            
                                            PaymentItem item1 = new PaymentItem();
                                            DecimalFormat df = new DecimalFormat("#.00");
                                            
                                            item1.setAmount(df.format(pobj.getSubscriptionPrice()));
                                            item1.setName(pobj.getSubscriptionName());
                                            
                                            PaymentItem[] items  = {item1};
                                            
                                            Payment payment = new Payment(items);
                                            payment.setCurrency(Currency.EUR);
                                            payment.setNote(InsurancemanagerUI.getCurrent().logged_user.getUsername());
                                            
                                            DoExpressCheckoutPayment setDEC = new DoExpressCheckoutPayment(payment,
                                                                                                            responseMap.get("token"),
                                                                                                            PaymentAction.SALE,
                                                                                                            responseMap.get("PayerID"));
                                            
                                            LogManager.debug(logger, "Paypal PAYMENT To Send:" + setDEC.toString());
                                            Proxy proxy = null;
                                            if(InitialApplicationSettingsLoader.application_proxy_server.length() >0){
                                                try{
                                                    proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(InitialApplicationSettingsLoader.application_proxy_server,
                                                                                                             InitialApplicationSettingsLoader.application_proxy_port));    
                                                }catch(Exception e){
                                                    LogManager.debug(logger, "Proxy could not be setup:", e);
                                                }
                                            }
                                            pp.setResponse(setDEC,proxy);
                                            
                                            Map<String, String> responseLast = setDEC.getNVPResponse();
                                            LogManager.debug(logger, "Paypal Response for Charge:" + responseLast.toString());
                                            
                                            if(responseLast.containsKey("PAYMENTSTATUS")){
                                                if(responseLast.get("PAYMENTSTATUS").equalsIgnoreCase("Completed") ||
                                                        responseLast.get("PAYMENTSTATUS").equalsIgnoreCase("Pending")){
                                                    //The payment was completed, add the subscription to the user.
                                                    BillingHandler.assignSubscriptionToUser(logged_user.getID(), pobj.getSubscriptionid(), "PAYPAL");
                                                }else{
                                                    LogManager.debug(logger, "Payment Status is :" + responseLast.get("PAYMENTSTATUS") + " so REMOVING the purchase");
                                                    try {
                                                        DatabaseHelperPaypalPayments.deleteOpenPaypalPaymentForToken(responseMap.get("token"));
                                                    } catch (Throwable e) {
                                                        LogManager.error(logger, "Could not delete open PaypalPayment", e);
                                                    }    
                                                }
                                            }else{
                                                LogManager.debug(logger, "Response doesn't include PAYMENTSTATUS. Remove the transaction");
                                                try {
                                                    DatabaseHelperPaypalPayments.deleteOpenPaypalPaymentForToken(responseMap.get("token"));
                                                } catch (Throwable e) {
                                                    LogManager.error(logger, "Could not delete open PaypalPayment", e);
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                        
                    }
                    return true;
                }

                @Override
                public void afterViewChange(ViewChangeEvent event) {
                }
            });

Have fun! :slight_smile:

Nick, thank you!! This is extremely helpful even 4 years later.

Is this code still reliable today with PayPal? I’m just starting my payment journey with Vaadin.

Glad I could help!
I have no idea really, since at this project no-one really used the Paypal integration but I don’t think there will be significant differences since Paypal and other ‘big’ companies don’t like to change their API all the time so my guess is that it will work just fine.
Don’t forget that you can always create a dummy-paypal account at the Paypal Sandbox and test all the features there before going live!

I’ll definitely use the Sandbox, thanks for your detailed support. Cheers

You can also check these different payment gateways for ecommerce. https://payment-gateways.net/

For Teemu Pöntelin to say that the integration of payment gateways doesn’t have anything to do with Vaadin is to completely ignore how Vaadin differs from other UI frameworks. Every payment gateway that I’ve looked at requires the developer to embed their components in the UI. The Vaddin framework is designed such that the UI is composed entirely of Vaadin components that are Java based. PayPal, like most other payment gateways, gives you the HTML to embed a PayPal button in your UI. The only reason to use Vaadin is so that the UI can be written in Java instead of HTML and JavaScript.