Paypal sandbox account response fails on server - php

I'm new to paypal and sandbox, however the algorithm works fine with my on the localhost,
whereas it fails to complete the transaction on remote, I'm using php laravel
the algorithm on my paypal controller :
$request = new OrdersCreateRequest();
$request->prefer('return=representation');
$request->body = [
"intent" => "CAPTURE",
"purchase_units" => [[
"reference_id" => rand(000000,999999),
"amount" => [
"value" => number_format($amount, 2, '.', ''),
"currency_code" => \App\Models\Currency::findOrFail(get_setting('system_default_currency'))->code
]
]],
"application_context" => [
"cancel_url" => url('paypal/payment/cancel'),
"return_url" => url('paypal/payment/done')
]
];
try {
//ddd($request);
// Call API with your client and get a response for your call
$response = $client->execute($request);
// ddd($response);
// If call returns body in response, you can get the deserialized version from the result attribute of the response
return Redirect::to($response->result->links[1]->href);
}catch (HttpException $ex) {
}
When I dump the response it's as :
PayPalHttp\HttpResponse {#2005 ▼
+statusCode: 201
+result: {#2012 ▼
+"id": "29F719283B401012X"
+"intent": "CAPTURE"
+"status": "CREATED"
+"purchase_units": array:1 [▼
0 => {#1944 ▼
+"reference_id": "481922"
+"amount": {#1948 ▼
+"currency_code": "USD"
+"value": "150.00"
}
+"payee": {#1975 ▼
+"email_address": "sb-adxtx19866369#business.example.com"
+"merchant_id": "MUJ4QB7EWSWDJ"
}
}
]
+"create_time": "2022-08-30T10:04:38Z"
+"links": array:4 [▼
0 => {#1949 ▼
+"href": "https://api.sandbox.paypal.com/v2/checkout/orders/29F719283B401012X"
+"rel": "self"
+"method": "GET"
}
1 => {#2017 ▼
+"href": "https://www.sandbox.paypal.com/checkoutnow?token=29F719283B401012X"
+"rel": "approve"
+"method": "GET"
}
2 => {#2010 ▼
+"href": "https://api.sandbox.paypal.com/v2/checkout/orders/29F719283B401012X"
+"rel": "update"
+"method": "PATCH"
}
3 => {#2009 ▼
+"href": "https://api.sandbox.paypal.com/v2/checkout/orders/29F719283B401012X /capture"
+"rel": "capture"
+"method": "POST"
}
]
}
}
and The Exception i get :
PayPalHttp\HttpException
{"name":"UNPROCESSABLE_ENTITY","details": [{"issue":"COMPLIANCE_VIOLATION","description":"Transaction cannot be processed due to a possible compliance violation. To get more information about the transaction, call Customer Support."}],"message":"The requested action could not be performed, semantically incorrect, or failed business validation.","debug_id":"a548bb80c1863","links":[{"href":"https://developer.paypal.com/docs/api/orders/v2/#error-COMPLIANCE_VIOLATION","rel":"information_link","method":"GET"}]}
I've tried multiple ways to resolve it like :
1- Changing the sandbox account region from EGY to US.
2- Changing the entire paypal account.
I would appreciate a little assistance here.
Thanks in advance.

COMPLIANCE_VIOLATION
For sandbox testing: the receiving business account should not be from one of the countries listed here. So, it should work if you try again with e.g. a US receiver account (payer/sending account does not matter)
In the live environment: this answer has more details on the set up needed to receive payments in one of those countries with auto withdrawal to a card or bank.

After a long debugging, the thing turn out to be after the payments. nothing wrong with paypal.
I debugged untill I found the payment status "completed"
After the payment, I update my DB records.
in laravel I used findOrFail($id) method which turns out to be the problem
It fails to find the record, I don't know why however this terminates the logic.
thank you guys.

Related

Symfony unit testing with loginUser(), login not working (returning 302 to login page)

