Im using this laravel package "https://github.com/kanazaca/easypay" to create a MB reference using the Easypay API.
I have this method to create the reference:
public function generateReference()
{
$amount = Session::get('total');
$payment_info = [
't_value' => $amount,
'o_obs' => '',
't_key' => 1
];
$easypay = new EasyPay($payment_info);
$reference = $easypay->createReference();
Session::put('entity', $reference['ep_entity']);
Session::put('reference', $reference['ep_reference']);
Session::put('value', $reference['ep_value']);
}
And it works fine with this code I get some reference codes which can be payed using MB or credit-card.
Then, when a payment is made, easypay will call a "Notification URL".
that we should configure on easypay's backoffice under "URL Configurations".
Because when the easypay service receives the payment they will call the URL that we provided. So I defined a url in the easypay´s backoffice and created a route in the project:
Route::get('/easypay/notification-callback', [
'uses' => 'PaymentController#receiveNotifications',
'as' =>'mb.notifications'
]);
In the api backoffice there is a button that simulates a payment, after this button is clicked nothing happens and if I manually access "http://....ngrok.io/easypay/notification-callback" it appears an empty array:
[]
But in the documentation (https://docs.easypay.pt/workflow/payment-notification) says that when Easypay calls this endpoint, it comes with a few parameters: "ep_cin", "ep_user" and "ep_doc" that will be necessary in the process. So it should not appear an empty array.
Do you know what can be the issue? Im a beginner uing API´s so Im not understnading what the issue can be.
PaymentController receiveNotifications() method:
public function receiveNotifications(Request $request)
{
dd($request->all());
//$easypay = new EasyPay($payment_info);
//$xml = $easypay->processPaymentInfo();
//return \Response::make($xml, '200')->header('Content-Type', 'text/xml'); //must return in text/xml for easypay
}
receiveNotifications() method with log:
public function receiveNotifications(Request $request)
{
//dd($request->all());
Log::info('Showing info: ' .var_export($request->all(),true));
$payment_info = [
'ep_cin' => $request->ep_cin,
'ep_user' => $request->ep_user,
'ep_doc' => $request->ep_doc
];
Log::info('Showing info: ' .var_export($payment_info,true));
//dd($payment_info);
$easypay = new EasyPay($payment_info);
$xml = $easypay->processPaymentInfo();
return \Response::make($xml, '200')->header('Content-Type', 'text/xml'); //must return in text/xml for easypay
}
The session is saved in the session file of the user that visits your website that initiates the payment.
The receiveNotifications would call data from the session file that belongs to the payment gateway server if you were doing anything there. The data isn't matched because the two don't know about each other.
Also, you might not have a Session::save() somewhere in your request handling which writes the session data to file.
Store the reference in a database. Create a model for storing this data, so you can then query that model for the correct reference ID to verify/do stuff.
When the request comes back from the payment gateway use the variables ep_cin, ep_user and ep_doc to get the data from the model.
When you manually request that data you are requesting it with a GET request, which doesn't send the above data along.
The request made by the payment provider will get the result of the DD but that's logged nowhere, so nothing happens.
Log your data for requests triggered by remote api's to see what happens.
Related
How can I test RESTful api of DELETE in Laravel by using Codeception?
I use the following function:
public function authenticatedUserSuccessDeleteEmployee(ApiTester $I)
{
$I->wantToTest('authenticated super user success delete employee');
// set header authorization
$I->amBearerAuthenticated($this->token);
//
$this->employee = factory(\App\Models\Employee::class)->create([
'id' => '20200100000000'
]);
// see database row is containing our expected data
$I->seeRecord('employees', ['id' => '20200100000000']);
// Send delete request
$I->sendDELETE('employees', array('id' => '20200100000000'));
// check expected response code is 200 OK
$I->seeResponseCodeIs(200);
}
But the employee does not created in the DB!
How can I create an object for testing delete API?
I found the problem. I need to send the id as part of the url!
$I->sendDELETE('employees/20200100000000');
What I'm trying to do here is to implement a callback function in a Laravel 5.4 controller. This uses Authorize.net to process a credit card transaction, then inserts a bunch of stuff into the database, sends some messages, makes an invoice and airbill, and so on.
What I WANT to happen is:
Hit the "Submit" button, sends AJAX request
Processes the Authorize.net transaction
If good, then call a callback function to do all the gruntwork but return a transaction response.
4) Notify the user
The reason I wanna do it this way is that I want the user to wait the minimum amount of time to see the result of their payment processing without having to wait another 5 seconds or so staring at a spinning wheel waiting to go to the order complete page.
Can a callback function help me do this?
Thanks
My current implementation results in a 500 error, and I'm not quite sure what I should do from here...
[ route in web.config ]
// AJAX call to process the transaction, insert the new order, inform the user of success/failure
Route::post('/shop/processtransaction', 'OrderCheckoutController#processTransaction');
[ function processTransaction in OrderCheckoutController.php ]
public function processTransaction(Request $request) {
return self::processPaymentAndOrderInsertion($request, 'createOrder');
}
[ function processPaymentAndOrderInsertion in OrderCheckoutController.php ]
public function processPaymentAndOrderInsertion(Request $request, callable $createOrderCallback = null) {
$order_proc = new OrderProcessingTools;
$transaction_response = $order_proc->processTransaction($request);
if($transaction_response['success'] === true) {
self::$createOrderCallback($request, $transaction_response);
}
return json_encode($transaction_response);
}
[ my callback function ]
public function createOrder(Request $request, $transaction_response) {
$order_proc = new OrderProcessingTools;
$new_order = $order_proc->insertNewOrder($request);
$new_order->payment_status_id = $transaction_response['response_data']['order_payment_status_id'];
$new_order->save();
// record the payment transaction
$order_proc->insertOrderPaymentData($new_order, $transaction_response);
// insert the travelers for this order
$travelers = $order_proc->insertOrderTravelers($new_order);
// insert order inbound shipment record
$order_proc->insertInboundOrderShipping($new_order->id);
// generate inbound shipping airbill
$order_proc->generateInboundShippingAirbill($new_order->id);
/// generate the invoive
$order_proc->generateInvoice($new_order);
// send new order notification to the user
$order_proc->sendNewOrderNotificationToUser($new_order);
// send new order notification to admin
$order_proc->sendNewOrderNotificationToAdmin($new_order);
// finally kill the session variable
$_SESSION['travelers'] = [];
}
[ my previous non-asynchronous implementation looks like this...]
public function processTransaction(Request $request) {
// :: POST
// Process the Authorize.net transaction, insert the order, generate invoices
// and airbills, send notifications
$order_proc = new OrderProcessingTools;
$transaction_response = $order_proc->processTransaction($request);
if($transaction_response['success'] === true) {
// insert a new order
$new_order = $order_proc->insertNewOrder($request);
$new_order->payment_status_id = $transaction_response['response_data']['order_payment_status_id'];
$new_order->save();
// record the payment transaction
$order_proc->insertOrderPaymentData($new_order, $transaction_response);
// insert the travelers for this order
$travelers = $order_proc->insertOrderTravelers($new_order);
// insert order inbound shipment record
$order_proc->insertInboundOrderShipping($new_order->id);
// generate inbound shipping airbill
$order_proc->generateInboundShippingAirbill($new_order->id);
/// generate the invoive
$order_proc->generateInvoice($new_order);
// send new order notification to the user
$order_proc->sendNewOrderNotificationToUser($new_order);
// send new order notification to admin
$order_proc->sendNewOrderNotificationToAdmin($new_order);
// finally kill the session variable
$_SESSION['travelers'] = [];
}
// either good news or bad news at this point..
return json_encode($transaction_response);
}
When I try it this way, this is the error that is returned...
xception: "Symfony\Component\Debug\Exception\FatalThrowableError"
file: "F:\wamp64\www\uspassports\public_html\app\Http\Controllers\OrderCheckoutController.php"
line: 105
message: "Argument 2 passed to App\Http\Controllers\OrderCheckoutController::processPaymentAndOrderInsertion() must be callable or null, string given
You need to pass a callable type, but passing just the string name of the method won't work as PHP will only check if it's a global function.
You need to pass an array, with the first parameter being the object to call the method on, and the second the name of the function, like so:
return self::processPaymentAndOrderInsertion($request, [$this, 'createOrder']);
Documentation: https://www.php.net/manual/en/language.types.callable.php
In my tutorial, I realised that I am able to get the number/id of the order during every event except orders/delete. In my controller below, I try to retrieve the order number just as I do for every topic ('orders/create', 'orders/paid')etc, but then I get an error saying:
Undefined index: number in Controller
Controller
public function registerOrderDeleteWebhook()
{
$shop = Auth::user()->site;
$token = Auth::user()->access_token;
$shopify = Shopify::setShopUrl($shop)->setAccessToken($token);
Shopify::setShopUrl($shop)->setAccessToken($token)->post("admin/webhooks.json", ['webhook' =>
['topic' => 'orders/delete',
'address' => 'https://example.domain.com/order-delete-webhook',
'format' => 'json'
]
]);
}
public function orderDeleteWebhook(Request $request)
{
$order = $request->getContent();
$order = json_decode($order, true);
$order_id = $order['number'];
//send notification to Admin with order number deleted below
}
Why could this be happening for only orders/delete?
the undefinded index error
occurs because there is no number field in Shopify Order Delete webhook response. Moreover, it is always a good idea to check if the field exists in the first place.
If you look at the Delete Order response sent by Shopify, it only includes,
{
"id": 777859760246
}
where id is the Order Id. But as the order is deleted you cannot get anymore details later even via API. According to this forum post an order cannot be deleted until it is cancelled first. So a workaround is to listen to Order Cancel hook too and save this information somwehere in your Laravel application ( database etc ) and use it later when Order Delete webhook is recieved.
I am using a function I created that I have tried creating customers from, and creating charges from. For whatever reason it seems to be double charging in test mode (Not bringing into live mode under these conditions) and I'm trying to understand why. I had it going through a few functions so I made it all happen in one function to make sure that it had nothing to do with what I had made. I'm lost on why this is happening. I try to make charges from token, doubles in less than a second. I try to create a customer from token, doubles in less than a second. I am using Stripes latest stripe-php library.
public function invoice($invoice = null) {
//Provides billing info for invoice.ctp
$this->loadModel('Invoice');
$billingi = $this->Invoice->get($invoice, [
'contain' => ['Items'],
]);
$dollars = 0;
foreach ($billingi->items as $item) {
$dollars += $item->price;
}
$cents = bcmul($dollars, 100);
$price = floatval($cents);
if ($this->request->is('post')) {
$stripeToken = $this->request->data('stripeToken');
//Sets stripe API
\Stripe\Stripe::setApiKey("sk_test_QVYouMViTf1k3zfVu2VAyZge");
//Retrieves stripe token from stripe API
//$response = \Stripe\Token::retrieve($stripeToken);
\Stripe\Customer::create(array(
"description" => "Test customer",
"source" => $stripeToken // obtained with Stripe.js
));
$this->Flash->success(__('Thank you for your payment!'));
return $this->redirect(['action' => 'approved', $invoice]);
}
/*
if ($response && $this->checkExists($response->card->cvc_check, $response->card->address_zip_check) == true) {
$this->insertCharge($invoice, $response, $price);
} else {
//Throw error because cvc_check or zip came back null (doesn't exist)
}
}
*/
$this->set('billingi', $billingi);
$this->set('_serialize', ['billing']);
}
The reason why there are things commented out is because I wanted to test the function without it, but adding it back later when I understand what the issue is.
In your code, the only API request sent to Stripe is a customer creation request (\Stripe\Customer::create(...)).
This doesn't charge the user -- it merely validates the card from the token in the source parameter, and creates a persistent customer object that you can in turn use to create actual charges. This tutorial explains this flow.
There's nothing in your code that would cause the API request to be sent twice. It's very unlikely the issue is on Stripe's end. More likely, your code is being called twice for some reason that's not related to Stripe. You'd need to add traces to your code to figure out what exactly is being called in what order.
I've created a custom payment gateway but now I need to handle post payment notifications (just like IPN) to append additional information for a given transaction.
I've tried a lot of different combinations including:
Mage::getModel('sales/order')->load('#id')
->getPayment()
->getTransaction('#id')
->setAdditionalInformation('foo', 'bar')
->save();
Which doesn't produce any error (I'm able to retrieve order/payment/transaction)
But save action seems to be inoperant. I also tried to save through the payment object without luck.
Found out by myself :P
$payment->getTransaction($id)
->setAdditionalInformation(
Mage_Sales_Model_Order_Payment_Transaction::RAW_DETAILS,
$data
)->save();
If you´re trying to include information on the "authorize" stage of paymnet, here´s an useful snippet (please change variables to your own data!):
public function authorize(Varien_Object $payment, $amount) {
.....
$_data = array( 'Tranx' => $_transax, 'Auth' => $_autho ...);
$payment->setTransactionAdditionalInfo(
Mage_Sales_Model_Order_Payment_Transaction::RAW_DETAILS,
$_data);
$payment->setTransactionId($_authid)->setIsTransactionClosed(0);
return $this
}
$transactin_detail = Mage::getModel('sales/order')->loadByIncrementId($order_id)->getPayment()->getTransaction($transId)->save();
echo '<pre>';
print_r($transactin_detail);