Seems like nobody in the last 5 years has tried to get PayPal to work with a Laravel site on PHP so I am forcibly asking now.
I am using this package: https://github.com/srmklive/laravel-paypal
And I am sending PayPal this:
array:6 [▼
"items" => array:2 [▼
0 => array:3 [▼
"name" => "Product 1"
"price" => 9.99
"qty" => 1
]
1 => array:3 [▼
"name" => "Product 2"
"price" => 4.99
"qty" => 2
]
]
"return_url" => "https://github.com/payment/success"
"invoice_id" => "PAYPALDEMOAPP_1"
"invoice_description" => "Order #PAYPALDEMOAPP_1 Invoice"
"cancel_url" => "https://github.com/cart"
"total" => 19.97
]
These values are purely for testing of course but they should work.
However, I get this error:
array:3 [▼
"type" => "error"
"message" => ""
"paypal_link" => null
]
My code looks like this:
public function start()
{
$provider = new ExpressCheckout();
$data = [];
$data['items'] = [
[
'name' => 'Product 1',
'price' => 9.99,
'qty' => 1,
],
[
'name' => 'Product 2',
'price' => 4.99,
'qty' => 2,
],
];
$data['return_url'] = 'https://github.com/payment/success';
$data['invoice_id'] = 'PAYPALDEMOAPP_' . 1;
$data['invoice_description'] = "Order #{$data['invoice_id']} Invoice";
$data['cancel_url'] = 'https://github.com/cart';
// $data['return_url'] = url('/payment/success');
// $data['cancel_url'] = url('/cart');
$total = 0;
foreach($data['items'] as $item) {
$total += $item['price'] * $item['qty'];
}
$data['total'] = $total;
$response = $provider->setExpressCheckout($data);
dd($response);
return redirect($response['paypal_link']);
}
These values are exactly the same as the one used by https://github.com/srmklive/laravel-paypal-demo/
Which is a working demo!
I looked into it further an found where the requests are sent within the package and it sends a POST Request to https://api-3t.sandbox.paypal.com/nvp and when I recreate the request with the same postdata in postman, I get ACK=Failure&L_ERRORCODE0=81002&L_SHORTMESSAGE0=Unspecified%20Method&L_LONGMESSAGE0=Method%20Specified%20is%20not%20Supported&L_SEVERITYCODE0=Error which is what I believe the real error to be.
If anyone could help, that'd be great!
The package you linked to is ancient, 2 generations out of date as far as PayPal APIs go. Don't use it.
Here is the current PHP SDK (not laravel specific): https://github.com/paypal/Checkout-PHP-SDK
It should be used to create two routes on your server, one to 'Set up Transaction', and one to 'Capture Transaction'. Here is a guide: https://developer.paypal.com/docs/checkout/reference/server-integration/
Those 2 routes should be called by this front-end code: https://developer.paypal.com/demo/checkout/#/pattern/server
Double check that credentials are configured correctly.
validate_ssl may also need to be set to false: https://github.com/srmklive/laravel-paypal/issues/229#issuecomment-472755054
Related
I have tried searching for something similar to the question above but no luck.
I have a one to many relationship between a series and videos table. Inside the videos table I have title and url to the video.
The issue i am having is that, i am using jquery to add multiple rows containing title and url.
I tried pushing the title and url to the videos table on the database. There's no problem when pushing one input but when i have many title and url, the code breaks.
I have also tried using createMany but it can only add an array of one input. I can't get it to add both title and url.
$data = \request()->validate([
'title' => 'required',
'vimeo_id' => 'required',
'episode_number' => 'required'
]);
$pricourse->videos()->createMany($data);
After i dd the data in the browser i got the following
array:4 [▼
"_token" => "82k5RnVcdzSkPoOnDYeYipuRqAcJqhXzcWAx3RwW"
"title" => array:2 [▼
0 => "Angles of Elevation"
1 => "English 2"
]
"vimeo_id" => array:2 [▼
0 => "12343"
1 => "12343"
]
"episode_number" => array:2 [▼
0 => "1"
1 => "2"
]
]
Any help will be appreciated..
Thanks
createMany() is the way to go as far as I can understand. You are probably doing it wrong.
Here is an example :
$videosToCreate = [
[
'title' => 'title number 1',
'url' => 'some url number 1'
],
[
'title' => 'title number 2',
'url' => 'some url number 2'
],
[
'title' => 'title etc...',
'url' => 'some url etc...'
]
];
$this->videos()->createMany($videosToCreate);
We cannot help you if you do not share any code though.
I discovered i was not passing the data from the hmtl page properly. I made a few changes to it.
<input type="text" name="videos[0][title]">
<input type="text" name="videos[0][vimeo_id]">
<input type="text" name="videos[0][episode_number]">
<input type="text" name="videos[1][title]">
<input type="text" name="videos[1][vimeo_id]">
<input type="text" name="videos[1][episode_number]">
My controller code goes below
$data = \request()->validate([
'videos.*.title' => 'required',
'videos.*.vimeo_id' => 'required',
'videos.*.episode_number' => 'required'
]);
$pricourse->videos()->createMany($data['videos']);
All i had to do was pass $data['videos'] inside createMany
Thank you all for your help. It served as a pointer
I've been trying to discover whether or not it's currently possible to do the following.
Basically I have three models: Customer, Invoice, and Unit. (Customer has one Invoice; an Invoice has many Units).
I was wondering if it was possible to seamlessly do the following:
...
# Let's pretend that further up the code that
# Customer has all the properties set and now
# being saved in the database.
$Customer->save();
# This is currently trying set the values of
# 'units' to a non-existent table column in
# 'invoices' table.
$Customer->invoice()->create([
"units" => [
[
"name" => "Unit 1",
"amount" => 999.99,
"tax" => "20%",
"type" => "+"
]
]
]);
If you setup the relationships in the model as you described them, then you can achieve it close to what you've shown. Something like this:
Customer
public function invoice()
{
return $this->hasOne(Invoice::class);
}
Invoice
public function units()
{
return $this->hasMany(Unit::class);
}
Then calling:
$customer->invoice()->units()->create([
"name" => "Unit 1",
"amount" => 999.99,
"tax" => "20%",
"type" => "+"
]);
Should work.
If you setup the relationships in the model as you described them, then you can achieve it close to what you've shown. Something like this:
Customer
public function invoice()
{
return $this->hasOne(Invoice::class);
}
Invoice
public function units()
{
return $this->hasMany(Unit::class);
}
Then calling:
$customer->invoice()->units()->create([
"name" => "Unit 1",
"amount" => 999.99,
"tax" => "20%",
"type" => "+"
]);
Should work.
if you call save on the invoice first, then you should just call $invoice->units()
$invoice = $customer->invoice()->create([
"campany" => "Unit 1",
"dat" => "2022-02-18"
]);
$invoice->units()->create([
"name" => "Unit 1",
"amount" => 999.99,
"tax" => "20%",
"type" => "+"
]);
... instead of doing it through the Customer. so $invoice = $customer->invoice()->create(...); before, and then add units.
The Setup
Using the Reviews extension for WP Job Manager, I have comments with the meta field review_average which is an average of `review_stars. I'm customizing the WP REST API so I can read and write comments remotely via the mobile app I'm building.
I've exposed these fields with
register_meta( 'comment', 'review_average', array( 'show_in_rest' => true,
'type' => 'string',
'description' => 'review_average',
'single'=> false));
register_meta( 'comment', 'review_stars', array( 'show_in_rest' => true,
'type' => 'string',
'description' => 'review_stars',
'single'=> false));
which results in this field in the REST API response for comments:
meta: {
review_average: [
"4"
],
review_stars: [
"Array"
]
},
(I can't seem to break down that array, but there's only one stars category so the average is fine)
I've written a create_review function that uses add_comment_meta to write to review_average and review_stars which successfully gives the comment the right stars. Both those meta values are required for it to work.
function create_review($param) {
$id = wp_insert_comment(array('comment_post_ID' => $param['post_id'],
'comment_author' => $param['username'],
'comment_author_email' => $param['email'],
'user_id' => $param['user_id'],
'comment_content' => $param['content']));
if ($id) add_comment_meta($id, 'review_average', $param['rating']);
if ($id) add_comment_meta($id, 'review_stars', array('Your Rating'=>$param['rating']));
return get_comment($id);
}
The Problem
I can't seem to get the ratings meta info into a response for the comments. On my way to writing the "index" function get_comments, I've written the "show" function, get_commment:
function get_review($param) {
$id = $param['id'];
$info = get_comment($id);
$res = array(
'id' => $id,
'author_name' => $info->comment_author,
'author_email' => $info->comment_author_email,
'author_id' => $info->user_id,
'date' => $info->comment_date,
'rating' => $info->review_average
);
return $res;
}
The response has rating: null. Same result with 'rating' => $info->meta->review_average, as well as using _review_average in both those scenarios.
I have another function for my custom posts, which are job_listings that in my app are customers.job_listing has a meta field that shows up in the default REST API response under meta as _job_location, but inside my get_customer function, $res['address'] = $info->_job_location; works just fine!
How do I get the damn rating_average meta!?
Well, 'rating' => get_comment_meta($id) inside my get_review method gives me this:
"rating": {
"review_average": [
"4"
],
"review_stars": [
"a:1:{s:11:\"Your Rating\";s:1:\"4\";}"
]
}
And then
'rating' => get_comment_meta($id)['review_average'][0],
'rating_info' => get_comment_meta($id),
Gives me a nice full
"rating": "4",
"rating_info": {
"review_average": [
"4"
],
"review_stars": [
"a:1:{s:11:\"Your Rating\";s:1:\"4\";}"
]
}
I'm learning php as I go, so I'd love if someone could post a comment about why
get_comment_meta($id)->review_average
returns null but
get_comment_meta($id)['review_average']
works.
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.
i want to make a laravel validator that validates the the fields inside an un-named array ( 0,1,2,3 ) that is inside an array
so my array is like
array [ //the form data
"items" => array:2 [ //the main array i want to validate
0 => array:2 [ // the inner array that i want to validate its data
"id" => "1"
"quantity" => "1000"
]
1 => array:2 [
"id" => "1"
"quantity" => "1000"
]
// other fields of the form,
]
]
so what i want is something like
$validator = Validator::make($request->all(), [
'items.*.id' => 'required' //notice the star *
]);
Laravel 5.2
The syntax in the question is now supported
http://laravel.com/docs/master/validation#validating-arrays
Laravel 5.1
First create the validator with all of your other rules. Use the array rule for items
$validator = Validator::make($request->all(), [
'items' => 'array',
// your other rules here
]);
Then use the Validator each method to apply a set of rules to every item in the items array.
$validator->each('items', [
'id' => 'required',
'quantity' => 'min:0',
]);
This will automatically set these rules for you...
items.*.id => required
items.*.quantity => min:0
https://github.com/laravel/framework/blob/5.1/src/Illuminate/Validation/Validator.php#L261
You could simply do something like that:
$rules = [];
for($i = 0; $i < 10; $i++) {
$rules["items.$i.id"] = "required";
}
$validator = \Validator::make($request->all(), $rules);