How to implement an external payment gateway with Prestashop? - php

I need to implement an external payment gateway in Prestashop. I have to send an HTTP request as below:
<form method="post" name="payment" action="url">
blah blah....
<input name="ResponseURL" value="{$response}">
</form>
The ResponseURL is the URL provided by me to retrieve the response from the API. This is where I need to perform validation checking and redirect to the order confirmation page. (similarly to the validation front controller from ps_checkpayment module)
I have also added the hookPaymentOption
public function hookPaymentOptions($params)
{
if (!$this->active) {
return;
}
//some code here
$response = 'http://' . $_SERVER['SERVER_NAME'] . $this->_path . '/classes/response.php';
$formAction = $this->context->link->getModuleLink($this->name, 'validation', array(), true);
$this->smarty->assign([
//some code here
'response' => $response
]);
$paymentForm = $this->fetch('module:easypaymentoption/views/templates/hook/payment_options.tpl');
$newOption = new PaymentOption();
$newOption->setModuleName($this->displayName)
->setCallToActionText($this->displayName)
->setAction($formAction)
->setForm($paymentForm);
$payment_options = array(
$newOption
);
return $payment_options;
}
I'm just really clueless as to how to proceed. I've tried to link my $response to a front module controller class, but I get an error that says
Fatal error: Uncaught Error: Class 'ModuleFrontController' not found in C:\xampp\htdocs\prestashop\modules\easypaymentoption\classes\response.php:3 .
I have also tried to link to an empty php file, but by doing this I can't get the necessary information to do validation checking and redirect to the order confirmation page that I would otherwise would get by using a class that extends ModuleFrontController.
Any help is appreciated, as I've been stuck here for almost 3 days.

Related

Paying with the api and saving the returned result in the database

I am not very experienced in Laravel and I am working on a payment method.
I prepared the payment form. The data I send is approved on the other side, but the confirmation notification gives an error when returning to the site.
I need to receive this notification via POST. But the method I applied was not enough.
**web**
Route::post('gateway/confirm_payment/{order_id}', 'Website\GatewayController#confirm_payment');
**GatewayController**
use Illuminate\Http\Request;
public function confirm_payment(Request $request, $order_id){
$post = $_POST;
$merchant_key = 'xxxxxx';
$merchant_salt = 'xxxxxx';
$hash = base64_encode( hash_hmac('sha256',
$request->merchant_oid.$merchant_salt.$request->status.$request->total_amount, $merchant_key, true) );
if( $hash != $request->hash)
die('Notification failed: bad hash');
if( $request->status == 'success' ) {
dd($request->all());
//output null
}else{
//Insert
}
}
**Payment.blade**
<div id="gateway-loader">
<script src="https://www.gateway.com/js/iframeResizer.min.js"></script><iframe src="https://www.gateway.com/payment/secure/{{ $order->tokens ?? '' }}" id="iframe" frameborder="0" scrolling="no" style="width: 100%;"></iframe>
<script type="text/javascript">
setInterval(function(){
iFrameResize({},'#iframe');
}, 1000);
</script>
</div>
When I say send the form, the payment is sent to the other party and I can successfully pay.
But when returning to the site as a result of the payment, I get the following error.
"The GET method is not supported for this route. Supported methods: POST."
According to the returned result, I needed to register to the database, but I did not understand why I could not get the POST data returned by the Api.
When I use GET, it does not give an error, but an undefined value comes.
I need to get this returning result with POST method, how can I use POST method?

Response object - Payment with Mollie and Omnipay

