F3-PYPL: PayPal Express Checkout plugin

332 views
Skip to first unread message

Tim

unread,
Aug 4, 2016, 11:14:06 AM8/4/16
to f3-fra...@googlegroups.com
I've been working away on an Express Checkout plugin for F3 for a while now and its finally at a mature enough stage where I felt I could share with the community.
My original goal was to create a plugin that would allow you to complete a transaction via the API using two methods & some simple routing (see quick start guide) and also had enough features to create a full Express Checkout Shortcut or PayPal Mark integration (both are also documented in great detail).

Demo
https://timoleary.net/f3pypl

Github
https://github.com/kreative/F3-PYPL

Hopefully someone will find it useful, feedback would be greatly appreciated!

Ricardo Andrade

unread,
Aug 12, 2016, 8:23:21 AM8/12/16
to Fat-Free Framework
Hi Tim,

Appear to be a good plugin! I managed to do an integration with subscriptions mode using the code examples from Paypal and I remember to think how good could be have a plugin for it. :)

I am not sure, but is not possible to use for subscriptions for now, right?

Congratulations. :)

Ricardo Andrade

Tim

unread,
Aug 12, 2016, 7:31:52 PM8/12/16
to f3-fra...@googlegroups.com
Hi Ricardo,

I haven't added recurring payments (subscriptions) support to the plugin yet, but it's a great request. 
I'll add it as an enhancement over the next few weeks :) 

I'd just like to highlight that you can use the apireq method to leverage any of the classic API operations https://developer.paypal.com/docs/classic/api/#ec.

For example here's a simple one to pull the balance of the PayPal account using the GetBalanace API.

$paypal=new PayPal;
$nvp=array('RETURNALLCURRENCIES'=>1);
$result=$paypal->apireq('GetBalance',$nvp);

So technically its possible to to leverage the plugin to create a subscription you'd just have to form part of the request string manually for the two API requests.

SetExpressCheckout (see billing agreement section)

and

CreateRecurringPaymentsProfile



Cheers,
Tim

Ricardo Andrade

unread,
Aug 12, 2016, 8:23:54 PM8/12/16
to Fat-Free Framework
Nice!

I will wait the enhacement to try your plugin and maybe adopt it in place of my code. :)

Best Regards,

Ricardo Andrade

Tim

unread,
Sep 27, 2016, 12:59:32 PM9/27/16
to Fat-Free Framework
Recurring Payments added to the RP branch; I just need to update the example code and merge back to the main branch.

https://github.com/kreative/F3-PYPL/tree/RP

Summer White

unread,
Oct 18, 2016, 1:39:57 AM10/18/16
to f3-fra...@googlegroups.com
I'm about to start on a payment gateway integration for my cms. I've previously looked at paypals new api called braintree and now am wondering if I should reinvent the wheel or extend onto your plugin or just use your plugin and not worry about braintree.

Naturally I have no experience with payment gateways yet so I was hoping for some wise words from you before I start :)

edit: more content

Tim

unread,
Oct 18, 2016, 8:59:19 AM10/18/16
to Fat-Free Framework
Hey Summer,

I guess it really depends on what you want to do from a payments perspective?
The v.zero integration method is the latest and greatest, followed by REST or the classic API with in-context (lightbox/popup).

The F3-PYPL plugin covers pretty much everything now. I've added support for recurring payments (subscriptions) and billing agreements (reference transactions) to the RP branch.
I just need to do a few more tests update the documentation and merge.

Cheers,
T

ved

unread,
Oct 18, 2016, 11:42:44 AM10/18/16
to Fat-Free Framework
Braintree already has a pretty good PHP library so I personally wouldn't waste time reinventing it with F3.

Tim O'Leary

unread,
Oct 18, 2016, 12:28:41 PM10/18/16
to ved via Fat-Free Framework, Fat-Free Framework on behalf of Anatol Buchholz

Yup, just setup the PHP SDK and add the v.zero JS library and you're good to go


