What parameters do I pass to doExpressCheckouPaymentt()? - php

I have this controller that is supposed to perform PayPal payments. The payment function is working well but on getting to success function I am getting an error Illegal string offset 'total' . I am passing $this->productData($request) as suggested in this question. I tried creating a variable $total = $response['AMT'] which is the response from setCheckoutDetails but I still got the same error. How do I go about it?
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Srmklive\PayPal\Services\ExpressCheckout;
class PayPalController extends Controller
{
private function projectData(Request $request){
// dd($request->all());
$item = [];
$datat = array_map(function($item){
return [
'name'=>$request->project_id,
'price'=>$request->budget,
'desc'=>'Deposit',
'qty'=>1
];
}, $item);
$data = [
'items'=>$datat,
'invoice_id' => uniqid(),
'invoice_description' => "Payment for Project No.".$request->project_id." Amount ".$request->budget,
'return_url' => route('payment.success'),
'cancel_url' => route('payment.cancel'),
'total'=>$request->budget
];
// dd($data);
return $data;
}
/**
* Responds with a welcome message with instructions
*
* #return \Illuminate\Http\Response
*/
public function payment(Request $request) {
$data = $this->projectData($request);
$provider = new ExpressCheckout;
$response = $provider->setExpressCheckout($data);
// dd($response);
// $response = $provider->setExpressCheckout($data, true);
return redirect($response['paypal_link']);
}
/**
* Responds with a welcome message with instructions
*
* #return \Illuminate\Http\Response
*/
public function cancel()
{
dd('Your payment is canceled. You can create cancel page here.');
}
/**
* Responds with a welcome message with instructions
*
* #return \Illuminate\Http\Response
*/
public function success(Request $request)
{
$provider = new ExpressCheckout;
$response = $provider->getExpressCheckoutDetails($request->token);
$token = $response['TOKEN'];
$payerId = $response['PAYERID'];
$total = $response['AMT'];
// dd($response);
if (in_array(strtoupper($response['ACK']), ['SUCCESS', 'SUCCESSWITHWARNING'])) {
// dd('Payment successful');
//Performing transaction
$payment_status = $provider->doExpressCheckoutPayment($token, $payerId, $this->projectData($request));
dd($payment_status);
}
dd('Something is wrong.');
}
}

You have to pass three parameters
data, token, PAYERID
Data can service information like
$data = array(
'total' => Total amount,
'invoice_id' => Invoicen number,
'invoice_description' => invoice descrption
);
And items as well which will contain name, price, desc and qty

Related

Laravel: Mollie - webhook failed with status code 500