I'm trying to create a payment with Omnipay and Mollie in my Laravel project. I'm using the following 2 libraries:
https://github.com/barryvdh/laravel-omnipay
https://github.com/thephpleague/omnipay-mollie
I'm doing the following in my code:
$gateway = Omnipay\Omnipay::create('Mollie');
$gateway->setApiKey('test_gSDS4xNA96AfNmmdwB3fAA47zS84KN');
$params = [
'amount' => $ticket_order['order_total'] + $ticket_order['organiser_booking_fee'],
'description' => 'Bestelling voor klant: ' . $request->get('order_email'),
'returnUrl' => URL::action('EventCheckoutController#fallback'),
];
$response = $gateway->purchase($params)->send();
if ($response->isSuccessful()) {
session()->push('ticket_order_' . $event_id . '.transaction_id',
$response->getTransactionReference());
return $this->completeOrder($event_id);
}
The payment works. When the payment is done he goes back to the function fallback. But I don't know what to put in this function and how to go back to the line if($response->isSuccesfull()...).
The most important thing I need to do after the payment is :
session()->push('ticket_order_' . $event_id . '.transaction_id',
$response->getTransactionReference());
return $this->completeOrder($event_id);
Can someone help me figure out how to work with the fallback function and above?
A typical setup using Mollie consists of three separate pages:
a page to create the payment;
a page where Mollie posts the final payment state to in the background; and
a page where the consumer returns to after the payment.
The full flow is described in the Mollie docs. Also take a look at the flow diagram at that page.
DISCLAIMER: I've never used Omnipay myself and did not test the following code, but it should at least give you an idea how to set up your project.
Creating the payment:
$gateway = Omnipay\Omnipay::create('Mollie');
$gateway->setApiKey('test_gSDS4xNA96AfNmmdwB3fAA47zS84KN');
$params = [
'amount' => $ticket_order['order_total'] + $ticket_order['organiser_booking_fee'],
'description' => 'Bestelling voor klant: ' . $request->get('order_email'),
'notifyUrl' => '', // URL to the second script
'returnUrl' => '', // URL to the third script
];
$response = $gateway->purchase($params)->send();
if ($response->isRedirect()) {
// Store the Mollie transaction ID in your local database
store_in_database($response->getTransactionReference());
// Redirect to the Mollie payment screen
$response->redirect();
} else {
// Payment failed: display message to the customer
echo $response->getMessage();
}
Receiving the webhook:
$gateway = Omnipay\Omnipay::create('Mollie');
$gateway->setApiKey('test_gSDS4xNA96AfNmmdwB3fAA47zS84KN');
$params = [
'transactionReference' => $_POST['id'],
];
$response = $gateway->fetchTransaction($params);
if ($response->isPaid()) {
// Store in your local database that the transaction was paid successfully
} elseif ($response->isCancelled() || $response->isExpired()) {
// Store in your local database that the transaction has failed
}
Page where the consumer returns to:
// Check the payment status of your order in your database. If the payment was paid
// successfully, you can display an 'OK' message. If the payment has failed, you
// can show a 'try again' screen.
// Most of the time the webhook will be called before the consumer is returned. For
// some payment methods however the payment state is not known immediately. In
// these cases you can just show a 'payment is pending' screen.

Guzzle post request result in a 400 Bad Request

I'm new to google drive api.
When I run the following piece of code (I got it from here) I get the following error:
Fatal error: Uncaught exception 'GuzzleHttp\Exception\ClientException' with message 'Client error: POST https://spreadsheets.google.com/feeds/list/1AnZ9_h3jnKogvx5AIftxypGnGM0f2P4r_ut4RGFC7AQ/od6/private/full resulted in a 400 Bad Request response'
The code:
$postBody = '<entry xmlns="http://www.w3.org/2005/Atom" xmlns:gsx="http://schemas.google.com/spreadsheets/2006/extended"><gsx:gear>more gear</gsx:gear><gsx:quantity>44</gsx:quantity></entry>';
echo "BBBB<br>";
$httpClient = new GuzzleHttp\Client(['headers' => $headers]);
echo "CCCC<br>";
$resp = $httpClient->request($method, $url, ['body' => $postBody]);
echo "DDDD<br>";
$body = $resp->getBody()->getContents();
$code = $resp->getStatusCode();
$reason = $resp->getReasonPhrase();
echo "$code : $reason\n\n";
echo "$body\n";
Can some one help me find the error?
Although this is not related to Guzzle at all, I found another method to do my task.
After creating the form go to Responses menu and select 'Get pre-filled URL'
Fill the dummy form you get and submit. Then you will be given a URL. Here change 'viewResponse' to 'formResponse'
Append the data to necessary parts of the URL.
Send request to this URL to fill the google form automatically and submit

Facebook TokenResponseException with Laravel 4.1 and oauth-4-laravel