--
-- You've received this message because you are subscribed to the Google Groups group. To post to this group, send an email to f3-fra...@googlegroups.com. To unsubscribe from this group, send an email to f3-framework+unsubscribe@googlegroups.com. For more options, visit this group at https://groups.google.com/d/forum/f3-framework?hl=en
---
You received this message because you are subscribed to a topic in the Google Groups "Fat-Free Framework" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/f3-framework/PZSBCVQ0MeM/unsubscribe.
To unsubscribe from this group and all its topics, send an email to f3-framework+unsubscribe@googlegroups.com.
To post to this group, send email to f3-fra...@googlegroups.com.
Visit this group at https://groups.google.com/group/f3-framework.
To view this discussion on the web visit https://groups.google.com/d/msgid/f3-framework/0617d41a-7c41-4273-80ee-93ccf89857b9%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Summer White

unread,
Oct 20, 2016, 2:48:59 AM10/20/16
to Fat-Free Framework
Thanks for the advice. I decided I'll dive in with your plugin anyway and get some experience with the 'classic' API. Once I feel comfortable I'll do another integration with v.zero.

I'm setting this up on localhost so I'm having a few troubles with the sandbox. But one very interesting thing I found was that the sandbox was responding with HTTP/1.0 400 Bad Request.

After doing some research I added to the options array (line 63) 'protocol_version' => 1.1 and that seemed to fix that problem.

Summer White

unread,
Oct 20, 2016, 2:57:45 AM10/20/16
to Fat-Free Framework
Just finished testing a basic $paypal->create() and it worked perfectly.

Also, I'm not a fan about your design decision to use the config section to set the paypal api information. I understand why, but it would be nice that it was optional and that you can set it up through the constructor. For example I am currently doing this to setup your plugin (settings pulls from a sqlite database).

$f3->PAYPAL = [
   
"user" => $this->settings["username"],
   
"pass" => $this->settings["password"],
   
"signature" => $this->settings["signature"],
   
"endpoint" => "sandbox",
   
"apiver" => "124.0",
   
"return" => $f3->SCHEME ."://".$f3->HOST.$f3->BASE."/".trim($this->settings["return"], "/"),
   
"cancel" => $f3->SCHEME ."://".$f3->HOST.$f3->BASE."/".trim($this->settings["cancel"], "/"),
   
"log"=>0
];

$paypal
= new PayPal;

$f3
->clear("paypal");

What I would rather be able to do instead is

new PayPal ([
   
"user" => $this->settings["username"],
   
"pass" => $this->settings["password"],
   
"signature" => $this->settings["signature"],
   
"endpoint" => "sandbox",
   
"apiver" => "124.0",
   
"return" => $f3->SCHEME ."://".$f3->HOST.$f3->BASE."/".trim($this->settings["return"], "/"),
   
"cancel" => $f3->SCHEME ."://".$f3->HOST.$f3->BASE."/".trim($this->settings["cancel"], "/"),
   
"log"=>0
]);

Tim

unread,
Oct 22, 2016, 8:22:14 AM10/22/16
to Fat-Free Framework
Cool I like this - happy to take on board changes and improvements! Can you address the comment I left on git so I can complete the merge?

Cheers,
Tim

Tim

unread,
Oct 27, 2016, 10:43:53 AM10/27/16
to f3-fra...@googlegroups.com
1.0.1 is released - now with recurring payments, reference transactions & Summers additional configuration :)

https://github.com/kreative/F3-PYPL/releases/tag/v1.0.1

Anatol Buchholz

unread,
Oct 27, 2016, 4:59:08 PM10/27/16
to Fat-Free Framework
+1 Tim, nice work!

RHF

unread,
Jun 11, 2018, 12:57:21 PM6/11/18
to Fat-Free Framework
Tim,