I'm using the mollie developer setup to simulate payment offers. I've followed a tutorial by my teacher and he hasn't any problems. So what is going on?
Because Mollie is an online service, I'm using Ngrok to create a tunnel for the webhook and my localhost. I'll post my code below but know that I wrote a Log which gave as response:
[2022-07-26 18:22:54] local.ERROR: Method App\Http\Controllers\webHookController::handle does not exist. {"exception":"[object] (BadMethodCallException(code: 0): Method App\Http\Controllers\webHookController::handle does not exist. at C:\Users\stefv\SCHOOL\GENT\NMD\WEBDEV2\werkstuk---geboortelijst-Stef-Verniers\vendor\laravel\framework\src\Illuminate\Routing\Controller.php:68)
I have no clue what exact error this log is targeting so if anyone can point this out, it's much appreciated!
Because the webhook can't get to mollie my status inside my database can't be changed so it's on 'pending' forever...
So I'm looking for a way to fix the error so my webhook can reach Mollie and my payment is accepted so the payment status in my database can change to 'paid'.
This is my code:
My Controller which sets up Mollie:
public function additional(Request $r)
{
$articles = Article::all();
$categories = Category::all();
$websites = Website::all();
$session_id = request()->session()->getId();
$cartItems = Cart::session($session_id)->getContent();
$cartTotal = Cart::session($session_id)->getTotal();
$r->session()->put('cusnaam', 'Cas');
$r->session()->put('tel', 'Tel');
$r->session()->put('email', 'Email');
$r->session()->put('pb', 'pb');
return view('customer-info', compact('articles', 'categories', 'websites', 'cartItems', 'cartTotal'));
}
public function checkout(Request $r)
{
$session_id = request()->session()->getId();
$cartTotal = Cart::session($session_id)->getTotal();
$order = new Order();
$order->name = $r->input('Cus');
$order->note = $r->input('pb');
$order->total = $cartTotal;
$order->status = 'pending';
$order->save();
$mollie = new \Mollie\Api\MollieApiClient();
$mollie->setApiKey("test_6vGchNb62gynePtcsNsbm8dartsmjU");
$mollie->methods->allAvailable();
$session_id = request()->session()->getId();
$cartItems = Cart::session($session_id)->getContent();
$valuta = number_format($cartTotal, 2);
$webhookUrl = route('webhooks.mollie');
if(App::environment('local')) {
$webhookUrl = 'https://5d25-84-199-205-243.eu.ngrok.io/webhooks/mollie';
};
$payment = Mollie::api()->payments->create([
"amount" => [
"currency" => "EUR",
"value" => $valuta // You must send the correct number of decimals, thus we enforce the use of strings
],
"description" => "Bestelling op dag " . date('d-m-Y h:i'),
"redirectUrl" => route('success'),
"webhookUrl" => $webhookUrl,
"metadata" => [
"order_id" => $order->id,
"order_name" => $order->name
],
]);
return redirect($payment->getCheckoutUrl(), 303);
}
public function success()
{
return view('succes');
}
And this is the controller that handles the webhook:
public function handleWebhookNotification(Request $request)
{
$payment = Mollie::api()->payments->get($request->id);
$orderId = $payment->metadata->order_id;
if ($payment->isPaid() && ! $payment->hasRefunds() && ! $payment->hasChargebacks()) {
$order = Order::findOrFail($orderId);
$order->status = 'paid';
$order->save();
Log::alert('tis in de cachoche');
} elseif ($payment->isOpen()) {
/*
* The payment is open.
*/
} elseif ($payment->isPending()) {
/*
* The payment is pending.
*/
} elseif ($payment->isFailed()) {
/*
* The payment has failed.
*/
} elseif ($payment->isExpired()) {
/*
* The payment is expired.
*/
} elseif ($payment->isCanceled()) {
/*
* The payment has been canceled.
*/
} elseif ($payment->hasRefunds()) {
/*
* The payment has been (partially) refunded.
* The status of the payment is still "paid"
*/
} elseif ($payment->hasChargebacks()) {
/*
* The payment has been (partially) charged back.
* The status of the payment is still "paid"
*/
}
}

Laravel WhereNotNull always data missing

I want to ask why when I call the pagination API the "data missing" error message always appears when using whereNotNull.
this is the code that I made.
/**
* Display a listing of the resource.
*
* #return \Illuminate\Http\Response
*/
public function index()
{
$req = $this->request;
$query = DB::table('voucher')->whereNotNull('voucher.type')
->where('type', '!=', '')->select('id', 'type', 'actived_at', 'expired_at', 'created_at');
if ($this->request->has('sort')) {
$sorts = explode(',', $this->request->sort);
foreach ($sorts as $sort) {
list($sortCol, $sortDir) = explode('|', $sort);
$query = $query->orderBy($sortCol, $sortDir);
}
} else {
$query = $query->orderBy('created_at', 'desc');
}
$perPage = $this->request->has('per_page') ? (int) $this->request->per_page : 10;
$pagination = $query->paginate($perPage);
$pagination->appends([
'sort' => $this->request->sort,
'end_to' => $this->request->end_to,
'per_page' => $this->request->per_page
]);
return response()->json(new MP($pagination));
}
in Resource Collection
/**
* Transform the resource into an array.
*
* #param \Illuminate\Http\Request $request
* #return array
*/
public function toArray($request)
{
return [
'hashedId' => Hashids::connection('alternative')->encode($this->id),
'created_at' => Carbon::parse($this->created_at)->format('Y-m-d H:i:s'),
'hour' => $this->getHour($this->actived_at),
'price_type' => $this->type,
'duration' => $this->getDuration($this->actived_at, $this->expired_at),
'actived_at' => $this->actived_at
];
}
public function getHour($value)
{
return Carbon::parse($value)->format('H');
}
public function getDuration($start, $end)
{
$to = Carbon::createFromFormat('Y-m-d H:i:s', $start);
$from = Carbon::createFromFormat('Y-m-d H:i:s', $end);
$duration = $to->diffInMinutes($from);
return $duration;
}
Here I am trying to call the table name again but still "data missing"
Can anyone explain why?
Thanks all.
i hope this help you:
$query->get()
Sorry, all of this is wrong from the code that I made. This "data missing" is because the data that I have haven't totaled ten.
like in this section code.
$perPage = $this->request->has('per_page') ? (int) $this->request->per_page : 10;
if there is a per_page request the value will be returned according to the request, but if not this will be the default request of 10 data

php/symfony: retrieving an attribute in the url for POST/PUT api

For a datatable I use in a page (webix datatable), I have to use a REST API.
My url is for example: http://localhost:8000/trial/1
In this page to make the api call I use the following:
save: "rest->{{ path('api_i_post') }}",
url: "rest->{{ path('erp_interventionapi_get', { trialid: trial.id })
With the GET method, I retrieve for a trial (/trial/1), many interventions which are loaded from a database and filled in the datatable.
With this datatable, I'm able to "add a new row". It uses the POST method (save: "rest->{{ path('api_i_post') }}")
When I add a new row, I'd like to be able to get the field trial_id filled in automatically, depending from where I add a new row in the datatable (for /trial/1, trial_id = 1) but I don't know how to retrieve this attribute (or the trial object id), in a POST and a PUT.
My postAction:
/**
* #Rest\Post("/api_i/", name="api_i_post")
*/
public function postAction(Request $request)
{
$data = new Intervention;
$id = $request->get('id');
$action = $request->get('action');
$daadala = $request->get('daadala');
$date = $request->get('date');
$week = $request->get('week');
$infopm = $request->get('info_pm');
$comment = $request->get('comment');
$location = $request->get('location');
$trial = $request->get('trialid');
$data->setAction($action);
$data->setDaadala($daadala);
$data->setDate($date);
$data->setWeek($week);
$data->setWho($infopm);
$data->setInfoPm($comment);
$data->setComment($location);
$data->setTrial($trial);
$em = $this->getDoctrine()->getManager();
$em->persist($data);
$em->flush();
$lastid = $data->getId();
$response=array("id" => $id, "status" => "success", "newid" => $lastid);
return new JsonResponse($response);
$view = View::create(array("newid" => $lastid, "id" => $id, "status" => "success"));
return $this->handleView($view);
}
And my putAction
/**
* #Rest\Put("/api_i/{id}")
*/
public function putAction(Request $request)
{
$data = new Intervention;
$id = $request->get('id');
$action = $request->get('action');
$daadala = $request->get('daadala');
$date = $request->get('date');
$week = $request->get('week');
$infopm = $request->get('info_pm');
$comment = $request->get('comment');
$location = $request->get('location');
$sn = $this->getDoctrine()->getManager();
$intervention = $this->getDoctrine()->getRepository('ErpBundle:Sponsor')->find($id);
if (empty($intervention)) {
return new View("Sponsor not found", Response::HTTP_NOT_FOUND);
}
$intervention->setAction($action);
$intervention->setDaadala($daadala);
$intervention->setDate($date);
$intervention->setWeek($week);
$intervention->setWho($infopm);
$intervention->setInfoPm($comment);
$intervention->setComment($location);
$sn->flush();
$response=array("id" => $id, "status" => "success");
return new JsonResponse($response);
}
Can you help me with this issue?
Thank you very much
Update of my code after the replys:
I have update this in my twig template:
save: "rest->{{ path('api_i_post', { trialid: trial.id }) }}",
If I look in the profiler of the ajax request, I see it is here:
Key Value
trialid "1"
But I still don't figure how to get it in my post request (the trial_id is still null right now)
I've tried the following:
/**
* #Rest\Post("/api_i/", name="api_i_post")
* #Rest\RequestParam(name="trialid")
*
* #param ParamFetcher $paramFetcher
* #param Request $request
*/
public function postAction(Request $request, ParamFetcher $paramFetcher)
{
$data = new Intervention;
$id = $request->get('id');
$action = $request->get('action');
$daadala = $request->get('daadala');
$date = $request->get('date');
$week = $request->get('week');
$infopm = $request->get('info_pm');
$comment = $request->get('comment');
$location = $request->get('location');
$trial = $paramFetcher->get('trialid');
$data->setAction($action);
$data->setDaadala($daadala);
$data->setDate($date);
$data->setWeek($week);
$data->setWho($infopm);
$data->setInfoPm($comment);
$data->setComment($location);
$data->setTrial($trial);
$em = $this->getDoctrine()->getManager();
$em->persist($data);
$em->flush();
$lastid = $data->getId();
$response=array("id" => $id, "status" => "success", "newid" => $lastid);
return new JsonResponse($response);
$view = View::create(array("newid" => $lastid, "id" => $id, "status" => "success"));
return $this->handleView($view);
}
I guess you are using the FosRestBundle, if so, you can use annotations to retrieve your url parameters :
/**
* #Rest\Put("/api_i/{id}", requirements={"id" = "\d+"})
*/
public function putAction($id)
{
// you now have access to $id
...
}
If you want to allow additionnal parameters for your route but not in the uri, you can use RequestParam with annotations :
/**
* #Rest\Put("/my-route/{id}", requirements={"id" = "\d+"})
*
* #Rest\RequestParam(name="param1")
* #Rest\RequestParam(name="param2")
*
* #param ParamFetcher $paramFetcher
* #param int $id
*/
public function putAction(ParamFetcher $paramFetcher, $id)
{
$param1 = $paramFetcher->get('param1');
....
}
Be sure to check the fosRestBundle documentation to see everything you can do (such as typing the params, making them mandatory or not, etc...)
To get post value you need to do this inside your post action:
public function postAction(Request $request)
{
$postData = $request->request->all();
Then you have an array of value like:
$id = $postData['id'];
For the PUT you need this:
public function putAction(int $id, Request $request)
{
$putData = json_decode($request->getContent(), true);
And then to treieve a value like this:
$id = $putData['id'];

Laravel testing with JWT-Auth

I'm trying to test my api that's made with JWT_auth: https://github.com/tymondesigns/jwt-auth
class UpdateTest extends TestCase
{
use DatabaseTransactions;
public $token;
public function signIn($data = ['email'=>'mail#gmail.com', 'password'=>'secret'])
{
$this->post('api/login', $data);
$content = json_decode($this->response->getContent());
$this->assertObjectHasAttribute('token', $content);
$this->token = $content->token;
return $this;
}
/** #test */
public function a_user_updates_his_account()
{
factory(User::class)->create([
'name' => 'Test',
'last_name' => 'Test',
'email' => 'mail#gmail.com',
'mobile' => '062348383',
'function' => 'ceo',
'about' => 'About me.....',
'corporation_id' => 1
]);
$user = User::first();
$user->active = 2;
$user->save();
$this->signIn();
$url = '/api/user/' . $user->slug . '?token=' . $this->token;
$result = $this->json('GET', $url);
dd($result);
}
}
Result is always:
The token could not be parsed from the request
How do I get this t work!?
Source (https://github.com/tymondesigns/jwt-auth/issues/206)
One way to test your API in this situation is to bypass the actual token verification, but still log your user in (if you need to identify the user). Here is a snippet of the helper method we used in our recent API-based application.
/**
* Simulate call api
*
* #param string $endpoint
* #param array $params
* #param string $asUser
*
* #return mixed
*/
protected function callApi($endpoint, $params = [], $asUser = 'user#example.org')
{
$endpoint = starts_with($endpoint, '/')
? $endpoint
: '/' . $endpoint;
$headers = [];
if (!is_null($asUser)) {
$token = auth()->guard('api')
->login(\Models\User::whereEmail($asUser)->first());
$headers['Authorization'] = 'Bearer ' . $token;
}
return $this->json(
'POST',
'http://api.dev/' . $endpoint,
$params,
$headers
);
}
And is used like this:
$this->callApi('orders/list', [
'type' => 'customers'
])
->seeStatusOk()
Basically, there is not really a way for now. The fake request that is created during testing and is passed to Laravel to handle, somehow drops the token data.
It has alredy been reported in an issue (https://github.com/tymondesigns/jwt-auth/issues/852) but as far as I know, there is no solution yet.

How to collect tweets/retweets using GNIP API in php

Since twitter has switched to streaming his API, we have to collect the data by ourselves.
How we can do it using GNIP API in php?
Answering this, I’ve just wanted to ensure that I’ve done everything right and maybe to improve my TwitterGnipClient class with your help.
But if there are no answers, let it be FAQ style question.
Main methods see below:
/**
* Add rules to PowerTrack stream’s ruleset.
* #example ['id' => 'url', ...]
* #param array $data
*/
public function addRules(array $data)
{
$rules = [];
foreach ($data as $id => $url) {
$rules[] = $this->buildRuleForUrl($url, $id);
}
$this->httpClient->post($this->getRulesUrl(), [
'auth' => [$this->getUser(), $this->getPassword()],
'json' => ['rules' => $rules]
]);
}
/**
* Retrieves all existing rules for a stream.
* #return \Generator
*/
public function getRules()
{
$response = $this->httpClient->get($this->getRulesUrl(), [
'auth' => [$this->getUser(), $this->getPassword()]
]);
$batchStr = '';
$body = $response->getBody();
while (!$body->eof()) {
$batchStr .= $body->read(1024);
}
$batchArray = explode(PHP_EOL, $batchStr);
unset($batchStr);
foreach ($batchArray as $itemJson) {
yield $this->unpackJson($itemJson);
}
}
/**
* Removes the specified rules from the stream.
* #param $data
*/
public function deleteRules($data)
{
$rules = [];
foreach ($data as $id => $url) {
$rules[] = $this->buildRuleForUrl($url, $id);
}
$this->httpClient->delete($this->getRulesUrl(), [
'auth' => [$this->getUser(), $this->getPassword()],
'json' => ['rules' => array_values($rules)]
]);
}
/**
* Open stream through which the social data will be delivered.
* #return \Generator
*/
public function listenStream()
{
$response = $this->httpClient->get($this->getStreamUrl(), [
'auth' => [$this->getUser(), $this->getPassword()],
'stream' => true
]);
$batchStr = '';
$body = $response->getBody();
while (!$body->eof()) {
$batchStr .= $body->read(1024);
$batchArray = explode(PHP_EOL, $batchStr);
// leave the last piece of response as it can be incomplete
$batchStr = array_pop($batchArray);
foreach ($batchArray as $itemJson) {
yield $this->processBroadcastItem($this->unpackJson($itemJson));
}
}
$body->close();
}
/**
* Process broadcast item data
* #param $data
* #return array
*/
protected function processBroadcastItem($data)
{
if (is_array($data)) {
$url = str_replace('url_contains:', '', $data['gnip']['matching_rules'][0]['value']);
switch ($data['verb']) {
// Occurs when a user posts a new Tweet.
case 'post':
return $this->getMappedResponse($url, 'tweet', 1);
break;
// Occurs when a user Retweets another user's Tweet
case 'share':
return $this->getMappedResponse($url, 'retweet', $data['retweetCount']);
break;
}
}
return [];
}
All class I shared as Gist - here
P.S. If you see an evident issue - comment it please.

Categories