I'm getting a TokenResponseException from Laravel when I try to login to my web site with Facebook using oauth-4-laravel.
OAuth \ Common \ Http \ Exception \ TokenResponseException
Failed to request resource.
Using Facebook's JavaScript API works like its supposed to, so I'm pretty sure my application is configured correctly.
Are there any known issues that might cause this problem? Am I doing something wrong, or is this a bug in the library?
With the exception of a redirect line that works around another bug, my code is identical to the example code at the GitHub page. I think the exception is thrown when I try to get the token from the Facebook Service object.
Here's the code:
public function loginWithFacebook() {
// get data from input
$code = Input::get( 'code' );
// get fb service
$fb = OAuth::consumer( 'Facebook' );
// check if code is valid
// if code is provided get user data and sign in
if ( !empty( $code ) ) {
// This was a callback request from google, get the token
$token = $fb->requestAccessToken( $code );
// Send a request with it
$result = json_decode( $fb->request( '/me' ), true );
$message = 'Your unique facebook user id is: ' . $result['id'] . ' and your name is ' . $result['name'];
echo $message. "<br/>";
//Var_dump
//display whole array().
dd($result);
}
// if not ask for permission first
else {
// get fb authorization
$url = $fb->getAuthorizationUri();
// return to facebook login url
// ref: https://github.com/artdarek/oauth-4-laravel/issues/27
//return Response::make()->header( 'Location', (string)$url );
return Redirect::to((string)$url);
}
}
And a screenshot:
I had this exact same problem. It turns out that my issue was that my return_uri was missing a trailing slash, which through off the entire process. Make sure that when you're calling it you've added it.
$fb = OAuth::consumer('Facebook','http://url.to.redirect.to/');
NOT
$fb = OAuth::consumer('Facebook','http://url.to.redirect.to');
first try to load file_get_contents("https://www.facebook.com");
if allow_url_fopen=0 was set in the php.ini it will not work so you need to change it to allow_url_fopen=1
The weirdest thing i have your problem with google not with facebook, so here is my code maby it helps you fix your fb problem
public function loginWithFacebook() {
// get data from input
$code = Input::get( 'code' );
// get fb service
$fb = OAuth::consumer( 'Facebook' );
// check if code is valid
// if code is provided get user data and sign in
if ( !empty( $code ) ) {
// This was a callback request from facebook, get the token
$token = $fb->requestAccessToken( $code );
// Send a request with it
$result = json_decode( $fb->request( '/me' ), true );
$message = 'Your unique facebook user id is: ' . $result['id'] . ' and your name is ' . $result['name'];
echo $message. "<br/>";
//Var_dump
//display whole array().
dd($result);
}
// if not ask for permission first
else {
// get fb authorization
$url = $fb->getAuthorizationUri();
// return to facebook login url
return Redirect::to( (string)$url );
}
}
Since my previous answer was deleted.. Let's try again..
--
After some debugging I think I got it. Commenting out the error_reporting part visible in your code snippet will already tell you a lot. The file_get_contents call got a 401 Unauthorized because the tokens were no longer valid.
After changing code, start your auth process from the beginning and don't refresh your url half-way, that wil cause the error.
The problem should be here $token = $fb->requestAccessToken( $code );
When I tried var_dump it, I get this.
object(OAuth\OAuth2\Token\StdOAuth2Token)[279]
protected 'accessToken' => string 'your-accessToken' (length=180)
protected 'refreshToken' => null
protected 'endOfLife' => int 1404625939
protected 'extraParams' =>
array (size=0)
empty
Try this and check what you've get as accessToken. Anyway, your function loginWithFacebook working fine with me.
I had the same problem. I was trying to access facebook graph. It wasn't that it could not access the URL, it was that Facebook was returning a 400 error because I wasn't passing parameters through. Try connecting to HTTPS on a site that will have a working HTTPS connection. E.g. Try this:
file_get_contents("https://www.namhost.com");
If that works, you must see why the HTTPs connection you are connecting to is failing, because the problem isn't that you can't connect to HTTPs, but rather that what you are connecting to isn't liking the request.

cakephp & nusoap - Function ("my_function") is not a valid method for this service