I just became aware of your plugin. It is clear you have done a lot of good work and I thought I would give it a try.
Unfortunately, I am having problems getting the Quick Start express checkout to work.
Some of the elements in the $result array are: 

  'ACK' => 'Failure',
  'L_ERRORCODE0' => '10002',
  'L_SHORTMESSAGE0' => 'Security error',
  'L_LONGMESSAGE0' => 'Security header is not valid',
  'L_SEVERITYCODE0' => 'Error',

It appears I have something wrong with my credentials.
I thought I would check with you on the terminology, which seems to have changed.
'user'=>'apiusername'        ->  Same as Sandbox account email
'pass'=>'apipassword'        ->  Sandbox account password
'signature'=>'apisignature'  ->  Client ID
I would appreciate any thoughts or suggestions,

Bob

Tim O'Leary

unread,
Jun 11, 2018, 4:30:40 PM6/11/18
to f3-framework+APn2wQcoB8VR61yPBwA...@googlegroups.com, Fat-Free Framework on behalf of Anatol Buchholz
Hi Bob,

The terminology your using above (client ID, secret etc) is related to the REST API's.

In PayPal Developer navigate to Sandbox > Accounts
image.png

Click the profile link under your test business account.

image.png

In the popup window click the API Credentials tab and you'll see the API username, password & signature.

image.png





--
-- You've received this message because you are subscribed to the Google Groups group. To post to this group, send an email to f3-fra...@googlegroups.com. To unsubscribe from this group, send an email to f3-framework...@googlegroups.com. For more options, visit this group at https://groups.google.com/d/forum/f3-framework?hl=en

---
You received this message because you are subscribed to a topic in the Google Groups "Fat-Free Framework" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/f3-framework/PZSBCVQ0MeM/unsubscribe.
To unsubscribe from this group and all its topics, send an email to f3-framework...@googlegroups.com.

To post to this group, send email to f3-fra...@googlegroups.com.
Visit this group at https://groups.google.com/group/f3-framework.

RHF

unread,
Jun 11, 2018, 5:47:17 PM6/11/18
to Fat-Free Framework
 
Tim,

Excellent. That is what I needed to access the account. 
Now I just need to learn how to use the different features of your plugin.
Thanks very much,

Bob

Tim O'Leary

unread,
Jun 11, 2018, 6:03:03 PM6/11/18
to RHF via Fat-Free Framework
The documentation is pretty extensive, let me know what you want to do and I'll give you as much guidance as possible. The sample code is a pretty good example of using the code in a cart scenario, so have a look at that first :)

--
-- You've received this message because you are subscribed to the Google Groups group. To post to this group, send an email to f3-fra...@googlegroups.com. To unsubscribe from this group, send an email to f3-framework...@googlegroups.com. For more options, visit this group at https://groups.google.com/d/forum/f3-framework?hl=en
---
You received this message because you are subscribed to a topic in the Google Groups "Fat-Free Framework" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/f3-framework/PZSBCVQ0MeM/unsubscribe.
To unsubscribe from this group and all its topics, send an email to f3-framework...@googlegroups.com.
To post to this group, send email to f3-fra...@googlegroups.com.
Visit this group at https://groups.google.com/group/f3-framework.

Zazou Vito

unread,
May 13, 2020, 9:08:35 AM5/13/20
to Fat-Free Framework

Hi Tim,
nice job and nice name ;-)

I have a weird problem, communication is fine with pp but I get an error with API call -10426.

A transaction was refused because the ItemTotal amount is invalid.
see: https://www.paypal.com/be/smarthelp/article/why-did-i-get-api-error-code-10426-ts2049

I tried many possibilities in 'itemtotal' ("10", '10', $amout=10 etc...) but without success.
It must be silly, but I can't find a solution.
here's my code :
"
        $paypal = new PayPal($ppconfig);
        $result = $paypal->create("Sale", "EUR", "10.00");

        if ($result['ACK'] != 'Success') {
            die('Error with API call -' . $result["L_ERRORCODE0"]);
        } else {
        //$this->f3->reroute($result['redirect']);
        }
    }
