Coupon Code For Paypal Express Checkout - paypal

I'm using Paypal Express Checkout system on my website. But I want to put a coupon (discount) code area. It will make a reduction if code is true. (Like GoDaddy.com's cart system)
Have you any idea, where should I start for this?
(I'm not using any eCommerce framework)

I know this is an old thread but wanted to put here my experience for others looking for the same thing, and maybe this did not apply then but it does apply now, at least on the sandbox meaning I have not tested this in a real transaction
When adding items that you send to paypal you basically send this
L_PAYMENTREQUEST_0_QTY0 = 1
L_PAYMENTREQUEST_0_AMT0 = 1.00
L_PAYMENTREQUEST_0_NAME0 = my item 0 name
L_PAYMENTREQUEST_0_NUMBER0 = myitem0id
Then we add another item
L_PAYMENTREQUEST_0_QTY1 = 1
L_PAYMENTREQUEST_0_AMT1 = 1.00
L_PAYMENTREQUEST_0_NAME1 = my item 1 name
L_PAYMENTREQUEST_0_NUMBER1 = myitem1id
And now we add the coupon
L_PAYMENTREQUEST_0_QTY2 = 1
L_PAYMENTREQUEST_0_AMT2 = -0.50
L_PAYMENTREQUEST_0_NAME2 = my coupon name
L_PAYMENTREQUEST_0_NUMBER2 = mycouponcode
And then we add the subtotal and total values
PAYMENTREQUEST_0_AMT = 1.50
AMT = 1.50
What I think paypal does is ads up all item totals so it would do for this order something like
1.00+1.00-0.50 = 1.50
Then compares it to your total amounts
if they match then it is a go, the customer sees this as an extra item, but obviously with the minus sign, this picture below is from a paypal sandbox express checkout transaction

One approach is to have a shopping cart on your site where the user can enter a promo code. Once they've entered their promo codes, and are ready to begin the checkout process, this is when you redirect them to the Express Checkout (where you send Paypal the final amount of your order, etc).
According to this post on Paypal forum, they do not have a feature to pass the discount details to the checkout process: https://www.x.com/thread/39681 ("With express checkout all discount calculations will need to be done on your site.")
How to calculate before sending price to paypal
1) Add a SEPARATE form for the promo code to your page:
<form method="GET">
<input type="text" name="promocode">
<input type="submit" value="Add Promo">
</form>
2) On the server side, check the code, update the page accordingly with new prices (e.g. re-build your select menu with new prices). Example with PHP:
<?
if(isset($_GET('promocode')) {
$prices = processPromo($_GET('promocode'));
}
else {
$prices = array(2000, 4000, 6000);
}
?>
If you don't have access to the server, you would have to do this with JavaScript I guess (i.e. have your promo-code and price hard-coded into the page)
To initiate express checkout on server side
Download PHP NVP SDK & examples from Paypal's website:
https://cms.paypal.com/us/cgi-bin/?cmd=_render-content&content_ID=developer/library_download_sdks
<?php
require_once 'CallerService.php';
session_start();
ini_set('session.bug_compat_42',0);
ini_set('session.bug_compat_warn',0);
/* Gather the information to make the final call to
finalize the PayPal payment. The variable nvpstr
holds the name value pairs
*/
$token =urlencode( $_SESSION['token']);
$paymentAmount =urlencode ($_SESSION['TotalAmount']);
$paymentType = urlencode($_SESSION['paymentType']);
$currCodeType = urlencode($_SESSION['currCodeType']);
$payerID = urlencode($_SESSION['payer_id']);
$serverName = urlencode($_SERVER['SERVER_NAME']);
$nvpstr='&TOKEN='.$token.'&PAYERID='.$payerID.'&PAYMENTACTION='.$paymentType.'&AMT='.$paymentAmount.'&CURRENCYCODE='.$currCodeType.'&IPADDRESS='.$serverName ;
/* Make the call to PayPal to finalize payment
If an error occured, show the resulting errors
*/
$resArray=hash_call("DoExpressCheckoutPayment",$nvpstr);
/* Display the API response back to the browser.
If the response from PayPal was a success, display the response parameters'
If the response was an error, display the errors received using APIError.php.
*/
$ack = strtoupper($resArray["ACK"]);
if($ack != 'SUCCESS' && $ack != 'SUCCESSWITHWARNING'){
$_SESSION['reshash']=$resArray;
$location = "APIError.php";
header("Location: $location");
}
?>

Related

how to calculate tax using paypal api

i installed the .net sdk of paypal and created an app in sandbox environment
next i picked up the clientId and secret and used the following sample code to make a payment.
static void Main(string[] args)
{
// Get a reference to the config
var config = ConfigManager.Instance.GetProperties();
// Use OAuthTokenCredential to request an access token from PayPal
var accessToken = new OAuthTokenCredential(config["clientId"], config["clientSecret"]);
var apiContext = new APIContext(accessToken.GetAccessToken());
var payment = Payment.Create(apiContext, new Payment
{
intent = "sale",
payer = new Payer
{
payment_method = "paypal"
},
transactions = new List<Transaction>
{
new Transaction
{
description = "Test",
invoice_number = "009",
amount = new Amount
{
currency = "EUR",
total = "41.00",
details = new Details
{
tax = "0",
shipping = "0",
subtotal = "40",
handling_fee = "1"
}
},
item_list = new ItemList
{
items = new List<Item>
{
new Item
{
name = "Room 12",
currency = "EUR",
price = "10",
quantity = "4",
}
}
}
}
},
redirect_urls = new RedirectUrls
{
return_url = "https://google.de/",
cancel_url = "https://google.de/"
}
});
}
in the transaction i have to pass Tax information.
Is there was that i let paypal calculate the tax and i just pass amount information along with address and some other information if required ?
No, you must calculate the tax yourself.
By default the user will be able to select their shipping address at PayPal, which is recommended as this saves them from having to type it manually. Given that their address can change during the PayPal checkout, you may wish to calculate a new tax amount and/or shipping amount based on the selected address. You can do this using the JS SDK's onShippingChange callback.
Firstly, though, it appears you may be using a deprecated SDK and deprecated v1/payments API, and also a redirect away from your site to PayPal, all of which is old. Don't do any of this.
Instead: follow the PayPal Checkout integration guide and make 2 routes on your server, one for 'Create Order' and one for 'Capture Order' (see the optional step 5 in 'Add and modify the code'). Both of these routes should return only JSON data (no HTML or text). There is a Checkout-Java-SDK you can use, or integrate with your own direct HTTPS API calls (obtain an access_token first, it can be cached but expires in 9 hours).
Inside the 2nd capture route on your server, when the capture API call is successful you should store its resulting payment details in your database (particularly purchase_units[0].payments.captures[0].id, which is the PayPal transaction ID) and perform any necessary business logic (such as sending confirmation emails or reserving product) immediately before forwarding your return JSON to the frontend caller.
Pair those 2 routes with the frontend approval flow: https://developer.paypal.com/demo/checkout/#/pattern/server

Paypal - Recurring payments with checkout.js

Is it possible to trigger recurring payments (subscriptions / billing agreements) using checkout.js?
If so, can you please provide a working example?
Yes its possible. I just created a POC for this.
Create a BillingPlan and activate it
plan = Plan.new(PlanAttributes)
plan.create
patch = Patch.new
patch.op = "replace"
patch.path = "/";
patch.value = { :state => "ACTIVE" }
plan.update( patch )
inside the payment function of paypal.Button call your server to create a BillingAgreement. The user will then authorize the payment.
agreement = Agreement.new(agreement_attributes)
agreement.plan = Plan.new( :id => "<the_plan_id>" )
agreement.create
inside the onAuthorize function of paypal.Button call your server to execute the BillingAgreement
agreement.execute
Following the example in
Checkout https://github.com/chibeepatag/paypal_poc

PayPal Merchant SDK GetExpressCheckoutDetailsResponseDetails not returning buyer's email or phone number

I'm using the PayPal Merchant SDK for .NET (v 2.15.117) and am trying to retrieve the shipping address info, customer's email address, and phone number from the GetExpressCheckoutDetailsRequestType.GetExpressCheckoutDetailsResponseDetails call. The shipping address is populated as expected but for the life of me, I can't figure out how to get the buyer's email or phone number. At a minimum we have to have the email to communicate about the order (ie tracking emails).
I see a BuyerMarketingEmail property but it is null and I am under the impression that is an optional email the buyer can choose to provide. For phone, I see a PayerInfo.ContactPhone property but that is also null (and I'm less concerned about having that but it would be nice for customer service issues or to give to ground shippers like FedEx).
I am using the PayPal sandbox if that matters.
What am I missing?
var getExpressCheckoutDetails = new GetExpressCheckoutDetailsReq();
var getExpressCheckoutDetailsRequest = new GetExpressCheckoutDetailsRequestType(token);
getExpressCheckoutDetails.GetExpressCheckoutDetailsRequest = getExpressCheckoutDetailsRequest;
var service = new PayPalAPIInterfaceServiceService();
paypalResponse = service.GetExpressCheckoutDetails(getExpressCheckoutDetails);
if (paypalResponse != null)
{
//Success values check for a matching PayerID to validate the token response
if (paypalResponse.Ack.ToString().Trim().ToUpper().Equals("SUCCESS") &&
PayerID == paypalResponse.GetExpressCheckoutDetailsResponseDetails.PayerInfo.PayerID)
{
checkout.ShippingInfo.ShippingName = paypalResponse.GetExpressCheckoutDetailsResponseDetails.PayerInfo.Address.Name;
checkout.ShippingInfo.ShippingAddress1 = paypalResponse.GetExpressCheckoutDetailsResponseDetails.PayerInfo.Address.Street1;
checkout.ShippingInfo.ShippingAddress2 = paypalResponse.GetExpressCheckoutDetailsResponseDetails.PayerInfo.Address.Street2;
checkout.ShippingInfo.ShippingCity = paypalResponse.GetExpressCheckoutDetailsResponseDetails.PayerInfo.Address.CityName;
checkout.ShippingInfo.ShippingState = paypalResponse.GetExpressCheckoutDetailsResponseDetails.PayerInfo.Address.StateOrProvince;
checkout.ShippingInfo.ShippingZip = paypalResponse.GetExpressCheckoutDetailsResponseDetails.PayerInfo.Address.PostalCode;
checkout.ShippingInfo.ShippingCountry = paypalResponse.GetExpressCheckoutDetailsResponseDetails.PayerInfo.Address.Country.ToString();
//these next two are always null
checkout.BillingInfo.Email = paypalResponse.GetExpressCheckoutDetailsResponseDetails.BuyerMarketingEmail;
checkout.ShippingInfo.PhoneNumber = paypalResponse.GetExpressCheckoutDetailsResponseDetails.PayerInfo.ContactPhone;
}
}
Thought I'd post an answer to wrap this up -
As stated above in my comment to the original question, the email address of the buyer is PayerInfo.Payer.
Also, suddenly/magically, PayerInfo.ContactPhone began returning the phone number instead of null. I can only chalk that up to something in the Sandbox environment or my sandbox user account.

Error 500 when calling payment creation via REST API

I trying the new Paypal REST API and want integrate it in sandbox mode into a simple site just to see is it possible to implement one of the following payment flows:
Flow1
1) user fills the payment form, including credit card information
2) user clicks Buy
3) browser stores credit card information in paypal vault via REST API for credit cards (card id used later).
4) browser creates payment for the purchase via REST API call.
5) browser calls app server to ensure that purchase is going on.
5) browser redirects user to url provided by paypal.
6) when user consent/approval received at paypal website, and site redirected back to welcome page,
7) under the hood the IPN callback receives the conformation of payment and marks purchase as paid
8) user obtains access to the service app provides
Flow 2
1) user fills the payment form, including credit card information
2) user clicks Buy
4) browser creates payment for the purchase via REST API call.
5) browser calls app server to ensure that purchase is going on.
5) browser redirects user to url provided by paypal.
6) when user consent/approval received at paypal website, and site redirected back to welcome page,
7) under the hood the IPN callback receives the conformation of payment and marks purchase as paid and uses a bit more pf purchase details like credit card type and last 4 digits to add this info to my purchase object.
8) user obtains the access to services the application provides
8) user obtains access to the service app provides
Reasons to implement all this in such way
Mostly I going this path because i don't want deal with all this PCI compliance, and hones;ty i don't care where customers of my app live, which exactly card numbers they used, or when the card expire, since i don't want use automated subscription like payment, i want use different model:
user gets some pats of service for free, but to use rest of service, user buys time intervals of improved access (e. g. X months or 1 year).
This is what i trying to implement without storing credit cards information or storing as less as possible (paypal credit card id is enough i guess).
Question
Can i implement all this with Paypal REST API?
What i trying to do:
PaypalAdapter.prototype.sendCreditCardPayment = function (amount, description, creditCard, success, failure) {
var ccNumberResult = this.impl.validator.validateCardNumber(creditCard.number);
if (!ccNumberResult.success) {
return this.impl.$q.reject(ccNumberResult);
}
var cardInfo = {
number: ccNumberResult.number,
type: ccNumberResult.type,
expire_month: creditCard.expireMonth,
expire_year: String(creditCard.expireYear),
cvv2: creditCard.securityCode,
first_name: creditCard.firstName,
last_name: creditCard.lastName
};
var self = this;
var defer = self.impl.$q.defer();
this.impl.storeCardAPI(cardInfo,
function cardTokenCreated(cardTokenReply) {
var paymentSettings = {
intent: self.PaymentIntents.Sale,
redirect_urls: {
return_url: self.urls.returnUrl,
cancel_url: self.urls.cancelUrl
},
payer: {
payment_method: self.PayMethods.CreditCard,
funding_instruments: [
{
credit_card_token: {
credit_card_id: cardTokenReply.id
}
}
]
},
transactions: [
{
amount: {
total: String(amount.toFixed(2)),
currency: self.currencyCode
},
description: description
}
]
};
self.impl.createPaymentAPI(paymentSettings, function paymentCreated(payment) {
defer.resolve(payment);
}, function failedToCreatePayment(pcErr) {
defer.reject(pcErr);
});
},
function failedToStoreCard(ctErr) {
defer.reject(ctErr);
});
return defer.promise.then(success, failure);
};
To keep context more clean, here some more pieces of code:
var defaultHeaders = {
Authorization: 'Bearer ' + securityContext.tokens.paypal.access_token,
Accept: 'application/json'
};
var createPaymentResource = $resource(securityContext.configuration.paypal.endPoint + 'payments/payment', {}, {
sendPayment : {
method:'POST',
headers: defaultHeaders
}
});
var saveCreditCardResource = $resource(securityContext.configuration.paypal.endPoint + "vault/credit-cards", {}, {
storeCreditCard: {
method: 'POST',
headers: defaultHeaders
}
});
function storeCardFunc(cardInfo, success, failure) {
return saveCreditCardResource.storeCreditCard(null, cardInfo, success, failure);
}
function createPaymentFunc(paymentInformation, success, failure) {
return createPaymentResource.sendPayment(null, paymentInformation, success, failure);
}
var adapter = new PaypalAdapter($q, securityContext, creditCardValidator, storeCardFunc, createPaymentFunc);
return adapter;
Current "Results"
What i getting:
1) I can store credit card into vault via REST API.
2) i getting error 500 on try to create payment whether i use plain credit card properties to fill credit card funding instrument or try to use credit card token instead.
What i'm doing wrong?
Update
My mistake is a sort of logical with a lack of knowledge.
1) The direct credit cards payments (weather user approves them manually (with intent 'order' and payment_method = 'credit_card'), or not ('sale' intent and payment method 'credit_card') are not available for my country (Republic of Georgia). This is a single reason for the error i see.
Discovered this via Paypal account pages at developer.paypal.com website... It is a frustrating thing. Especially with all this too cryptic "internal server error". I t would be VERY helpful if Paypal would provide at least an informative message "Requested feature not available for your account" with info link to that page with available/enabled features.
Also documentation s a bit broken - some fields like first_name or last_name of payer object of order/payment request are NOT expected by the /payments/payment endpoint...

delayed chained payment

Can anyone tell me how to automatically execute a delayed payment (let's say it's 5 days after the primary receiver receive the payment) in a chained payment manner? The key is automatic execution, not having to manually approve and pay the secondary receiver. Please illuminate with some sample code.
I have used "actionType" => "PAY_PRIMARY" so that primary receiver get money.
But how can I code so that secondary receiver get money?
Check this answer for the solution. Basically you just need to execute an ExecutePayment operation with the payKey within 90 days to send the payment to the secondary party.
actionType is PAY_PPRIMARY
you then trigger this payment within 90 days.
Its delayed but not time-elapsed.
https://cms.paypal.com/cms_content/US/en_US/files/developer/PP_AdaptivePayments.pdf
well may be its too late but it will help someone in future for sure.
As we integrated paypal delayed chained payment, you can set a primary account in which all the amount will go and you can also set secondary account in which account will be transfered once they approved by primary account holder.
string endpoint = Constants_Common.endpoint + "Pay";
NVPHelper NVPRequest = new NVPHelper();
NVPRequest[SampleNVPConstant.requestEnvelopeerrorLanguage] = "en_US";
//NVPRequest[SampleNVPConstant.Pay2.actionType] = "PAY";
//the above one is for simple adoptive payment payment
NVPRequest[SampleNVPConstant.Pay2.actionType] = "PAY_PRIMARY";
//the above one for deleayed chained payment
NVPRequest[SampleNVPConstant.Pay2.currencyCode] = "USD";
NVPRequest[SampleNVPConstant.Pay2.feesPayer] = "EACHRECEIVER";
NVPRequest[SampleNVPConstant.Pay2.memo] = "XXXXXXXX";
Now we have to set primary and secondary receivers:
//primary account
NVPRequest[SampleNVPConstant.Pay2.receiverListreceiveramount_0] = TotalAmount;
NVPRequest[SampleNVPConstant.Pay2.receiverListreceiveremail_0] = "XXXx.xxxxx.com";
NVPRequest[SampleNVPConstant.Pay2.receiverListreceiverprimary_0] = "true";
//secondary accounts
NVPRequest[SampleNVPConstant.Pay2.receiverListreceiveramount_1] = (somemoney out of total amount);
NVPRequest[SampleNVPConstant.Pay2.receiverListreceiveremail_1] = "xxxxx.xxxx.com";
NVPRequest[SampleNVPConstant.Pay2.receiverListreceiverprimary_1] = "false";
NVPRequest[SampleNVPConstant.Pay2.receiverListreceiveramount_2] = (somemoney out of total amount);
NVPRequest[SampleNVPConstant.Pay2.receiverListreceiveremail_2] = x.x.com;
NVPRequest[SampleNVPConstant.Pay2.receiverListreceiverprimary_2] = "false";
Don't forget that you have to give a valid paypal account while using delayed chained payment.
Now you get your pay_key which you have to use to execute your payment whithin 90 days so that other secondary receivers get money.
Here is the working code:
String endpoint = Constants_Common.endpoint + "ExecutePayment";
NVPHelper NVPRequest = new NVPHelper();
//requestEnvelope.errorLanguage is common for all the request
NVPRequest[SampleNVPConstant.requestEnvelopeerrorLanguage] = "en_US";
NVPRequest[SampleNVPConstant.ExecutePayment.payKey] = "your pay key";
string strrequestforNvp = NVPRequest.Encode();
//calling Call method where actuall API call is made, NVP string, header value adne end point are passed as the input.
CallerServices_NVP CallerServices = new CallerServices_NVP();
string stresponsenvp = CallerServices.Call(strrequestforNvp, Constants_Common.headers(), endpoint);
//Response is send to Decoder method where it is decoded to readable hash table
NVPHelper decoder = new NVPHelper();
decoder.Decode(stresponsenvp);
if (decoder != null && decoder["responseEnvelope.ack"].Equals("Success") && decoder["paymentExecStatus"].Equals("COMPLETED"))
{
//do something
}
Hope it will help someone.