I'm integrating a paypal payment method on my website, I got it all running just fine, I'm stuck at the point were paypal sends me to my return URL with information about the customer and items purchased.
I get this following structure on the confirmation array
Array
(
some customer info
...
[L_NAME0] => Frame%20Rojo
[L_NAME1] => External%20Hard%20Disk
[L_NUMBER0] => PD1002
[L_NUMBER1] => PD1003
[L_QTY0] => 1
[L_QTY1] => 1
[L_TAXAMT0] => 0%2e00
[L_TAXAMT1] => 0%2e00
[L_AMT0] => 29%2e00
[L_AMT1] => 100%2e00
...
)
What I'm interested is in saving the whole item list, quantities and prices to my database so I can later keep track of what's been sent and what not.
My issue here is that as you can see, paypal returns to me a set of values that are names "something+n" (L_NUMBER0 and so on), so, I can't just set up a table on my DDBB as I don't know how many items would an user get. I could save it on 2 tables: purchase and items_per_purchase like structure, but I still face the issue of parsing that array.
What would be the best way to run through it and see how many items per purchase there are to save?
I thought of some kind of bucle wich sees:
while(if(isset($_GET['L_NUMBER'.$cont]))) {
// save to ddbb
L_NAME.$cont
L_NUMBER.$cont
...
cont++
}
... and increment some counter but I would like to know if there's a better solution.
I think your solution is fine, though you don't need an if inside the while test...
$cont = 0;
while (isset($_GET['L_NUMBER' . $cont])) {
// save to database after assembling array keys as follows...
// L_NAME . $cont
// L_NUMBER . $cont
// etc.
cont++;
}
And you should never trust input from $_GET. I recommend using parameterized queries with PDO.
Related
I am facing a problem to add such a product to the cart.
I manage to create the booking with:
$new_booking = get_wc_booking ($new_booking_data);
$new_booking -> create ($status);
But then I tried to apply these different methods without success:
add_cart_item_data ($cart_item_meta, $product_id); // error 500
or
$ new_booking_object -> add_cart_item ($cart_item_meta); // error 500
The $cart_item_meta object I create is like the following (some keys are duplicative, like for example start and start_date, because I observed in the code that both names are used, and I wanted to be sure to send at least the correct one ;-) ). BTW, by comparing with standard bookings created via the plugin form, I can be sure that the values I set in the array have the correct format.
$cart_item_meta = array(
'all_day' => false,
'cost' => $price,
'customer_id' => 1,
'user_id' => 1,
'date_created' => '',
'date_modified' => '',
'end' => $endDate,
'end_date' => $endDate,
'google_calendar_event_id' => 0,
'order_id' => $order->get_id(),
'order_item_id' => 0,
'parent_id' => 0,
'person_counts' => array($addPaxId => $pax),
'persons' => array($addPaxId => $pax),
'product_id' => $prodId,
'resource_id' => $resourceId,
'start' => $startDate,
'start_date' => $startDate,
'status' => 'in-cart',
'local_timezone' => 'Europe/Brussels',
);
I do get a record in the "posts" table, with the same specifics as a normal booking created by the normal way. In particular, I get post_type = wc_booking, and post_status = in-cart. But the cart remains empty.
I have compared all the entries in the database, and I can't see what is missing. But I'm definitely missing some of the understanding of the mechanics of WooCommerce ...
Does someone can help me to find a way to pass the final step: putting the created booking in the cart ? Thanks!
Well, maybe someone will be interested to know how I worked around, as so far I couldn't find a complete programming solution.
The products I want to book programmatically and add to the cart are existing products in my WooCommerce store. My purpose is just to use my own form to allow the customer to better understand what he books (I'm managing a flight simulators center with several machines), and the native WC Bookings form is not clear enough for me, and moreover it is really heavy and slow.
So after gathering customers info with my own form (simulator, duration, participants, timeslot), my problem was to put all this in the cart. I could achieve to create the relevant booking in the database, but not add it to the cart.
I observed that when you book via the standard form, you send a POST to the server on the same product page, including the following parameters (random data for example):
wc_bookings_field_persons_xxxx => 2 // 'xxxx' is the ID of the related 'bookable_person' in 'posts'
wc_bookings_field_start_date_month => 11 // November (sample)
wc_bookings_field_start_date_day => 26 // the 26th (sample)
wc_bookings_field_start_date_year => 2021 // Year (sample)
wc_bookings_field_start_date_time => 2021-11-26T15:00:00+0100
wc_bookings_field_start_date_local_timezone => Europe/Brussels
add-to-cart => 1147 // the product ID in 'posts'
So the simplest solution is to create a POST call (via form + button or button + ajax), setting the action/ajax url to the related product after filling the fields here above with the custom form...
EDIT: while I was thinking this was the solution, I discovered that it worked only when another tab in my browser previously 'opened the door' by adding the same product in the standard way. But when this tab is closed (or timeout), the above method fails and just open the product page. The 302 redirect that was operating stops to work for un unknown reason, and we get the standard 200 straight forward. No Cart.
So the question is still pending.
Summary:
Google_Service_Calendar seems to be "force-paginating" results of $service->events->listEvents();
Background:
google calendar API v3,
using php client library
We are developing a mechanism to sync our internal calendar with a user's google calendar.
Please note I will refer below to $x, which represents google's default limit on the number of events, similar to $options['maxResults']; The default value is 250, but it should not matter: we have tested the below with and without explicitly defined request parameters such as 'maxResults', 'timeMin', and 'timeMax' - the problem occurs in all cases.
Another relevant test we did: export this calendar to foobar.ics, created a new gmail user form scratch, import foobar.ics to newuser#gmail.com. DOES NOT REPLICATE THIS ISSUE. We have reviewed/reset various options in the subject calendar (sharing, etc) but cannot find any setting that has any effect.
The Problem:
Normally, when we call this:
$calendar='primary';
$optParams=array();
$events = $this->service->events->listEvents($calendar, $optParams);
$events comes back as a Google_Service_Calendar_Events object, containing $n "items". IF there are more than $x items, the results could be paginated, but the vanilla response (for a 'normal', result set with ( count($items) < $x ) ) is a single object, and $events->nextPageToken should be empty.
One account we are working with (of course, the boss's personal account) does not behave this way. The result of:
$events = $this->service->events->listEvents('primary', []);
is a Google_Service_Calendar_Events object like this:
Google_Service_Calendar_Events Object
(
[accessRole] => owner
[defaultRemindersType:protected] => Google_Service_Calendar_EventReminder
[defaultRemindersDataType:protected] => array
[description] =>
[etag] => "-kakMffdIzB99fTAlD9HooLp8eo/WiDS9OZS7i25CVZYoK2ZLLwG7bM"
[itemsType:protected] => Google_Service_Calendar_Event
[itemsDataType:protected] => array
[kind] => calendar#events
[nextPageToken] => CigKGmw5dGh1Mms4aWliMDNhanRvcWFzY3Y1ZGkwGAEggICA6-L3lrgUGg0IABIAGLig_Zfi278C
[nextSyncToken] =>
[summary] => example#mydomain.com
[timeZone] => America/New_York
[updated] => 2014-07-23T15:38:50.195Z
[collection_key:protected] => items
[modelData:protected] => Array
(
[defaultReminders] => Array
(
[0] => Array
(
[method] => popup
[minutes] => 30
)
)
[items] => Array
(
)
)
[processed:protected] => Array
(
)
)
Notice that $event['items'] is empty, and nextPageToken is not null. If we then do a paginated request like this:
while (true) {
$pageToken = $events->getNextPageToken();
if ($pageToken) {
$optParams = array('pageToken' => $pageToken);
$events = $this->service->events->listEvents($calendar, $optParams);
if(count($events) > 0){
h2("Google Service returned total of ".count($events)." events.");
}
} else {
break;
}
}
The next result set gives us the events. In other words, the google service seems to be paginating the initial results, despite the fact that we are certain the result is less than $x.
To be clear, if we have 5 events on our calendar, we expect 1 result with 5 items. Instead, we get 1 result with 0 items, but the first result of the 'nextPageToken' logic gives us the desired 5 items.
Solution Ideas?:
A. handle paginated results, and/or "Incremental Syncronization'. These are on our list of features to implement, but we consider these to be more 'optimization' than 'necessity'. In other words, I understand that handling/sending nextSyncToken and nextPageToken are OPTIONAL- thus the issue we are having should not depend on our client code doing this.
B. use a different, non-primary calendar for this user. we think this particular primary calendar may corrupt or somehow cached on google's side: to be fair, we did at one point accidentally insert a bunch of junk events on this calendar to the point that google put us in read-only mode as described here: https://support.google.com/a/answer/2905486?hl=en but we understand that was a temporary result of clunky testing.... In other words, we know we HAD screwed this calendar up badly, but this morning we deleted ALL events, added a single test event, and got the same result as above FOR THIS CALENDAR. Cannot replicate for any other user.... including a brand new gmail user.
C. delete the 'primary' calendar, create a new one. Unfortunately, we understand it is not possible to delete the primary CALENDAR, only to delete the CALENDAR EVENTS.
D. make the boss open a brand new google account
Any other suggestions? We are proceeding with A, but even that is a band-aid to the problem, and does not answer WHY is this happening? How can we avoid it in the future? (Please don't say "D")
Thanks in advance for any advice or input!
There is a maximum page size, if you don't specify one yourself there is an implicit one (https://developers.google.com/google-apps/calendar/v3/pagination). Given this it's necessary to implement pagination for your app to work correctly.
As you noticed, a page does not always contain the maximum number of results so pagination is important even if the number of events does not exceed the page size. Just keep following the page tokens and it will eventually give you all the results (there will be a page with no nextPageToken)
TL;DR A :)
I need to be able to store the $_POST data from a form (I'm doing that with the SESSION variable) and I need to add data to the $_POST array without overwriting the previous data.
Here's my original thread about the SESSION variables: Store Array Variables Through Page Refresh with PHP
Here's an example of what I need to do:
There's a form on a page that you can put the width and height of a wall to calculate out how much paint/labor would be needed to paint the walls. Once the first wall dimensions are entered, the user can click the submit button labeled "Add Wall" to add another wall to their order.
After the first wall input, the POST data would return something like this:
Array ( [wallW] => Array ( [0] => 9 ) [wallL] => Array ( [0] => 10 ) )
After the second wall is entered it would look something like this:
Array ( [wallW] => Array ( [0] => 9 [1] => 20 ) [wallL] => Array ( [0] => 10 [1] => 15 ) )
This would continue on until the user has entered all of their walls.
I've tried doing array_merge, array_append, etc, but none of those seem to be working; it keeps overwriting what's tin the POST data, even if I bring the POST data into another array.
I know the easy thing would be to throw some jQuery in there, but this is for a PHP class (and we're not allowed to use SQL yet) so I'd like to try to figure this out with just PHP.
Any help would be awesome.
Thanks,
Chelsea
I don't know why this has been downvoted, i find it rude as you are obviously new to php. But you just need to re-post your post vars in subsequent requests. So you would need to serialize you existing post objects as perhaps hidden fields. What you are missing is that php / http is stateless. So nothing is preserved between requests, another easy solution may be to move these POST variables to SESSION variables.
I see you've added the POST data to the session, but there is no reason to add it back to post, just keep appending to session and then use it from there. adding things to _POST wont force them to be posted next time if thats you are trying todo, see the part about serializing them to hidden fields.
Good luck, welcome to programming for the web.
The way you are constructing array seems little odd to me. Instead I would do something like.
if(!empty($_POST))
{
$wall = array('w' => $_POST['w'], 'h' => $_POST['h']);
$_SESSION['walls'][] = $wall;
}
Please give this a try.
I’ve been scratching my head for days on this one. Any help or a push in the right direction would be greatly appreciated.
I’ve extended the sales report under Reports->Sales->Orders and created my own custom filters to filer the report by channels.
Each order has a ‘channel_name’ attribute to identify whether the order came from eBay, Amazon, etc.
Now I cannot for the life of me figure out how sales/order_aggregated_created table that is used to generate the reports is created. Where does the magic happen? I want to add ‘channel_name’ to the order_aggregated_created table to be able to filter by this attribute, but I cannot figure out how to this.
Diagram for order_aggregated_created table with its attributes:
http://www.magento-exchange.com/wp-content/uploads/2010/11/MAGENTO-SALES-ORDER-ER.png
Mage_Sales_Model_Resource_Report_Order_Collection is where the magic starts in retrieving the sales totals, particularly if I understood this correctly inside
protected function _getSelectedColumns(){...}
if (!$this->isTotals()) {
$this->_selectedColumns = array(
'period' => $this->_periodFormat,
'orders_count' => 'SUM(orders_count)',
'total_qty_ordered' => 'SUM(total_qty_ordered)',
'total_qty_invoiced' => 'SUM(total_qty_invoiced)',
'total_income_amount' => 'SUM(total_income_amount)',
'total_revenue_amount' => 'SUM(total_revenue_amount)',
'total_profit_amount' => 'SUM(total_profit_amount)',
'total_invoiced_amount' => 'SUM(total_invoiced_amount)',
'total_canceled_amount' => 'SUM(total_canceled_amount)',
'total_paid_amount' => 'SUM(total_paid_amount)',
'total_refunded_amount' => 'SUM(total_refunded_amount)',
'total_tax_amount' => 'SUM(total_tax_amount)',
'total_tax_amount_actual' => 'SUM(total_tax_amount_actual)',
'total_shipping_amount' => 'SUM(total_shipping_amount)',
'total_shipping_amount_actual' => 'SUM(total_shipping_amount_actual)',
'total_discount_amount' => 'SUM(total_discount_amount)',
'total_discount_amount_actual' => 'SUM(total_discount_amount_actual)',
);
}
If would be awesome if I can just ‘channel_name’ =>$this->_channelName, and be on my merry way.
After a lot and lot of research it turns out that sales/order_aggregated_created table gets generated in here:
Mage_Sales_Model_Resource_Report_Order_Createdat
now I've looked here before seemed like exactly what I needed, but any changes I made would not reflect in Magento reports especially inside the sales/order_aggregated_created table.
I found out that Mage_Sales_Model_Resource_Report_Order_Createdat only gets called when you refresh the statistics inside Reports->Sales->Orders, only then a NEW sales/order_aggregated_created table is generated! So for anyone looking to filter the order sales report by a custom attribute, look inside: /app/code/core/Mage/Sales/Model/Resource/Report/Order/Createat.php
I have an application that generates an array of statistics based on a greyhounds racing history. This array is then used to generate a table which is then output to the browser. I am currently working on creating a function that will generate an excel download based on these statistics. However, this excel download will only be available after the original processing has been completed. Let me explain.
The user clicks on a race name
The data for that race is then processed and displayed in a table.
Underneath the table is a link for an excel download.
However, this is where I get stuck. The excel download exists within another method within the same controller like so...
function view($race_id) {
//Process race data and place in $stats
//Output table & excel link
}
function view_excel($race_id) {
//Process race data <- I don't want it to have to process all over again!
//Output excel sheet
}
As you can see, the data has already been processed in the "view" method so it seems like a massive waste of resources having it processed again in the "view_excel" method.
Therefore, I need a method of transferring $stats over to the excel method when the link is clicked to prevent it having to be reproduced. The only methods I can think of are as follows.
Transferring $stats over to the excel method using a session flash
The variable may end up being too big for a session variable. Also, if for some reason the excel method is refreshed, the variable will be lost.
Transferring $stats over to the excel method using an ordinary session variable
As above, the variable may end up being too big for a session variable. This has the benefit that it wont be lost on a page refresh but I'm not sure how I would go about destroying old session variables, especially if the user it processing alot of races in a short period of time.
Storing $stats in a database and retrieving it in the excel method
This seems like the most viable method. However, it seems like a lot of effort to just transfer one variable across. Also, I would have to implement some sort of cron job to remove old database entries.
An example of $stats:
Array
(
[1] => Array
(
[fcalc7] =>
[avgcalc7] =>
[avgcalc3] => 86.15
[sumpos7] =>
[sumpos3] => 9
[sumfin7] =>
[sumfin3] => 8
[total_wins] => 0
[percent_wins] => 0
[total_processed] => 4
[total_races] => 5
)
[2] => Array
(
[fcalc7] => 28.58
[avgcalc7] => 16.41
[avgcalc3] => 28.70
[sumpos7] => 18
[sumpos3] => 5
[sumfin7] => 23
[sumfin3] => 7
[total_wins] => 0
[percent_wins] => 0
[total_processed] => 7
[total_races] => 46
)
[3] => Array
(
[fcalc7] => 28.47
[avgcalc7] => 16.42
[avgcalc3] => 28.78
[sumpos7] => 28
[sumpos3] => 11
[sumfin7] => 21
[sumfin3] => 10
[total_wins] => 0
[percent_wins] => 0
[total_processed] => 7
[total_races] => 63
)
)
Would be great to hear your ideas.
Dan
You could serialize the array into a file in sys_get_temp_dir() with a data-dependet file name. The only problem left is cleaning up old files.
Putting it into the database is also possible as you said, and deleting old data is easier than on the file system if you track the creation time.