"
and $result gives :
"
array(10) {
  ["TIMESTAMP"]=>
  string(20) "2020-05-13T13:00:32Z"
  ["CORRELATIONID"]=>
  string(13) "d3754fbf2154c"
  ["ACK"]=>
  string(7) "Failure"
  ["VERSION"]=>
  string(5) "204.0"
  ["BUILD"]=>
  string(8) "54552145"
  ["L_ERRORCODE0"]=>
  string(5) "10426"
  ["L_SHORTMESSAGE0"]=>
  string(94) "Transaction refused because of an invalid argument. See additional error messages for details."
  ["L_LONGMESSAGE0"]=>
  string(22) "Item total is invalid."
  ["L_SEVERITYCODE0"]=>
  string(5) "Error"
  ["redirect"]=>
  string(66) "https://www.sandbox.paypal.com/webscr&cmd=_express-checkout&token="
}
"
thank you for your help,
Vito.

Tim

unread,
May 13, 2020, 9:36:36 AM5/13/20
to Fat-Free Framework
Hi Vito,

I just did a quick test 

$f3->route('GET /vito',
    function ($f3) {

        $paypal = new PayPal;
        $result = $paypal->create('Sale', 'EUR', '10.00');
        // Reroute buyer to PayPal with resulting transaction token
        if ($result['ACK'] != 'Success') {
            // Handle API error code
            die('Error with API call - ' . $result["L_ERRORCODE0"]);
        } else {
            // Redirect Buyer to PayPal
            $f3->reroute($result['redirect']);
        }
    }
);

And it's working fine, I've a few meetings coming up now shortly but I'll take a look at it a little later for you.

F3-PYPL is pretty outdated at this stage, I plan on releasing something in the coming months that's more up to date that leverages the client side REST JS SDK.

Cheers,
Tim

Zazou Vito

unread,
May 13, 2020, 1:34:17 PM5/13/20
to Fat-Free Framework
Hi Tim,
thank you for your quick answer,
I simply copy and paste your code but I still got the same error...
I was using another code on my own for pp transactions and it's still working well
but it use Rest\ApiContext and did not use the f3 basket...
But in the future I would like to use your pp class for its easy binding to f3 basket. ;-)
So I'm not really in a hurry, but thank you for your further investigations.
thank again,
Vito

Tim

unread,
May 13, 2020, 6:39:04 PM5/13/20
to Fat-Free Framework
Hey Vito,

Actually while looking into this you brought my attention to a problem :)
https://github.com/timoleary/F3-PYPL/commit/1f563cb391b3b122fdcdf24347e24e610ad67f3f

The item total API value should only be added to the request when using the copyBasket() or setLineItem() methods.
I don't think this is the root cause of the problem you were experiencing, but a side effect of fixing this is that it will also remove the additional line that's causing the problem with your API request.

Let me know how you get on.

Cheers,
Tim

Zazou Vito

unread,
May 14, 2020, 6:16:38 AM5/14/20
to f3-fra...@googlegroups.com
Thanxxx Tim,
it helps !

But I don't know if my changes is a good solution.
I try to use setLineItem() method and still got the same error, then make the change you suggest
still the same weird error so I struggle again with itemtotal and I came on this code that works for me :

        if (isset($this->lineitems)) {
            if ($this->itemtotal > 0) {

                $this->lineitems["PAYMENTREQUEST_0_ITEMAMT"] = $this->itemtotal;    //sprintf('%0.2f', $this->itemtotal);
                $nvp = array_merge($nvp, $this->lineitems);
            }
        }

and called like this :

            $result = $paypal->create('Sale', 'EUR', '110');

I just remove sprintf and it works but again I' not quite sure it's a good idea...
Anyway thank you so much for your kindness and your work.
Let me know about it,
Vito

Tim O'Leary