I'm building a test for a Symfony 5.4 application.
I have created a test like this:
public function testCreateProduct() {
$client = static::createClient();
/** #var User $mainAdmin */
$mainAdmin = static::getContainer()->get(UserRepository::class)->find(1);
//$client->catchExceptions(false);
$client->loginUser($mainAdmin);
$crawler = $client->request('GET', '/en/product/new');
$this->assertResponseIsSuccessful();
$this->assertSelectorTextContains('span.username', $mainAdmin->getUsername());
}
But the login is not working, I get a 302 redirect to the login page, and if I set catchExceptions(false) I get an AccessDeniedException.
How can I debug this?
Edit:
I tried to change the patch to a public route, then I did a dd($this->getUser(), $request)
getUser() is null, but the request session contains the user:
#session: Symfony\Component\HttpFoundation\Session\Session {#16616
#storage: Symfony\Component\HttpFoundation\Session\Storage\MockFileSessionStorage {#16631
-savePath: "C:\www\project\var\cache\test/sessions"
#id: "a9d00704e1a0211d06ebddadfaabbf0188e9d65d94faac05afbdc63bb9fb7caa"
#name: "MOCKSESSID"
#started: true
#closed: false
#data: array:3 [
"_sf2_attributes" => &1 array:1 [
"_security_main" => "O:52:"Symfony\Bundle\FrameworkBundle\Test\TestBrowserToken":2:{i:0;s:4:"main";i:1;a:5:{i:0;C:15:"App\Entity\User":118:{a:5:{i:0;i:2;i:1;s:5:"admin";i:2;s:60:"$2y$13$abcdefghi......";i:3;i:1;i:4;b:0;}}i:1;b:1;i:2;N;i:3;a:0:{}i:4;a:9:{i:0;s:9:"ROLE_USER";i:1;s:10:"ROLE_ADMIN";i:2;[...]}}}"
]
"_sf2_meta" => &2 array:3 [
"u" => 1645718565
"c" => 1645718565
"l" => 0
]
"_symfony_flashes" => &3 []
]
I see a difference between
$request->getSession()->getBag('attributes')
done in dev (working) vs in test: in dev I have _security_secured_area, while in test I have _security_main. May this be the reason?
Solved.
Since I was using a custom firewall name in security.yaml, in my case secured_area, I had to pass that as the second parameter of loginUser():
$client->loginUser($mainAdmin, 'secured_area');

Laravel: Redirect with post route

Been trying to find a way to call to pass a multidimensional array to a Post route with no success.
The array looks like this:
"order" => array:16 [
"id" => "1"
"total" => "4825"
"neighborhood" => "Barrio Bravo"
]
"products" => array:2 [
4 => array:4 [
"id" => "4"
"name" => "Maestro Dobel 750ml"
"price" => "530"
"quantity" => "1"
]
1 => array:4 [
"id" => "1"
"name" => "Don Julio 70 700ml"
"price" => "650"
"quantity" => "1"
]
]
"grandTotal" => "1180"
"balanceToPay" => "354"
"cartTotal" => "826"
I don't have any problem asserting the route in the unit test calling the route like so:
$this->post(route('order.success', $orderInfo));
But when it comes to the controller I can't find the way to redirect to order.success with its orderInfo array.
This won't work since redirect only works with GET:
return redirect(route('order.success', $orderInfo));
Ideas?
It's not going to work with a simple redirection because you cannot choose the HTTP method. It's always GET when you make a redirection. It works in your test because you make a POST request manually.
I can see 2 solutions:
You can send data using GET method (they are added as URL parameters). If they are not confidential it can be a solution.
If you don't want to send those data in the URL, you have to save them somewhere and get them from the storage when you're on the order.success page. You can save them, for instance, in the session storage or in the local storage of your browser.
Also, your test isn't good if it tests a behavior that does not happen in your app (post request instead of redirection).

Laravel Validation – Date Format m/y Not Accepting Specific Value