I have taken over an application from a previous developer, and there was some code which was half finished using Nusoap, I am getting the error:
Call to register_donation() web service failed due to an exception:
Function ("register_donation") is not a valid method for this service
The application is built on: CakePHP 1.2.10 & using nuSoap 0.9.5.
I have already ini_set('soap.wsdl_cache_enabled', 0); (This doesnt help.)
My code is below (I shortened it for readability), Am I processing this response correctly?
(The code was taken over by myself from a previous developer).
The Pastebin (of the full code) is here: PasteBin Link
A shortened version is below for a glance over, the full version is in the pastebin link above.
<?php
ini_set('soap.wsdl_cache_enabled', 0);
class ServicesController extends AppController
{
var $uses = array("Donation");
var $components = array( "Email", "MatchingEvents" );
function registerDonation($donation = null){
$this->log('hit registerDonation', 'donation');
$this->autoRender = false;
App::import('Vendor','nusoap');
Configure::write('debug',0);
Configure::write('Session.start', false);
//init soap server
$server = new soap_server();
$endpoint = 'http://new.mysite.com/services/registerDonation';
//initialize WSDL support
$server->configureWSDL('donations', 'urn:donations', $endpoint);
//setup service type
$server->wsdl->addComplexType(
'DonationResult',
'complexType',
'struct',
'all',
'',
array(
'success' => array('name' => 'success', 'type' => 'xsd:boolean'),
'msg' => array('name' => 'msg', 'type' => 'xsd:string'),
'error_number' => array('name' => 'error_number', 'type' => 'xsd:string')
)
);
//register the method to expose
$server->register('register_donation',
array('ct_number' => 'xsd:string', 'project_id' => 'xsd:int', 'donation_amount' => 'xsd:decimal',
// Stripped all other params
),
array(
'result' => 'tns:DonationResult'
),
'urn:donations',
'urn:donations#register_donation',
'rpc',
'encoded',
'Accepts the results of a donation to a charity or project on the site'
);
//This inner function is registered and then called (keep within outer function!)
function register_donation(
// Pass in all the params (Stripped for readability)
$ct_number = null, $project_id = null, $donation_amount = null
){
// This function is never hit!.. its not registered, why?
$this->log('hit #3-register_donation called!', 'donation');
$return = $this->Donation->add(array(
'unique_id' => $unique_id,
'ct_number' => $ct_number,
'project_id' => $project_id,
'donation_amount' => $donation_amount,
// Pass in all other params, (Stripped for readability)
));
// Process that request
$log = $this->Donation->log . 'Result: ' . $return['msg'] . "\n";
$this->log( $log, 'donation' );
if ( isset($this->Donation->matching['events']) )
{
//Reserved donations should already have had their events handled
$this->MatchingEvents->handle($this->Donation->matching, !$this->Donation->matching['reserved']);
}
if ( !empty($this->Donation->cacheSaved) )
$this->_sendDonationEmails($this->Donation->cacheSaved);
return $return;
}
$HTTP_RAW_POST_DATA = isset($GLOBALS['HTTP_RAW_POST_DATA']) ? $GLOBALS['HTTP_RAW_POST_DATA'] : '';
$server->service($HTTP_RAW_POST_DATA);
}
function _sendDonationEmails($donation)
{
// Send the emails
}
}
?>
If there is any more information I can provide, please let me know.
To Summarise: How do I process a nusoap response coming from a external source.
Any debugging ideas, hints & tips or solution will be rewarded (+1!).
In the code posted there's a function named registerDonation inside a controller named ServicesController. Inside that function there is another function called register_donation (This obviously doesn't make sense [Old Code]).
Remove the function named register_donation out of the registerDonation method and place it as a method inside the ServicesContoller.
Then change the following line (where you register the function to expose).
From: $server->register('register_donation',
To: $server->register('ServicesController.register_donation',
So you're calling class.method as opposed to method only (This would work in PHP4 procedural programming, but in OOP, you need to specify the controller.method when exposing the function).
Having other problems?
Q: CakePHP & nuSOAP is not hitting my controller/method, but redirects to app/webroot
A: Using CakePHP 1.2, I found when it did not have a services model (because it wasn't
technically required), The request does not hit the controller. So if you're having this issue, create a model for your controller, even if you're not using it. For your reference, here a modal example:
<?php // You may not need this modal, but cakephp requires it to be there.
class Services extends AppModel {
public $name = 'Services';
public $useTable = false;
}
?>
Q:What URL should I be receiving responses to?
A: The URL you set your response to hit must include ?wsdl.
So.. for eg: you have a controller named SOAPController and method named process.
In CakePHP, your URL would look like this: mydomain.com/SOAP/process.
So your WSDL is located at mydomain.com/SOAP/process?wsdl. Make sure your callback URL is set to this (including the wsdl).
Q: How do I debug SOAP requests/responses using CakePHP?
A: CakePHP has a logging feature which proved invaluable in debugging SOAP. In your controller (or modal) you can use:
$this->log('your message or variable', 'name_of_file_to_save_to);
You can use this through your SOAP request or response to see what parts are being hit/called and debugging variables (eg: $HTTP_RAW_POST_DATA).
Q: My WSDL location is shown as `domain.com/app/webroot` when I visit the SOAP page.
A: I thought this was the issue causing all the problems, Looking at the source code Nusoap uses PHP_SELF to get the current script (which in cakePHP is app/webroot/index.php), Don't worry about this, you can access the wsdl by appending the URL with ?wsdl, This will show you your generated WSDL file, You don't need to worry about fixing this. Its not interfering with your SOAP request whatsoever, It's merely there for your convenience.
Q: My SOAP address location is showing 'domain.com/app/webroot/index.php`
A: This was a issue I fixed by including the $endpoint in the configureWSDL().
//Set our endpoint, Replace with your URL
$endpoint = 'http://yourdomain.com/controller/method';
//initialize WSDL support - Include the $endpoint.
$server->configureWSDL('donations', 'urn:donations', $endpoint);
// Now your Soap Address Location should be what you set as the $endpoint

Categories