unread,
May 14, 2020, 6:39:59 AM5/14/20
to Zazou Vito via Fat-Free Framework
Can you run print_r(localeconv()); and check your decimal_point key?

I'd say you're in a region that's using comma rather than a period.

On Thu, 14 May 2020 at 11:16, Zazou Vito via Fat-Free Framework <f3-framework+APn2wQedS5acjvxz8gI...@googlegroups.com> wrote:
Thanxxx Tim,
it helps !

--
-- You've received this message because you are subscribed to the Google Groups group. To post to this group, send an email to f3-fra...@googlegroups.com. To unsubscribe from this group, send an email to f3-framework...@googlegroups.com. For more options, visit this group at https://groups.google.com/d/forum/f3-framework?hl=en
---
You received this message because you are subscribed to a topic in the Google Groups "Fat-Free Framework" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/f3-framework/PZSBCVQ0MeM/unsubscribe.
To unsubscribe from this group and all its topics, send an email to f3-framework...@googlegroups.com.

Zazou Vito

unread,
May 14, 2020, 8:10:04 AM5/14/20
to f3-fra...@googlegroups.com
this is what I get :
Array ( [decimal_point] => , [thousands_sep] => . [int_curr_symbol] => EUR [currency_symbol] => € [mon_decimal_point] => , [mon_thousands_sep] => . [positive_sign] => [negative_sign] => - [int_frac_digits] => 2 [frac_digits] => 2 [p_cs_precedes] => 0 [p_sep_by_space] => 1 [n_cs_precedes] => 0 [n_sep_by_space] => 1 [p_sign_posn] => 1 [n_sign_posn] => 1 [grouping] => Array ( [0] => 3 [1] => 3 ) [mon_grouping] => Array ( [0] => 3 [1] => 3 ) ) 1

you're rigth decimal_point is a comma...
so what am I suppose to do ?
convert itemtotal and where ? or setlocal() differently ?
any idea ?

 I just try this :

$this->lineitems["PAYMENTREQUEST_0_ITEMAMT"] = sprintf('%0,2f', $this->itemtotal);

I put a comma at the place of  the period in sprintf and it works well,
is this the right way ?
Thank again,
Vito

Tim

unread,
May 14, 2020, 8:24:17 AM5/14/20
to Fat-Free Framework
Excellent thank you for helping me debug.

That should be fixed now if you'd like to give it a go.

Paul Herring

unread,
May 14, 2020, 9:05:55 AM5/14/20
to Tim via Fat-Free Framework, Fat-Free Framework
Just an observation, Tim - and you can probably ignore it, but not all currencies have 2 dp... ;) 

(Basically Dinar's in various countries, and the Rial Omani have 3. There's a few there with 0 dp as well. Whether Paypal themselves actually support them is another matter...)

Zazou Vito

unread,
May 14, 2020, 9:20:08 AM5/14/20
to Fat-Free Framework
oh I'm so proud and happy to have been able to help you, even just a little.
I'm newbie with F3 ;-) and not really expert in developing...
Just try with your changes in lineitems and yessss it did it!
I'll dive deeper into this and thank you again for everything.
All the best,
Vito

Tim

unread,
May 14, 2020, 9:52:39 AM5/14/20
to Fat-Free Framework
Oh, that's a real good call out PJH - I tend to work with EUR, GBP & USD all the time so there's a fixed train of thought! Thanks for the derail hahah :)

For the majority of currencies PayPal use 2 decimal places and an optional comma for thousands with the classic API.

There are, as you point out exceptions to the rule. Within the PayPal list of supported currencies, specifically TWD, JPY & HUF are impacted.

I could add a format function that checks the currency and applies the format or leaves it alone if it's one of the 3 listed above.
If anyone has more suggestions or can think of a better way to handle it rather than a conditional let me know.

Cheers,
Tim

On Thursday, May 14, 2020 at 2:05:55 PM UTC+1, PJH wrote:
Just an observation, Tim - and you can probably ignore it, but not all currencies have 2 dp... ;) 