I've got the following validation rules for basic authentication of a Payment Method (advanced things, like CVD validation, existing card, etc. is handled afterward by Moneris).
$rules = [
"type" => "required|in:visa,mastercard",
"nickname" => "required",
"credit_card_number" => "required|numeric|digits:16",
"expiry" => "required|string|size:5|date_format:m/y|after:today",
"cvd" => "required|numeric|digits:3"
];
The rule expiry is not accepting a specific value, 04/yy, but it is accepting 03/yy and 05/yy; I have no idea why this is happening, but I need it remedied. Has anyone come across this behaviour?
For reference, the result dd($request->input(), $validator->passes(), $validator->errors()); when I pass 04/19 is as follows:
array:6 [▼
"type" => "visa"
"nickname" => "Testing"
"credit_card_number" => "4242424242424242"
"expiry" => "04/19"
"cvd" => "123"
"masked_pan" => "************4242"
]
false
MessageBag {#502 ▼
#messages: array:1 [▼
"expiry" => array:1 [▼
0 => "The expiry does not match the format m/y."
]
]
#format: ":message"
}
When I send 05/19, everything works fine:
array:6 [▼
"type" => "visa"
"nickname" => "Testing"
"credit_card_number" => "4242424242424242"
"expiry" => "05/19"
"cvd" => "123"
"masked_pan" => "************4242"
]
true
MessageBag {#502 ▼
#messages: []
#format: ":message"
}
Looks like it's an issue with how this validation rule works in Laravel 5.4. To fix, I check the date validity of the input prepended with 01/, and if it is valid, merge that into the request, with endOfMonth() to handle after:today validation:
$mergeDate = null;
$rawInput = $request->input("expiry");
try {
$mergeDate = Carbon::createFromFormat("d/m/y", "01/".$request->input("expiry"))->endOfMonth();
} catch(\Exception $ex){}
$request->merge([
"masked_pan" => str_repeat("*", 12).substr($request->input("credit_card_number", ""), -4),
"expiry" => $mergeDate ? $mergeDate->format("d/m/y") : $request->input("expiry")
]);
So now, if I pass 04/22, it will check if 01/04/22 is valid, then convert to end of month 30/04/22, then replace that as the value passed to the validation (which also needs to be updated)
"expiry" => "required|string|size:8|date_format:d/m/y|after:today",
I also have to update and pass $messages to avoid confusion to the user:
$messages = [
"expiry.size" => "The :attribute filed must be 5 characters.",
"expiry.date_format" => "The :attribute field does not match the format m/y"
];
$validator = \Validator::make($request->all(), $rules, $messages);
And finally, replace the value with the raw input if there's an error (so the user doesn't see a value they didn't enter)
if(!$validator->passes()){
$request->merge(["expiry" => $rawInput]);
return back()->withErrors($validator)->withInput();
}
A whole bunch of nonsense, but seems to handle 04/22 and other dates just fine.

How to get the ID out of Braintree's JSON response?

I'm trying to integrate PayPal Express Checkout using Braintree SDK.
I can so far charge the Nonce returned from the client and I receive this response. However, I need to take the ID out in order to save it in a table.
My question is how do I parse the id??
Successful {#315
+success: true
-_returnObjectNames: array:1 [
0 => "transaction"
]
#_attributes: []
+"transaction": Transaction {#324
#_attributes: array:63 [
"id" => "xxx"// How do I parse this out?
"status" => "settling"
"type" => "sale"
"currencyIsoCode" => "USD"
"amount" => "6.00"
The variable that holds this JSON is $success. Thus, I tried several things like:
$success->transaction->id
$success->id
If I do $success->success I get true and If I do $success->transaction I get the Transaction object.
Full disclosure: I work at Braintree. If you have any further questions, feel free to contact
support.
If running $success->successreturns True and $success->transaction returns the Transaction object, then you should be able to query the transaction ID using $success->transaction->id, we also demonstrate this in our developer documentation.
$result = $gateway->transaction()->sale([
'amount' => '10.00',
'paymentMethodNonce' => nonceFromTheClient,
'options' => [
'submitForSettlement' => True
]
]);
if ($result->success) {
// See $result->transaction for details
} else {
// Handle errors
}

Send $variable to a view in Laravel 5

I have an $alerts variable array.
Look like this
array:3 [▼
0 => array:3 [▼
"status" => 200
"message" => "Success"
"data" => []
]
1 => array:3 [▼
"status" => 200
"message" => "Success"
"data" => []
]
2 => array:3 [▼
"status" => 404
"error_code" => 35
"message" => "invalid json - api not supported"
]
]
I want to send it from my controller to my view.
I've tried this
controller
return Redirect::to('/account/'.$id)
->with('alerts',$alerts)
Route
My route : http://localhost:8888/account/1007
View
I tried accessing like this
{!!$alerts!!}
Then, I tried accessing it like this, but I kept getting
Undefined variable: alerts
As per the Laravel documentation on redirects, when redirecting using with() it adds the data to the session, and not as a view variable. Therefore, you will need to access it like:
#foreach (session('alerts') as $alert)
<p>{{ $alert['message'] }}</p>
#endforeach
Try this:
Session::flash('alerts', $alerts);
return route('ROUTENAME', $id);
Just change ROUTENAME, in the name of the route (if defined in routes.php).
For example:
Route::get('account/{id}', ['as' => 'account.show', 'uses' => 'AccountController#show']);
In this example, ROUTENAME would be 'account.show'.
In your view you can access it by doing:
Session::get('alerts');
Info:
- http://laravel.com/docs/5.1/session#flash-data
Sometimes you may wish to store items in the session only for the next request. You may do so using the flash method.
You haven't posted the code that actually loads the view. When you return a Redirect->with(...) all you're doing is passing the variable to the next request. In your controller that serves the account/{id} route you need to return view('viewname', ['alerts' => session('alerts')])

Categories