PluginProbe
AliNext – WooCommerce Dropshipping Plugin for AliExpress / trunk
AliNext – WooCommerce Dropshipping Plugin for AliExpress vtrunk
ali2woo-lite / includes / classes / controller / FrontendInitController.php

FrontendInitController.php in AliNext – WooCommerce Dropshipping Plugin for AliExpress trunk, at includes/classes/controller/FrontendInitController.php

575 lines 21.9 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 /**
4 * Description of FrontendInitController
5 *
6 * @author Ali2Woo Team
7 *
8 * @autoload: init
9 *
10 * @ajax: true
11 */
12
13 // phpcs:ignoreFile WordPress.Security.NonceVerification.Recommended
14
15 namespace AliNext_Lite;;
16
17 use WC_Customer;
18 use WC_Shipping_Rate;
19 use WC_Tax;
20
21 class FrontendInitController extends AbstractController
22 {
23 protected WoocommerceService $WoocommerceService;
24 protected ImportedProductServiceFactory $ImportedProductServiceFactory;
25 protected ProductService $ProductService;
26
27
28 public function __construct(
29 WoocommerceService $WoocommerceService,
30 ImportedProductServiceFactory $ImportedProductServiceFactory,
31 ProductService $ProductService,
32 ) {
33 parent::__construct();
34
35 $this->WoocommerceService = $WoocommerceService;
36 $this->ImportedProductServiceFactory = $ImportedProductServiceFactory;
37 $this->ProductService = $ProductService;
38
39 add_action('wp_ajax_a2wl_frontend_load_shipping_info', [$this, 'ajax_frontend_load_shipping_info']);
40 add_action('wp_ajax_nopriv_a2wl_frontend_load_shipping_info', [$this, 'ajax_frontend_load_shipping_info']);
41
42 add_filter('wcml_multi_currency_ajax_actions', [$this,'add_action_to_multi_currency_ajax'], 10, 1);
43
44 add_action('wp_ajax_a2wl_frontend_update_shipping_list', [$this, 'ajax_frontend_update_shipping_list']);
45 add_action('wp_ajax_nopriv_a2wl_frontend_update_shipping_list', [$this, 'ajax_frontend_update_shipping_list']);
46
47 $shippingOnCheckoutPage = get_setting(Settings::SETTING_ALLOW_SHIPPING_FRONTEND) &&
48 get_setting(Settings::SETTING_DELIVERY_INFO_DISPLAY_MODE) === 'default';
49
50 $shippingOnProductPage = $shippingOnCheckoutPage &&
51 get_setting(Settings::SETTING_SHIPPING_ON_PRODUCT_PAGE);
52
53 if ($shippingOnCheckoutPage) {
54 add_action(
55 'wp_ajax_a2wl_update_shipping_method_in_cart_item',
56 [$this, 'ajax_frontend_update_shipping_method_in_cart_item']
57 );
58 add_action(
59 'wp_ajax_nopriv_a2wl_update_shipping_method_in_cart_item',
60 [$this, 'ajax_frontend_update_shipping_method_in_cart_item']
61 );
62
63 if ($shippingOnProductPage) {
64 add_action('woocommerce_add_to_cart_validation', array($this, 'product_shipping_fields_validation'), 10, 3);
65 add_filter('woocommerce_add_cart_item_data', array($this, 'add_cart_item_data'), 10, 2);
66
67 //set country to the last added (to cart) item
68 add_action('woocommerce_add_to_cart', array($this, 'set_default_cart_country'), 10, 6);
69 }
70
71 //calculate shipping total in the cart and checkout page
72 add_filter('woocommerce_package_rates', [$this, 'woocommerce_package_rates'], 10, 2);
73
74 /**
75 * this hook is fired on frontend and backend.
76 * show shipping information on the order edit page (admin) and do not show on frontend for user (complete order page)
77 * also do not show in the customers emails
78 */
79 add_filter('woocommerce_order_item_get_formatted_meta_data',
80 [$this, 'woocommerce_order_item_get_formatted_meta_data'], 10, 2
81 );
82 }
83
84 }
85
86 function add_action_to_multi_currency_ajax($ajax_actions)
87 {
88 $ajax_actions[] = 'a2wl_frontend_load_shipping_info';
89
90 return $ajax_actions;
91 }
92
93 /**
94 * Get shipping info for shipping popup or drop-down selection on the detailed product page
95 * @return void
96 */
97 public function ajax_frontend_load_shipping_info(): void
98 {
99 check_admin_referer(self::AJAX_NONCE_ACTION, self::NONCE);
100
101 if (empty($_POST['id']) || intval($_POST['id']) < 0) {
102 echo wp_json_encode(ResultBuilder::buildError("Missing product ID..."));
103 }
104
105 if (!empty($_POST['variation_id']) && intval($_POST['variation_id']) <= 0) {
106 echo wp_json_encode(ResultBuilder::buildError("Illegal product variation ID..."));
107 }
108
109 $countryToCode = isset($_POST['country']) ? wc_clean(wp_unslash($_POST['country'])) : "";
110
111 $quantity = 1;
112 if (!empty($_POST['quantity'])) {
113 $quantity = intval($_POST['quantity']);
114 }
115
116 if (!$countryToCode) {
117 echo wp_json_encode(ResultBuilder::buildError("Country is required."));
118 wp_die();
119 }
120
121 $wcProductId = intval($_POST['id']);
122 $wcVariationId = null;
123 if (!empty($_POST['variation_id']) && intval($_POST['variation_id']) > 0) {
124 $wcVariationId = intval($_POST['variation_id']);
125 }
126
127 $countries = Shipping::get_countries();
128
129 $country_label = $countries[$countryToCode];
130
131 $page = "cart";
132
133 if (isset($_POST['page'])) {
134 if ($_POST['page'] == "product") {
135 $page = "product";
136 }
137 }
138
139 if ($page == "product" && get_setting('aliship_not_available_remove')) {
140 //if this product page and option is enabled we use a separate not available message
141 $shipping_info = str_replace(
142 '{country}', $country_label, get_setting('aliship_product_not_available_message')
143 );
144
145 } else {
146 $shipping_info = Shipping::get_not_available_shipping_message($country_label);
147 }
148
149 $normalized_methods = [];
150
151 $type = "select";
152
153 if (isset($_POST['type'])) {
154 if ($_POST['type'] == "popup") {
155 $type = "popup";
156 }
157 }
158
159 $WC_ProductOrVariation = wc_get_product($wcProductId);
160 if (!$WC_ProductOrVariation) {
161 echo wp_json_encode(ResultBuilder::buildError("Bad product ID"));
162 wp_die();
163 }
164
165 if ($wcVariationId) {
166 $WC_ProductOrVariation = wc_get_product($wcVariationId);
167 if (!$WC_ProductOrVariation) {
168 echo wp_json_encode(ResultBuilder::buildError("Bad product variation ID"));
169 wp_die();
170 }
171 }
172
173 try {
174
175 $countryFromCode = $this->WoocommerceService->getShippingFromByProduct($WC_ProductOrVariation);
176 $importedProduct = $this->WoocommerceService->updateProductShippingItems(
177 $WC_ProductOrVariation,
178 $countryToCode,
179 $countryFromCode,
180 $quantity
181 );
182
183 $shippingItems = $this->ProductService->getShippingItems(
184 $importedProduct, $countryToCode, $countryFromCode
185 );
186 } catch (RepositoryException $RepositoryException) {
187 a2wl_error_log($RepositoryException->getMessage());
188
189 echo wp_json_encode(ResultBuilder::buildError(
190 'Can`t get product shipping')
191 );
192
193 wp_die();
194 } catch (ServiceException $ServiceException) {
195 a2wl_error_log($ServiceException->getMessage());
196 $shippingItems = [];
197 }
198
199 foreach ($shippingItems as $method) {
200 $normalized_method = Shipping::get_normalized($method, $countryToCode, $type);
201 if (!$normalized_method) {
202 continue;
203 }
204 $normalized_methods[] = $normalized_method;
205 }
206
207 echo wp_json_encode(ResultBuilder::buildOk([
208 'products' => [
209 'product_id' => $WC_ProductOrVariation->get_id(),
210 'default_method' => $importedProduct[ImportedProductService::FIELD_METHOD] ?? '',
211 'items' => $normalized_methods,
212 'shipping_cost' => $importedProduct[ImportedProductService::FIELD_COST] ?? '',
213 ],
214 'shipping_info' => $shipping_info
215 ]));
216
217 wp_die();
218 }
219
220 public function ajax_frontend_update_shipping_list(): void
221 {
222 check_admin_referer(self::AJAX_NONCE_ACTION, self::NONCE);
223
224 if (isset($_POST['items'])) {
225 foreach ($_POST['items'] as $ship_way) {
226 if (empty($ship_way['company']) || empty($ship_way['serviceName'])) {
227 continue;
228 }
229
230 $item = ShippingPostType::get_item($ship_way['company']);
231
232 // skip disabled items
233 if ($item === false) {
234 continue;
235 }
236
237 // if no such item yet, let`s add it and then get it
238 if (!$item) {
239 ShippingPostType::add_item($ship_way['company'], $ship_way['serviceName']);
240 }
241 }
242 }
243
244 echo wp_json_encode(ResultBuilder::buildOk());
245 wp_die();
246 }
247
248 public function ajax_frontend_update_shipping_method_in_cart_item(): void
249 {
250 check_admin_referer(self::AJAX_NONCE_ACTION, self::NONCE);
251
252 $cart_item_key = $_POST['id'];
253 $tariff_code = $_POST['value'];
254
255 if (isset(WC()->cart->cart_contents[$cart_item_key])) {
256 WC()->cart->cart_contents[$cart_item_key]['a2wl_shipping_method'] = $tariff_code;
257 } else {
258 $result = ResultBuilder::buildError('No cart item with given key in the cart!');
259
260 echo wp_json_encode($result);
261 wp_die();
262 }
263
264 //reset shipping post code field
265 //todo: remove?
266 if (!isset($_POST['calc_shipping_postcode'])) {
267 $_POST['calc_shipping_postcode'] = '';
268 }
269
270 // Update country in user meta.
271 //todo: remove?
272 $customer_id = apply_filters('woocommerce_checkout_customer_id', get_current_user_id());
273 if ($customer_id && !empty($_POST['calc_shipping_country'])) {
274 $customer = new WC_Customer($customer_id);
275 $customer->set_shipping_country(strval($_POST['calc_shipping_country']));
276 $customer->save();
277 }
278
279 //Update shipping & totals in the cart ( and in checkout?)
280
281 //reset shipping rates
282 $packages = WC()->cart->get_shipping_packages();
283 foreach ($packages as $package_key => $package) {
284 WC()->session->set('shipping_for_package_' . $package_key, false);
285 }
286
287 WC()->cart->calculate_totals();
288
289 WC()->cart->calculate_shipping();
290
291 $result = ResultBuilder::buildOk();
292
293 echo wp_json_encode($result);
294 wp_die();
295 }
296
297 private function get_plugin_data_from_request()
298 {
299 $data = ['a2wl_shipping_method_field' => false, 'a2wl_to_country_field'=> false];
300 if (isset($_REQUEST['a2wl_shipping_method_field']) && !empty($_REQUEST['a2wl_shipping_method_field'])){
301 $data['a2wl_shipping_method_field'] = $_REQUEST['a2wl_shipping_method_field'];
302 } elseif (isset($_REQUEST['data']['a2wl_shipping_method_field']) && !empty($_REQUEST['data']['a2wl_shipping_method_field'])){
303 $data['a2wl_shipping_method_field'] = $_REQUEST['data']['a2wl_shipping_method_field'];
304 }
305
306 if (isset($_REQUEST['a2wl_to_country_field']) && !empty($_REQUEST['a2wl_to_country_field'])){
307 $data['a2wl_to_country_field'] = $_REQUEST['a2wl_to_country_field'];
308 } elseif (isset($_REQUEST['data']['a2wl_to_country_field']) && !empty($_REQUEST['data']['a2wl_to_country_field'])){
309 $data['a2wl_to_country_field'] = $_REQUEST['data']['a2wl_to_country_field'];
310 }
311
312 return $data;
313 }
314
315 public function product_shipping_fields_validation($passed, $product_id, $quantity)
316 {
317
318 $external_id = get_post_meta($product_id, '_a2w_external_id', true);
319
320 if ($external_id) {
321
322 $plugin_request_data = $this->get_plugin_data_from_request();
323
324 if ($plugin_request_data['a2wl_shipping_method_field'] === false) {
325 wc_add_notice(esc_html__('Please select the shipping method', 'woocommerce'), 'error');
326 $passed = false;
327 }
328
329 if ($plugin_request_data['a2wl_to_country_field'] === false) {
330 wc_add_notice(esc_html__('Please select the country where you would like your items to be delivered', 'woocommerce'), 'error');
331 $passed = false;
332 }
333
334 }
335
336 return $passed;
337 }
338
339 public function add_cart_item_data($cart_item_meta, $product_id)
340 {
341 $plugin_request_data = $this->get_plugin_data_from_request();
342
343 if ($plugin_request_data['a2wl_shipping_method_field'] !== false) {
344 $cart_item_meta['a2wl_shipping_method'] = $plugin_request_data['a2wl_shipping_method_field'];
345 }
346
347 if ($plugin_request_data['a2wl_to_country_field'] !== false) {
348 $cart_item_meta['a2wl_to_country'] = $plugin_request_data['a2wl_to_country_field'];
349 }
350
351 return $cart_item_meta;
352 }
353
354 public function set_default_cart_country($cart_item_key, $product_id, $quantity, $variation_id, $variation, $cart_item_data)
355 {
356
357 if (isset($cart_item_data['a2wl_to_country'])) {
358 $country = $cart_item_data['a2wl_to_country'];
359
360 WC()->customer->set_billing_country($country);
361 WC()->customer->set_shipping_country($country);
362
363 //it forces the shipping calculator to update its country field
364 WC()->customer->set_calculated_shipping(true);
365 }
366
367 }
368
369 /**
370 * Handle works on shipping address update in the cart and checkout
371 * or when click on 'update cart' button
372 *
373 * @param $methods
374 * @param $package
375 * @return WC_Shipping_Rate[]
376 */
377 public function woocommerce_package_rates($methods, $package): array
378 {
379 if (!empty($package['contents'])) {
380 $ali_shipping_type = get_setting('aliship_shipping_type', 'new');
381 $countryToCode = $package["destination"]["country"];
382 $default_tariff_code = get_setting('fulfillment_prefship', 'EMS_ZX_ZX_US'); //ePacket
383
384 $ali_total_shipping = 0;
385 $ali_shipping = false;
386 $items_in_package = [];
387
388 $remove_cart_item = get_setting('aliship_not_available_remove');
389 $not_available_cost = get_setting('aliship_not_available_cost');
390
391 foreach ($package['contents'] as $cart_item_key => $cart_item) {
392 $WC_Product = $cart_item['data'];
393 $quantity = $cart_item['quantity'];
394
395
396 $importedProductService = $this->ImportedProductServiceFactory->createFromProduct($WC_Product);
397 $externalId = $importedProductService->getExternalId();
398
399 if ($externalId) {
400 $ali_shipping = true;
401
402 $countryFromCode = 'CN';
403 try {
404 $importedProduct = $this->WoocommerceService
405 ->updateProductShippingItems($WC_Product, $countryToCode, $countryFromCode, $quantity);
406 } catch (RepositoryException|ServiceException $Exception) {
407 a2wl_error_log($Exception->getMessage());
408
409 return $methods;
410 }
411
412 $shippingItems = $this->ProductService->getShippingItems(
413 $importedProduct, $countryToCode, $countryFromCode
414 );
415
416 $normalized_methods = [];
417
418 if (!empty($shippingItems)) {
419 $shipping_methods = $shippingItems;
420
421 if (!empty($shipping_methods)) {
422
423 $search_tariff_code = $cart_item['a2wl_shipping_method'] ?? $default_tariff_code;
424
425 $min_method = false;
426
427 foreach ($shipping_methods as $method) {
428
429 $normalized_method = Shipping::get_normalized($method, $countryToCode);
430
431 if (!$normalized_method) {
432 continue;
433 }
434
435 $normalized_methods[$method['serviceName']] = $normalized_method;
436
437 if (!$min_method || $normalized_method['price'] < $min_method['price']) {
438 $min_method = $normalized_method;
439 }
440 }
441
442 if (isset($normalized_methods[$search_tariff_code])) {
443 $chosen_method = $normalized_methods[$search_tariff_code];
444 $ali_total_shipping += $chosen_method['price'];
445 } else {
446 $chosen_method = $min_method;
447 $ali_total_shipping += $chosen_method['price'];
448 }
449
450 //save method cost to show in the future order
451 WC()->cart->cart_contents[$cart_item_key]['a2wl_shipping_info'] = array(
452 'company' => $chosen_method['company'],
453 'service_name' => $chosen_method['serviceName'],
454 'delivery_time' => $chosen_method['time'],
455 'shipping_cost' => $chosen_method['price']);
456
457 $items_in_package[] = $WC_Product->get_name() . ' &times; ' . $cart_item['quantity'];
458
459 } else {
460
461 //if product can't be delivered to the country
462 if (!$remove_cart_item && $not_available_cost) {
463
464 $ali_total_shipping += $not_available_cost;
465 }
466 }
467
468 } else {
469
470 //todo: it looks like rudiment condition shipping_info can't be false
471 //function can't come here, remove?
472
473 if (!$remove_cart_item && $not_available_cost) {
474 $ali_total_shipping += $not_available_cost;
475 }
476
477 }
478
479 }
480 }
481
482 if ($ali_shipping && $ali_shipping_type !== 'none') {
483 if ($ali_total_shipping) {
484 $id = 'flat_rate';
485 $label = get_setting('aliship_shipping_label');
486 if (!$label) {
487 $label = esc_html__('Shipping', 'ali2woo');
488 }
489 } else {
490 $id = 'free_shipping';
491 $label = get_setting('aliship_free_shipping_label');
492 if (!$label) {
493 $label = esc_html__('Free Shipping', 'ali2woo');
494 }
495 }
496
497 switch ($ali_shipping_type) {
498 case 'new':
499 /*Create a new shipping method but still show other available shipping methods*/
500 $taxes = WC_Tax::calc_shipping_tax($ali_total_shipping, WC_Tax::get_shipping_tax_rates());
501 $methods[$id] = new WC_Shipping_Rate($id, $label, $ali_total_shipping, $taxes, $id, '');
502 if (count($items_in_package)) {
503 $methods[$id]->add_meta_data(esc_html__('Items', 'woocommerce'), implode(', ', $items_in_package));
504 }
505 break;
506 case 'new_only':
507 /*Create a new shipping method and make it the only available shipping method*/
508 $taxes = WC_Tax::calc_shipping_tax($ali_total_shipping, WC_Tax::get_shipping_tax_rates());
509 $methods = array($id => new WC_Shipping_Rate($id, $label, $ali_total_shipping, $taxes, $id, ''));
510 if (count($items_in_package)) {
511 $methods[$id]->add_meta_data(esc_html__('Items', 'woocommerce'), implode(', ', $items_in_package));
512 }
513 break;
514 case 'add':
515 /*Add shipping cost to all available shipping methods*/
516 if ($ali_total_shipping) {
517 foreach ($methods as $rate_k => $rate) {
518 if (is_a($rate, 'WC_Shipping_Rate') && $rate && $rate->get_method_id() !== 'free_shipping') {
519 $cost = $rate->get_cost() + $ali_total_shipping;
520 $taxes = WC_Tax::calc_shipping_tax($cost, WC_Tax::get_shipping_tax_rates());
521 $methods[$rate_k]->set_cost($cost);
522 $methods[$rate_k]->set_taxes($taxes);
523 }
524 }
525 }
526 break;
527 default:
528 }
529
530 } else {
531 //if shipping calculation is none, do not calculate shipping
532 // just keep shipping information saved in the cart item meta (earlier)
533
534 if (!count($methods)) {
535
536 //we need at least one method if use doesn't create any method in woocommerce
537
538 $id = 'free_shipping';
539 $label = get_setting('aliship_free_shipping_label');
540 if (!$label) {
541 $label = esc_html__('Free Shipping', 'ali2woo');
542 }
543
544 $taxes = WC_Tax::calc_shipping_tax(0, WC_Tax::get_shipping_tax_rates());
545 $methods[$id] = new WC_Shipping_Rate('free_shipping', $label, 0, $taxes, $id, '');
546 }
547 }
548 }
549
550 return $methods;
551 }
552
553 public function woocommerce_order_item_get_formatted_meta_data($formatted_meta, $item)
554 {
555 if (!is_admin() || isset($_POST['a2wl_email_template_check'])) {
556 $user_formatted_meta = array();
557
558 foreach ($formatted_meta as $formatted_item) {
559 if ($formatted_item->key === Shipping::get_order_item_shipping_meta_key()) {
560 continue;
561 }
562
563 $user_formatted_meta[$formatted_item->key] = $formatted_item;
564 }
565
566 if (!empty($user_formatted_meta)) {
567 $formatted_meta = $user_formatted_meta;
568 }
569 }
570
571 return $formatted_meta;
572 }
573
574 }
575