(Basically Dinar's in various countries, and the Rial Omani have 3. There's a few there with 0 dp as well. Whether Paypal themselves actually support them is another matter...)

Vito

unread,
May 14, 2020, 10:03:52 AM5/14/20
to Fat-Free Framework
 Hi PJH,
I don't think PP support Dinar, I did not found in PP curency codes.
thank for your observation anyway...
Vito

Paul Herring

unread,
May 14, 2020, 10:28:56 AM5/14/20
to Vito via Fat-Free Framework, Fat-Free Framework
At the moment.

Anyway, combining your URL, with the one I posted:

Australian dollar AUD 2
Brazilian real 2 BRL 2
Canadian dollar CAD 2
Czech koruna CZK 2
Danish krone DKK 2
Euro EUR 2
Hong Kong dollar HKD 2
Hungarian forint 1 HUF 0
Indian rupee 3 INR 2
Israeli new shekel ILS 2
Japanese yen 1 JPY 0
Malaysian ringgit 4 MYR 2
Mexican peso MXN 2
New Taiwan dollar 1 TWD 2
New Zealand dollar NZD 2
Norwegian krone NOK 2
Philippine peso PHP 2
Polish złoty PLN 2
Pound sterling GBP 2
Russian ruble RUB 2
Singapore dollar SGD 2
Swedish krona SEK 2
Swiss franc CHF 2
Thai baht THB 2
United States dollar USD 2

 

Paul Herring

unread,
May 14, 2020, 10:46:06 AM5/14/20
to Tim via Fat-Free Framework, Fat-Free Framework
On Thu, May 14, 2020 at 2:52 PM Tim via Fat-Free Framework <f3-framework+APn2wQchkRDiZT2YcvC...@googlegroups.com> wrote:
I could add a format function that checks the currency and applies the format or leaves it alone if it's one of the 3 listed above.
If anyone has more suggestions or can think of a better way to handle it rather than a conditional let me know.

Presuming PP don't actually have a lookup for this sort of thing (do they?):

Else, presuming you want to be forward compatible with anything else they introduce:

function dp($currency){
       switch ($currency){
               case "BIF":
               case "BYN":
               case "BYR":
               case "CLP":
               case "DJF":
               case "HUF":
               case "ISK":
               case "JPY":
               case "KMF":
               case "KRW":
               case "MGA":
               case "MZN":
               case "PYG":
               case "RWF":
               case "VUV":
               case "XPF":
               /* - any more 0 dp- */
                       return 0;
               case "BHD":
               case "IQD":
               case "JOD":
               case "KWD":
               case "LYD":
               case "OMR":
               case "TND":
               /* - any more 3 dp- */
                       return 3;
                       break;
               default:
               /* - everything else- */
                       return 2;
                       break;
       }
}
Or simply cut the function down to the two I showed in the other post, but keep the structure, to make changes simpler later if/when PP add them (or, of course, double check the actual code there.)


Can you have multiple currencies in a purchase? If not, simply store $this->dp when you know the currency then, for the likes of #174

174 $this->lineitems["PAYMENTREQUEST_0_ITEMAMT"] = number_format($this->itemtotal, $this->dp, '.', '');
Or if different currencies..
174 $this->lineitems["PAYMENTREQUEST_0_ITEMAMT"] = number_format($this->itemtotal, dp($currency), '.', '');
To save the checking, 0 dp with number_format() omits the decimal separator:

$ php -r 'echo number_format(123.456, 3, ":", 0)."\n";'
123:456
$ php -r 'echo number_format(123.456, 2, ":", 0)."\n";'
123:46
$ php -r 'echo number_format(123.456, 1, ":", 0)."\n";'
123:5
$ php -r 'echo number_format(123.456, 0, ":", 0)."\n";'
123
$ php -r 'echo number_format(123.456, -1, ":", 0)."\n";' # just checking...
123



 
Reply all
Reply to author
Forward
0 new messages