I have a relatively complex array in PHP that needs to be sorted in a specific way but the number of filters and sorts is a bit on the complex side that a simple solution seems to be escaping me.
The Problem: We have products in an order that need to be filtered into "shipto" groups based on the following criteria: Date the product can be shipped, if the product can be grouped with other products, and in which warehouse(s) the product can be shipped from. If 2 products have the same date, warehouse, and allow grouping then they are placed together in the same "shipto".
Current Solution (Not fully realized)
When I extract an order I traverse the items in it and build an array with the following information (FYI, this probably contains more info than I need to solve this problem)
$allProducts = array();
$today = date("Ymd");
/* If the product is being shipped now, put in the Today ShipTo dated 00000000 */
if (($today > $start) && ($today < $end)) {
array_push($allProducts, array('ship' => '00000000', 'defaultwarehouse' => $defaultwarehouse, 'warehouse' => $warehouse, 'group' => $group,'product' => $product, 'start_month' => $start_month, 'start_day' => $start_day, 'end_month' => $end_month, 'end_day' => $end_day, 'description' => $description, 'qty_ordered' => $qty_ordered, 'row_total' => $row_total, 'price' => $price, 'tax_amount' => $tax_amount, 'shipping_group' => $shippingGroup, 'today' => $today, 'end' => $end, 'start' => $start ) );
} else {
/* If the product is not being shipped today, put in a Group that matches the starts date for the ShipTo */
array_push($allProducts, array('ship' => $start, 'defaultwarehouse' => $defaultwarehouse, 'warehouse' => $warehouse, 'group' => $group, 'product' => $product, 'start_month' => $start_month, 'start_day' => $start_day, 'end_month' => $end_month, 'end_day' => $end_day, 'description' => $description, 'qty_ordered' => $qty_ordered, 'row_total' => $row_total, 'price' => $price, 'tax_amount' => $tax_amount, 'shipping_group' => $shippingGroup, 'today' => $today, 'end' => $end, 'start' => $start ));
}
endif;
Where $defaultwarehouse is a number representing the default warehouse (i.e. 1), $warehouse is all of the possible warehouses a product can be in (i.e. 1,2), $start is the date a product can first be shipped (i.e. 20121201 for Dec 1, 2012; Ymd, 00000000 represents today so they can be numerically sorted) and $group is a boolean saying if the product can or can not be shipped with other items (i.e. 1 for yes, 0 for no)
My original idea here was to sort the array based on group, then on warehouse, then on start date. I would then traverse the array to build the "shipto"s and when certain components of the array change (like Warehouse or Start) I would close the previous shipto and start a new one. If I take Group and Multiple Warehouses out of the equation I can get this logic to work. But my task requires I have them in so I am running into the following complications.
First, after I sort by Group, I really want to do 2 sub-sorts of Group=Yes and Group=No for the rest of the filters. This lead me to think that maybe I should be separating the array into 2 arrays and sorting them similarly but separately. It seems inefficient to do it this way but I am not sure.
Second, since warehouse can be a comma separated value, how can I filter on that and get the proper matches. i.e. if I have 3 products where their warehouse value is 1:1,2:3 this should group into 2 shiptos. One for 1:1,2 and a Second for 3.
Thoughts on the problem
My feeling is the way I am thinking about this problem with filtering the items into a traversable array may not be the best way to tackle it. It may be that I need to push the order items individually into a new "Shipments" array that checks each item against all current "Shipments". But I am also not exactly sure on how that would work. Or there may be a different way I am not thinking about at all about how to achieve this.
Example Array Data (Extra Data removed for simplicity):
[0]=>
'ship' => 00000000
'defaultwarehouse' => 1
'warehouse' => 1
'group' => 1
'sku' => 'ABC123'
[1]=>
'ship' => 00000000
'defaultwarehouse' => 1
'warehouse' => 1,2
'group' => 1
'sku' => 'DEF234'
[2]=>
'ship' => 00000000
'defaultwarehouse' => 2
'warehouse' => 1,2
'group' => 1
'sku' => 'GHI567'
[3]=>
'ship' => 20121220
'defaultwarehouse' => 1
'warehouse' => 1,2
'group' => 1
'sku' => 'JKL890'
[4]=>
'ship' => 20121220
'defaultwarehouse' => 1
'warehouse' => 1,2
'group' => 1
'sku' => 'MNO123'
[5]=>
'ship' => 20130401
'defaultwarehouse' => 1
'warehouse' => 1
'group' => 1
'sku' => 'PQR456'
[6]=>
'ship' => 20130401
'defaultwarehouse' => 1
'warehouse' => 1
'group' => 0
'sku' => 'STU789'
This should result in 5 "shipto" groups:
shipto[1] => ABC123, DEF234 (Base "group" for all other comparisons)
shipto[2] => GHI567 (Default warehouse does not match, previous shiptos)
shipto[3] => JKL890, MNO123 (Different shipping date)
shipto[4] => PRQ456 (Different shipping date from all others)
shipto[5] => STU789 (Can not be grouped with other shipments)