-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathBE_Multiple_Packages.php
306 lines (269 loc) · 13 KB
/
BE_Multiple_Packages.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
<?php
class BE_Multiple_Packages
{
const MULTI_PACKAGE_RESTRICTIONS = 'bolder_multi_package_woo_restrictions';
// Singleton instance.
private static $instance;
// The current packages list.
private $packages = array();
/**
* Constructor.
*/
public function __construct()
{
}
// Create a new singleton instance.
public static function get_instance() {
if (!self::$instance) {
self::$instance = new self();
}
return self::$instance;
}
/**
* For each package, find the order lines that contain the products that
* are included in that package, and link those order lines to this
* shipping line.
* The assumption is made that however the packages are grouped, each product
* can only be put into one package (so no grouping by product variation, for
* example).
*
* @order_id int The Order ID in wp_posts
* @shipping_line_id int The ID of the shipping order line that has just been added.
* @package_key int The index number of the package in the WC()->shipping->get_packages() list
*/
public static function link_shipping_line_item($order_id, $shipping_line_id, $package_key)
{
$packages = WC()->shipping->get_packages();
if (!isset($packages[$package_key])) {
return;
}
$package = $packages[$package_key];
$product_ids = array();
foreach($package['contents'] as $product) {
if (!in_array($product['product_id'], $product_ids)) {
$product_ids[] = $product['product_id'];
}
}
// Add the product_ids to the shipping order line, for reference.
wc_add_order_item_meta($shipping_line_id, 'product_ids', $product_ids, true);
// Go through the order lines and find those that contain these product.
$order_line_ids = array();
$order = new WC_Order($order_id);
foreach ($order->get_items() as $order_line_id => $product) {
if (isset($product['product_id']) && in_array($product['product_id'], $product_ids)) {
$order_line_ids[] = $order_line_id;
// Link this product order line to its shipping order line.
wc_add_order_item_meta($order_line_id, 'shipping_line_id', $shipping_line_id, true);
}
}
// Throw the order line IDs onto the shipping line too, for a two-way
// link.
wc_add_order_item_meta($shipping_line_id, 'order_line_ids', $order_line_ids, true);
}
/**
* Get Settings for Restrictions Table
*
* @access public
* @return void
*/
public function generate_packages($packages)
{
if (get_option('multi_packages_enabled')) {
// Reset the packages.
// CHECKME: do we really want to reset the packages, or can
// we just go over the packages as they are, and maybe split
// them out further if necessary?
$package_restrictions = $this->get_package_restrictions();
$free_classes = get_option('multi_packages_free_shipping');
//
$product_meta_prefix = 'product-meta';
// Determine Type of Grouping
$multi_packages_type = get_option( 'multi_packages_type' );
if ($multi_packages_type == 'per-product') {
// separate each item into a package
$n = 0;
foreach ( WC()->cart->get_cart() as $item ) {
if ( $item['data']->needs_shipping() ) {
// Put inside packages
$this->packages[$n] = array(
'contents' => array($item),
'contents_cost' => array_sum(wp_list_pluck(array($item), 'line_total')),
'applied_coupons' => WC()->cart->applied_coupons,
'destination' => array(
'country' => WC()->customer->get_shipping_country(),
'state' => WC()->customer->get_shipping_state(),
'postcode' => WC()->customer->get_shipping_postcode(),
'city' => WC()->customer->get_shipping_city(),
'address' => WC()->customer->get_shipping_address(),
'address_2' => WC()->customer->get_shipping_address_2()
)
);
// Determine if 'ship_via' applies
$key = $item['data']->get_shipping_class_id();
if( $free_classes && in_array( $key, $free_classes ) ) {
$this->packages[$n]['ship_via'] = array('free_shipping');
} elseif (count($package_restrictions) && isset($package_restrictions[$key])) {
$this->packages[$n]['ship_via'] = $package_restrictions[$key];
}
$n++;
}
}
} elseif ($multi_packages_type == 'shipping-class') {
// FIXME: move these $$ variables into arrays to help debugging.
// This section seems to be more complicated than it needs to be,
// just because it tries to keep the index of the packages numeric
// right the way through, rather than just make them numeric at the
// end. It could be simplified a lot.
// Create arrays for each shipping class
$shipping_classes = array();
$other = array();
$get_classes = WC()->shipping->get_shipping_classes();
foreach ( $get_classes as $key => $class ) {
$shipping_classes[ $class->term_id ] = $class->slug;
$array_name = $class->slug;
$$array_name = array();
}
$shipping_classes['misc'] = 'other';
// Group packages by shipping class (e.g. sort bulky from regular)
foreach ( WC()->cart->get_cart() as $item ) {
if ( $item['data']->needs_shipping() ) {
$item_class = $item['data']->get_shipping_class();
if( isset( $item_class ) && $item_class != '' ) {
foreach ($shipping_classes as $class_id => $class_slug) {
if ( $item_class == $class_slug ) {
array_push( $$class_slug, $item );
}
}
} else {
$other[] = $item;
}
}
}
// Put inside packages
$n = 0;
foreach ($shipping_classes as $key => $value) {
if ( count( $$value ) ) {
// Custom elements can be added to this array and be displayed
// in template cart/cart-shipping.php for additional information
// or context.
$this->packages[$n] = array(
// contents is the array of products in the group.
'contents' => $$value,
'contents_cost' => array_sum( wp_list_pluck( $$value, 'line_total' ) ),
'applied_coupons' => WC()->cart->applied_coupons,
'destination' => array(
'country' => WC()->customer->get_shipping_country(),
'state' => WC()->customer->get_shipping_state(),
'postcode' => WC()->customer->get_shipping_postcode(),
'city' => WC()->customer->get_shipping_city(),
'address' => WC()->customer->get_shipping_address(),
'address_2' => WC()->customer->get_shipping_address_2()
)
);
// Determine if 'ship_via' applies
if ( $free_classes && in_array( $key, $free_classes ) ) {
$this->packages[$n]['ship_via'] = array('free_shipping');
} elseif (count($package_restrictions) && isset($package_restrictions[$key])) {
$this->packages[$n]['ship_via'] = $package_restrictions[$key];
}
$n++;
}
}
} elseif (substr($multi_packages_type, 0, strlen($product_meta_prefix)) == $product_meta_prefix) {
// Get the metafield name.
// It can come from the setting in th eplugin admin page, or
// from the package name field, as a suffix.
//
// We hope it is lower-case and with underscores, as that is
// what most packages seem to use, but the WP documentation is
// totally silent on the key format, and in reality anyth string
// is accepted.
if ($multi_packages_type == $product_meta_prefix) {
// A custom meta field key.
$meta_field_name = get_option('multi_packages_meta_field');
} else {
// A pre-defined meta field key.
$meta_field_name = substr($multi_packages_type, strlen($product_meta_prefix));
}
if (!is_string($meta_field_name) || empty($meta_field_name)) {
// If we don't have a string for the field name, then we
// can't move forward.
return $this->packages;
}
// Go over the items in the cart to get the package names.
foreach ( WC()->cart->get_cart() as $item ) {
if ( $item['data']->needs_shipping() ) {
$product_id = $item['product_id'];
$meta_value = get_post_meta($product_id, $meta_field_name, true);
$this->package_add_item($meta_value, $item);
}
}
} elseif ($multi_packages_type == 'per-owner') {
// FIXME: this is 90% duplicated from the previous grouping
// option. Do some refactoring.
// Go over the items in the cart to get the package names.
foreach ( WC()->cart->get_cart() as $item ) {
if ( $item['data']->needs_shipping() ) {
$product_id = $item['product_id'];
if ( isset( $item['data']->post->post_author ) ) {
$post_author = $item['data']->post->post_author;
} else {
$post_author = '-1';
}
$this->package_add_item($post_author, $item);
}
}
}
// The packages will be indexed by package name.
// We actually want it indexed numerically.
return array_values($this->packages);
}
}
/**
* Create a new package if it does not already exist.
* The package_id is a string or number - whatever they are grouped by.
*/
function check_create_package($package_id)
{
// Has this package name been encountered already?
if (!isset($this->packages[$package_id])) {
// No - so create it.
$this->packages[$package_id] = array(
// contents is the array of products in the group.
'contents' => array(),
'contents_cost' => 0,
'applied_coupons' => WC()->cart->applied_coupons,
'package_name' => $package_id,
'destination' => array(
'country' => WC()->customer->get_shipping_country(),
'state' => WC()->customer->get_shipping_state(),
'postcode' => WC()->customer->get_shipping_postcode(),
'city' => WC()->customer->get_shipping_city(),
'address' => WC()->customer->get_shipping_address(),
'address_2' => WC()->customer->get_shipping_address_2()
)
);
}
}
/**
* Add an item to a package.
*/
function package_add_item($package_id, $item)
{
// Make sure the package exists.
$this->check_create_package($package_id);
// Add the item to the package.
$this->packages[$package_id]['contents'][] = $item;
// Add on the line total to the package.
$this->packages[$package_id]['contents_cost'] += $item['line_total'];
}
/**
* Get Settings for Restrictions Table
*
* @access public
* @return void
*/
static function get_package_restrictions() {
return array_filter((array)get_option(BE_Multiple_Packages::MULTI_PACKAGE_RESTRICTIONS));
}
}