PluginProbe
MakeCommerce for WooCommerce / 4.0.1
MakeCommerce for WooCommerce v4.0.1
4.1.0 4.0.8 trunk 1.0 1.0.1 1.0.2 1.0.3 1.1.0 1.1.1 1.1.2 1.1.3 1.1.4 1.1.5 1.1.6 1.1.7 2.0.0 2.1.0 2.1.1 2.1.2 2.1.3 2.1.4 2.1.5 2.2.0 2.2.1 2.2.2 All 96 releases
makecommerce / shipping / shipping.php

shipping.php in MakeCommerce for WooCommerce 4.0.1, at shipping/shipping.php

1,089 lines 32.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace MakeCommerce;
4
5 /**
6 * The admin-specific functionality of the plugin.
7 *
8 * @link https://makecommerce.net/
9 * @since 3.0.0
10 *
11 * @package Makecommerce
12 * @subpackage Makecommerce/shipping
13 */
14
15 /**
16 * The shipping-specific functionality of the plugin.
17 *
18 * Defines the plugin name, version, and two examples hooks for how to
19 * enqueue the admin-specific stylesheet and JavaScript.
20 *
21 * @package Makecommerce
22 * @subpackage Makecommerce/shipping
23 * @author Maksekeskus AS <support@maksekeskus.ee>
24 */
25
26 use MakeCommerce;
27 use MakeCommerce\Shipping\Method\ParcelMachine\Map;
28
29 class Shipping {
30 use Map;
31
32 /**
33 * The ID of this plugin.
34 *
35 * @since 3.0.0
36 * @access private
37 * @var string $plugin_name The ID of this plugin.
38 */
39 private $plugin_name;
40
41 /**
42 * The version of this plugin.
43 *
44 * @since 3.0.0
45 * @access private
46 * @var string $version The current version of this plugin.
47 */
48 private $version;
49
50 private $loader;
51
52 private Shipping\Label $label;
53 private Shipping\Product $product;
54 private Shipping\Order $order;
55
56 /**
57 * Define all shipping methods
58 */
59 public $shipping_methods = [
60 [
61 "option" => "mk_transport_apt_omniva",
62 "method" => "parcelmachine_omniva",
63 "class" => "MakeCommerce\Shipping\Method\ParcelMachine\Omniva"
64 ],
65 [
66 "option" => "mk_transport_apt_smartpost",
67 "method" => "parcelmachine_smartpost",
68 "class" => "MakeCommerce\Shipping\Method\ParcelMachine\Smartpost"
69 ],
70 [
71 "option" => "mk_transport_apt_dpd",
72 "method" => "parcelmachine_dpd",
73 "class" => "MakeCommerce\Shipping\Method\ParcelMachine\DPD"
74 ],
75 [
76 "option" => "mk_transport_apt_lp_express_lt",
77 "default_name" => "LP Express",
78 "method" => "parcelmachine_lp_express_lt",
79 "class" => "MakeCommerce\Shipping\Method\ParcelMachine\LPExpress"
80 ],
81 [
82 "option" => "mk_transport_courier_omniva",
83 "method" => "courier_omniva",
84 "class" => "MakeCommerce\Shipping\Method\Courier\Omniva"
85 ],
86 [
87 "option" => "mk_transport_courier_smartpost",
88 "method" => "courier_smartpost",
89 "class" => "MakeCommerce\Shipping\Method\Courier\Smartpost"
90 ],
91 [
92 "option" => "mk_transport_courier_dpd",
93 "method" => "courier_dpd",
94 "class" => "MakeCommerce\Shipping\Method\Courier\DPD"
95 ]
96 ];
97
98 /**
99 * Initialize the class and set its properties.
100 *
101 * @since 3.0.0
102 * @param string $plugin_name The name of this plugin.
103 * @param string $version The version of this plugin.
104 */
105 public function __construct( $plugin_name, $version, Loader $loader ) {
106
107 $this->plugin_name = $plugin_name;
108 $this->version = $version;
109 $this->loader = $loader;
110
111 //loads all child classes such as label, admin specific functions, email functions
112 $this->load_children();
113
114 if ( is_admin() ) {
115 add_action( 'wp_ajax_verify_feature_swc', [$this, 'verify_makecommerce_shipment_mediaton_availablity'] );
116 }
117
118 if ( self::map_enabled() ) {
119 add_action('woocommerce_before_checkout_form', [$this, 'initialize_mc_map'] );
120 }
121 }
122
123 /**
124 * Check if the customer has shipment mediation for Omniva enabled in MakeCommerce
125 *
126 * @since 3.0.0
127 */
128 public function verify_makecommerce_shipment_mediaton_availablity() {
129
130 $status = $this->check_shipment_mediaton_availablity( 'shipments_without_credentials' );
131
132 wp_send_json( ['feature_name' => 'shipments_without_credentials', 'feature_status' => $status] );
133
134 exit;
135 }
136
137 /**
138 * Check if a shipment mediation is enabled in MakeCommerce
139 *
140 * @since 3.0.0
141 */
142 public function check_shipment_mediaton_availablity( $feature_name = '' ) {
143
144 $feature_enabled = false;
145
146 $MK = MakeCommerce::get_api();
147
148 if ( !$MK ) {
149 return false;
150 }
151
152 try {
153 $shopConfig = $MK->getShopConfig( MakeCommerce::config_request_parameters( "makecommerce feature_staus_check" ) );
154 $features = $shopConfig->features;
155
156 } catch ( \Exception $e ) {
157
158 error_log( print_r( $e, 1 ) );
159
160 return false;
161 }
162
163 if ( isset( $features ) ) {
164
165 foreach ( $features as $feature ) {
166
167 if ( $feature->name == $feature_name ) {
168 $feature_enabled = $feature->enabled;
169 }
170 }
171 }
172
173 return $feature_enabled;
174 }
175
176 /**
177 * Removes transient cache to be able to override shipping cost
178 *
179 * @since 3.0.0
180 */
181 public function initalize() {
182
183 global $wpdb;
184
185 $transients = $wpdb->get_col( "SELECT `option_name` FROM `".$wpdb->options."` WHERE `option_name` LIKE '_transient_wc_ship%'" );
186 if ( count($transients) ) {
187 foreach ( $transients as $tr ) {
188 delete_transient( substr( $tr, 11 ) );
189 }
190 }
191
192 $transient_value = get_transient( 'shipping-transient-version' );
193
194 \WC_Cache_Helper::delete_version_transients( $transient_value );
195
196 if ( WC()->session ) {
197 WC()->session->set( 'shipping_for_package', '' );
198 }
199 }
200
201 /**
202 * Load all supporting child classes
203 *
204 * @since 3.0.0
205 */
206 public function load_children() {
207
208 //load label class (everything to do with shipping labels and printing)
209 $this->label = new Shipping\Label( $this->loader );
210
211 //load product class (everything to do with shipping and products)
212 $this->product = new Shipping\Product( $this->loader );
213
214 //load order class (everything to do with shipping and orders)
215 $this->order = new Shipping\Order( $this->loader );
216 }
217
218 /**
219 * Manually add all different shipping methods to WooCommerce
220 *
221 * @since 3.0.0
222 */
223 public function add_shipping_methods( $methods ) {
224
225 foreach ( $this->shipping_methods as $shipping_method ) {
226
227 if ( get_option( $shipping_method["option"] ) === "yes" ) {
228 $methods[$shipping_method["method"]] = $shipping_method["class"];
229 }
230 }
231
232 return $methods;
233 }
234
235 /**
236 * Clears shipping rates cache, needed for calculation shipping cost
237 *
238 * @since 3.0.0
239 */
240 public function clear_shipping_rates_cache() {
241
242 $packages = WC()->cart->get_shipping_packages();
243
244 foreach ( $packages as $key => $value ) {
245
246 $shipping_session = "shipping_for_package_$key";
247 unset( WC()->session->$shipping_session );
248 }
249 }
250
251 /**
252 * Set order parcel machine meta
253 *
254 * @since 3.0.0
255 */
256 public function set_parcel_machine_meta( $post_id ) {
257
258 $update = false;
259 $order = wc_get_order( $post_id );
260
261 // Not an order
262 if ( !$order || get_transient( '_set_parcel_machine_meta_transient' ) ) {
263 return;
264 }
265
266 if ( isset( $_POST['_mk_machine_id'] ) ) {
267
268 //if the machine id is not the same as it was before then delete the _parcel_machine_shipment_id so a new one can be created.
269 $current_parcel_machine = $order->get_meta( '_parcel_machine', true );
270
271 // LP Express set order template
272 if ( isset( $_POST['_mk_template_id'] ) ) {
273 $current_template = $order->get_meta( '_mk_parcel_template', true );
274 //set the template for the order
275 if ( $_POST['_mk_template_id'] != $current_template ) {
276 $order->update_meta_data( '_mk_parcel_template', $_POST['_mk_template_id'] );
277 $update = true;
278 }
279 }
280
281 if ( $_POST['_mk_machine_id'] != $current_parcel_machine || $update ) {
282 //set new parcel machine
283 $order->update_meta_data( '_parcel_machine', $_POST['_mk_machine_id'] );
284
285 //remove old shipment id
286 $order->update_meta_data( '_parcel_machine_shipment_id', "" );
287
288 set_transient( '_set_parcel_machine_meta_transient', true, 5 );
289
290 $order->save();
291
292 //register shipment again
293 $this->register_shipment( $post_id );
294
295 //update address
296 self::update_order_parcelmachine_meta( $_POST['_mk_machine_id'], $post_id );
297
298 delete_transient( '_set_parcel_machine_meta_transient' );
299 }
300 }
301 }
302
303 /**
304 * Changes order view WHERE clause to include orders using MakeCommerce shipping
305 *
306 * @since 3.0.0
307 */
308 public function shipping_filter( $where, $wp_query ) {
309
310 global $pagenow, $wpdb;
311
312 $method = !empty( $_REQUEST['_shipping_method'] ) ? $_REQUEST['_shipping_method'] : false;
313 //HPOS?
314 if ( is_admin() && $pagenow=='edit.php' && $wp_query->query_vars['post_type'] == 'shop_order' && !empty( $method ) ) {
315 $where .= $GLOBALS['wpdb']->prepare( ' AND ID
316 IN (
317 SELECT items.order_id
318 FROM '.$wpdb->prefix.'woocommerce_order_itemmeta meta, '.$wpdb->prefix.'woocommerce_order_items items
319 WHERE meta.order_item_id = items.order_item_id
320 AND meta.meta_key = "method_id"
321 AND meta.meta_value = %s
322 ) ', $method );
323 }
324
325 return $where;
326 }
327
328 /**
329 * Set order parcel machine meta
330 *
331 * @since 3.1.0
332 */
333 public function update_courier_meta ( $post_id ) {
334
335 $order = wc_get_order( $post_id );
336
337 if ( !$order || get_transient( '_update_courier_meta_transient' ) ) {
338 return;
339 }
340
341 // Check if a shipping method exists
342 if ( isset( $_POST["shipping_method"] ) ) {
343 $method = $_POST["shipping_method"];
344 } else {
345 return;
346 }
347
348 if ( is_array( $method ) && count( $method ) > 0 ) {
349 // Check if it is a courier
350 if ( array_values( $method )[0] == "courier_smartpost"
351 || array_values( $method )[0] == "courier_omniva"
352 || array_values( $method )[0] == "courier_dpd"
353 ) {
354
355 //remove old shipment id
356 $order->update_meta_data( '_parcel_machine_shipment_id', "" );
357
358 set_transient( '_update_courier_meta_transient', true, 5 );
359
360 $order->save();
361
362 //register shipment again
363 $this->register_shipment( $post_id );
364
365 delete_transient( '_update_courier_meta_transient' );
366 }
367 }
368 }
369
370 /**
371 * Update parcel machine meta data for an order
372 * Adds all the shipping information possible.
373 *
374 * @since 3.0.3
375 */
376 public static function update_order_parcelmachine_meta( $machine_id, $order_id ) {
377
378 list( $carrier, $machine ) = explode( '||', $machine_id );
379
380 $machine = self::mk_get_machine( $carrier, $machine );
381
382 if ( !empty( $machine['id'] ) ) {
383
384 $order = wc_get_order( $order_id );
385
386 if ( empty( $order->get_shipping_first_name() ) ) {
387 $order->set_shipping_first_name( $order->get_billing_first_name() );
388 }
389
390 if ( empty( $order->get_shipping_last_name() ) ) {
391 $order->set_shipping_last_name( $order->get_billing_last_name() );
392 }
393
394
395 $order->set_shipping_address_1( sanitize_text_field( $machine['name'] ) );
396 $order->set_shipping_address_2( sanitize_text_field( $machine['address'] ) );
397 $order->set_shipping_city( sanitize_text_field( $machine['city'] ) );
398 $order->set_shipping_postcode( sanitize_text_field( $machine['zip'] ) );
399
400 $order->update_meta_data( '_parcel_machine', sanitize_text_field( $machine_id ) );
401
402 $order->save();
403 }
404 }
405
406 /**
407 * Registers shipment(s) via MakeCommerce API
408 *
409 * @since 3.0.0
410 */
411 public function register_shipment( $post_ids, $select_carrier = null ) {
412
413 //we always expect an array of post ids
414 if ( !is_array( $post_ids ) ) {
415 $post_ids = [$post_ids];
416 }
417
418 //initialize to delete transient and set WC session
419 $this->initalize();
420
421 $shipping_request = ['credentials' => [], 'orders' => []];
422
423 //setup shipping classes map
424 $shipping_classes_map = [];
425 foreach ( $this->shipping_methods as $shipping_method ) {
426
427 $shipping_classes_map[$shipping_method["method"]] = $shipping_method["class"];
428 }
429
430 //loop all post ids
431 foreach ( $post_ids as $post_id ) {
432
433 $order = wc_get_order( $post_id );
434
435 //if parcel machine shipment id already exists then skip
436 $oldId = $order->get_meta( '_parcel_machine_shipment_id', true );
437
438 if ( strlen( $oldId ) > 6 ) {
439 continue;
440 }
441
442 //check if the post state is even paid, if not, ignore this post...
443 //this could perhaps be in a way better location. Why is the function even called when post state is set to failed.
444 if ( ( string )$order->get_status() !== "completed" && ( string )$order->get_status() !== "processing" ) {
445 continue;
446 }
447
448 //skip if the order doesnt have a shipping method
449 $shipping_methods = $order->get_shipping_methods();
450 if ( empty( $shipping_methods ) ) {
451 continue;
452 }
453
454 //loop all MakeCommerce shipping methods
455 foreach ( $shipping_methods as $shipping_method ) {
456
457 $shipping_id = explode( ':', $shipping_method['method_id'] );
458 $shipping_class = $shipping_id[0];
459 $shipping_instance = !empty( $shipping_id[1] ) ? $shipping_id[1] : null;
460
461 //if chosen method is not the current method then move on to the next one
462 if ( empty( $shipping_classes_map[$shipping_class] ) ) {
463 continue;
464 }
465
466 // New metadata for keeping track of order shipping methods
467 if ( isset( $shipping_class ) ) {
468 $order->update_meta_data( '_mc_shipping_method', sanitize_text_field( $shipping_class ) );
469 $order->save();
470 }
471
472 $transport_class = new $shipping_classes_map[$shipping_class]( $shipping_instance );
473 $carrier_uc = mb_strtoupper( $transport_class->carrier_id );
474
475 //change carrier_uc if it has been set in the interface.
476 if ( isset( $transport_class->settings['service_carrier'] ) ) {
477 $carrier_uc = $transport_class->settings['service_carrier'];
478 }
479
480 if ( empty( $shipping_request['credentials'][$carrier_uc] ) ) {
481 $shipping_request = $this->set_shipping_request_credentials( $carrier_uc, $transport_class, $shipping_request );
482 // Move on to next post if the function returned empty values
483 if ( empty( $shipping_request['credentials'][$carrier_uc] ) && empty( $transport_class->settings['use_mk_contract'] ) ) {
484 $order->update_meta_data(
485 '_parcel_machine_error',
486 __( 'Request failed: missing credentials', 'wc_makecommerce_domain' )
487 );
488 $order->save();
489 continue;
490 }
491 }
492
493 $sr_order = $this->set_sr_order_data(
494 $order,
495 $transport_class,
496 $shipping_class,
497 $carrier_uc
498 );
499
500 if ( !$sr_order ) {
501 $order->update_meta_data(
502 '_parcel_machine_error',
503 __( 'Request failed: invalid sender or destination data', 'wc_makecommerce_domain' )
504 );
505 $order->save();
506 continue;
507 }
508
509 if ( $carrier_uc === 'LP_EXPRESS_LT' ) {
510 $default = get_option( 'mk_lpexpress_template' );
511
512 if ( !empty( $order->get_meta( '_mk_parcel_template', true ) ) ) {
513 $template = $order->get_meta( '_mk_parcel_template', true );
514 } else {
515 $template = $default;
516 }
517 $sr_order['lpExpressShipmentDetails']["templateId"] = $template;
518 }
519
520 $shipping_request['orders'][] = $sr_order;
521 }
522 }
523
524 $shipping_request['credentials'] = array_values( $shipping_request['credentials'] );
525
526 if ( empty( $shipping_request['orders'] ) ) {
527 return;
528 }
529
530 $MK = MakeCommerce::get_api();
531 if ( !$MK ) {
532 return;
533 }
534
535 try {
536 $response = $MK->createShipments( $shipping_request );
537 } catch ( \Exception $e ) {
538 error_log( 'Error while creating shipment ['.$e->getMessage().']' );
539 return;
540 }
541
542 $shipments = !empty( $response->shipments ) ? $response->shipments : $response;
543 $manifest = !empty( $response->manifests ) ? $response->manifests[0] : false;
544
545 foreach ( $shipments as $order_data ) {
546 // No id present, continue
547 if ( !wc_get_order( ( int ) $order_data->orderId ?? false ) ) {
548 continue;
549 }
550
551 $order = wc_get_order( ( int ) $order_data->orderId );
552
553 if ( $manifest ) {
554 $order->update_meta_data( '_parcel_machine_manifest', sanitize_text_field( $manifest ) );
555 }
556
557 if ( !empty( $order_data->lpExpressCartIdentifier ) ) {
558 $order->update_meta_data( '_lp_express_cart_identifier', sanitize_text_field( $order_data->lpExpressCartIdentifier ) );
559 }
560
561 // LP Express has shipmentId AND barcode
562 if ( isset( $order_data->barcode ) ) {
563 $order->update_meta_data( '_parcel_machine_shipment_barcode', sanitize_text_field( $order_data->barcode ) );
564 }
565
566 // OrderId needed for all the following blocks
567 if ( !empty( $order_data->orderId ) ) {
568 if ( ! empty( $order_data->shipmentId ) ) {
569 $order->update_meta_data( '_parcel_machine_shipment_id', sanitize_text_field( $order_data->shipmentId ) );
570 $order->update_meta_data( '_tracking_number', sanitize_text_field( $order_data->shipmentId ) ); //default value used by other plugins, such as WooCommerce PDF Invoices and so on
571 $order->delete_meta_data( '_parcel_machine_error' );
572 } else if ( !empty( $order_data->barCode ) ) {
573
574 $order->update_meta_data( '_parcel_machine_shipment_id', sanitize_text_field( $order_data->barCode ) );
575 $order->update_meta_data( '_tracking_number', sanitize_text_field( $order_data->barCode ) ); //default value used by other plugins, such as WooCommerce PDF Invoices and so on
576 $order->delete_meta_data( '_parcel_machine_error' );
577 } else if ( !empty( $order_data->errorMessage ) ) {
578
579 $order->update_meta_data( '_parcel_machine_error', sanitize_text_field( $order_data->errorMessage ) );
580 }
581 }
582
583 $order->save();
584 }
585 }
586
587 /**
588 * Returns shipping information for order
589 *
590 * @since 3.0.9
591 */
592 public function get_order_shipping_information( $order) {
593
594 $shipping_information = [];
595
596 $shipping_address = $order->get_address( 'shipping' );
597 $billing_address = $order->get_address( 'billing' );
598
599 $phone = '';
600 if ( isset( $shipping_address['phone'] ) ) {
601 $phone = $shipping_address['phone'];
602 }
603
604 if ( $phone == '' && isset( $billing_address['phone'] ) ) {
605 $phone = $billing_address['phone'];
606 }
607
608 $shipping_information['first_name'] = $shipping_address['first_name'] ? $shipping_address['first_name'] : $billing_address['first_name'];
609 $shipping_information['last_name'] = $shipping_address['last_name'] ? $shipping_address['last_name'] : $billing_address['last_name'];
610 $shipping_information['phone'] = $phone;
611 $shipping_information['email'] = $order->get_meta( '_shipping_email', true ) ? $order->get_meta( '_shipping_email', true ) : $billing_address['email'];
612
613 $shipping_information['recipient_name'] = $shipping_information['first_name'] . ' ' . $shipping_information['last_name'];
614
615 return $shipping_information;
616 }
617
618 /**
619 * Returns the correct link to be used for tracking link
620 *
621 * @since 3.0.0
622 */
623 public function get_tracking_link( $carrier, $order, $shipment_id, $shopLocation = false ) {
624 //do we use shop location or delivery location
625 if ( $shopLocation ) {
626 //get_base_country returns either EE, LT or LV. Everything else is irrelevant
627 $dst = substr( strtolower( WC()->countries->get_base_country() ), 0, 2);
628 $lang = get_locale();
629 if ( strlen( $lang ) > 2 ) {
630 // Make locales like en_US or lt_LT shorter
631 $lang = substr($lang, 0,2);
632 }
633 } else {
634 //get order delivery location. Returns EE, LT or LV. Evertyhing else is irrelevant
635 $dst = substr( strtolower( $order->get_shipping_country() ), 0, 2 );
636 $lang = substr( strtolower( $order->get_meta( 'wpml_language', true ) ), 0, 2 ); //returns nothing if it doesnt exist, otherwise returns en, et, lt, lv, ru
637 if ( empty( $lang ) ) {
638 // Try getting language with ploylang
639 if( function_exists('pll_current_language' ) ) {
640 $lang = pll_current_language();
641 }
642 }
643 }
644
645 $link = MC_TRACKING_SERVICE_URL . urlencode( $shipment_id );
646
647 $params = [
648 'carrier' => urlencode( $carrier ),
649 'dst' => urlencode( $dst ),
650 'lang' => urlencode( $lang )
651 ];
652
653 return esc_url( add_query_arg( $params, $link ) );
654 }
655
656 /**
657 * Returns all available parcelmachines
658 *
659 * @since 3.0.0
660 */
661 public static function mk_get_machines( $carrier, $country = null, $aptopts = [] ) {
662
663 //set machine cache
664 $data = get_option( 'mk_machines_cache', false );
665 $data_expires = get_option( 'mk_machines_expires', false );
666
667 if ( !$data || empty( $data ) || $data_expires < time() ) {
668
669 $MK = MakeCommerce::get_api();
670
671 if( !$MK ) {
672 return [];
673 }
674
675 $data = $MK->getDestinations( ['type' => 'APT,PUP'] );
676
677 update_option( 'mk_machines_cache', $data, 'no' );
678 update_option( 'mk_machines_expires', time() + 3 * 60 * 60, 'no' );
679 }
680
681 //return empty if no machines found for destination
682 if ( !$data || empty( $data ) ) {
683
684 return [];
685 }
686
687 //create machines array
688 $machines = [];
689
690 foreach ( $data as $machine ) {
691
692 if ( ( !$country || $machine->country === $country ) &&
693 ( $machine->type === 'APT' || $machine->type === 'PUP' ) &&
694 ( $carrier === '*' || strtolower( $carrier ) === strtolower( $machine->carrier ) ) ) {
695
696 if ( !(isset($aptopts['use_white_apts']) && $aptopts['use_white_apts'] == 1 &&
697 $machine->carrier == 'SMARTPOST' && strpos($machine->name, 'valge') != false)) {
698
699 if ( isset( $machine->x ) && isset( $machine->y ) ) {
700 $machines[] = [
701 'carrier' => strtolower( $machine->carrier ),
702 'id' => $machine->id,
703 'name' => $machine->name,
704 'city' => $machine->city,
705 'address' => $machine->address ?? '',
706 'commentEt' => $machine->commentEt ?? '',
707 'commentLv' => $machine->commentLv ?? '',
708 'commentLt' => $machine->commentLt ?? '',
709 'commentFi' => $machine->commentFi ?? '',
710 'availability' => $machine->availability ?? '',
711 'zip' => $machine->zip,
712 'x' => $machine->x,
713 'y' => $machine->y
714 ];
715 continue;
716 }
717
718 $machines[] = [
719 'carrier' => strtolower( $machine->carrier ),
720 'id' => $machine->id,
721 'name' => $machine->name,
722 'city' => $machine->city,
723 'address' => !empty( $machine->address ) ? $machine->address : '',
724 'zip' => $machine->zip
725 ];
726 }
727 }
728 }
729
730 //sort machines
731 usort( $machines, function( $a, $b ) {
732 if ( $a['city'] === $b['city'] ) {
733
734 return $a['name'] > $b['name'] ? 1 : -1;
735 }
736
737 return $a['city'] > $b['city'] ? 1 : -1;
738 });
739
740 return $machines;
741 }
742
743 /**
744 * Returns a specific parecelmachine
745 *
746 * @since 3.0.0
747 */
748 public static function mk_get_machine( $carrier, $id ) {
749
750 //get all available machines
751 $machines = self::mk_get_machines( $carrier );
752
753 //loop and return the machine we are searching for if found
754 foreach ( $machines as $machine ) {
755
756 if ( $machine['carrier'] === $carrier && $machine['id'] == $id ) {
757
758 return $machine;
759 }
760 }
761
762 return false;
763 }
764
765 /**
766 * Register the stylesheets.
767 *
768 * @since 3.0.0
769 */
770 public function enqueue_styles() {
771
772 if ( is_admin() ) {
773 wp_enqueue_style( $this->plugin_name . "-parcelmachine-admin", plugin_dir_url(__FILE__) . 'css/parcelmachine-admin.css', [], $this->version );
774 }
775 }
776
777 /**
778 * Register the JavaScript.
779 *
780 * @since 3.0.0
781 */
782 public function enqueue_scripts() {
783
784 if ( is_admin() ) {
785 MakeCommerce::mc_enqueue_script('MC_PARCELMACHINE_JS_ADMIN', dirname(__FILE__) . '/js/parcelmachine-admin.js', [], [ 'jquery' ]);
786 } else {
787
788 MakeCommerce::mc_enqueue_script('MC_PARCELMACHINE_SEARCHABLE_JS', dirname(__FILE__) . '/js/parcelmachine_searchable.js',
789 [['placeholder' => __( '-- select parcel machine --', 'wc_makecommerce_domain' )]], [ 'jquery' ]
790 );
791
792 MakeCommerce::mc_enqueue_script('MC_PARCELMACHINE_JS', dirname(__FILE__) . '/js/parcelmachine.js', [], [ 'jquery' ]);
793 }
794 }
795
796 /**
797 * Initializes the parcel machine map with required variables
798 *
799 * @since 3.3.0
800 */
801 public function initialize_mc_map() {
802 // Prepare the address or location you want to geocode
803 $address = implode( ',', array_filter(
804 [
805 get_option( 'woocommerce_store_address' ),
806 get_option( 'woocommerce_store_city' ),
807 get_option( 'woocommerce_store_postcode' )
808 ]
809 ) );
810
811 $api_key = get_option( 'mc_google_api_key', '' );
812 $url = 'https://maps.googleapis.com/maps/api/js?key=' . $api_key . '&callback=initMCPMMap&v=weekly';
813
814 self::initialize_map(
815 [
816 'site_url' => get_site_url(),
817 'address' => $address,
818 'map_init_url' => $url,
819 'locale' => substr( get_locale(), 0, 2 )
820 ]
821 );
822 }
823
824 /**
825 * Updates the coordinates for the map centre
826 *
827 * @since 3.3.0
828 */
829 public function update_map_center() {
830
831 $coords = [0,0];
832
833 // If geocoding is disabled, just update the country
834 if ( !self::geocoding_enabled() ) {
835 wp_send_json( [ 'coordinates' => $coords, 'country' => WC()->customer->get_shipping_country() ] );
836 }
837
838 // Prepare the address or location you want to geocode
839 $address = implode( ',', array_filter(
840 [
841 WC()->customer->get_shipping_address(),
842 WC()->customer->get_shipping_city(),
843 WC()->customer->get_shipping_postcode()
844 ]
845 ) );
846
847 $api_key = get_option( 'mc_map_geocoding_api_key', '' );
848 $url = 'https://maps.googleapis.com/maps/api/geocode/json?address=' . $address . '&key=' . $api_key;
849
850 $response = wp_remote_get( $url );
851
852 if ( is_wp_error( $response ) ) {
853 wp_send_json_error( [ 'status' => '400' ], '400' );
854 }
855
856 $data = json_decode( wp_remote_retrieve_body( $response ) );
857
858 if ( isset( $data->results[0]->geometry->location ) ) {
859 $coords = $data->results[0]->geometry->location;
860 $coords = [ $coords->lat, $coords->lng ];
861 }
862
863 wp_send_json( [ 'coordinates' => $coords, 'country' => WC()->customer->get_shipping_country() ] );
864 }
865
866 /**
867 * Adds credentials to the label / shipping request
868 *
869 * @since 3.3.0
870 */
871 public function set_shipping_request_credentials( $carrier_uc, $transport_class, $shipping_request ) {
872 // TMS enabled, return
873 if ( !empty( $transport_class->settings['use_mk_contract'] ) ) {
874 return $shipping_request;
875 }
876
877 if ( !empty( $transport_class->settings['api_key'] ) ) {
878 $shipping_request['credentials'][$carrier_uc]['apiKey'] = $transport_class->settings['api_key'];
879 }
880
881 if ( !empty( $transport_class->settings['service_user'] ) ) {
882 $shipping_request['credentials'][$carrier_uc]['username'] = $transport_class->settings['service_user'];
883 }
884
885 if ( !empty( $transport_class->settings['service_password'] ) ) {
886 $shipping_request['credentials'][$carrier_uc]['password'] = $transport_class->settings['service_password'];
887 }
888
889 // Check if any other credentials are added
890 // If not, then leave empty to skip registering
891 if ( !empty( $shipping_request['credentials'][$carrier_uc] ) ) {
892 $shipping_request['credentials'][$carrier_uc]['carrier'] = $carrier_uc;
893 }
894
895 return $shipping_request;
896 }
897
898 /**
899 * Adds sender and destination data to label / shipping request
900 *
901 * @since 3.3.0
902 */
903 public function set_sr_order_data(
904 $order,
905 $transport_class,
906 $shipping_class,
907 $carrier_uc,
908 $shipment_id = null,
909 $label_creation = false
910 ) {
911
912 if ( $transport_class->type === 'apt' ) {
913 $parcel_machine = $order->get_meta( '_parcel_machine', true );
914
915 if ( !$parcel_machine ) {
916 return;
917 }
918
919 list( $carrier, $machine_id ) = explode( '||', $parcel_machine );
920
921 if ( !$carrier || !$machine_id ) {
922 return;
923 }
924 }
925
926 $sender = [
927 'name' => !empty( $transport_class->settings['shop_name'] ) ? $transport_class->settings['shop_name'] : '',
928 'phone' => !empty( $transport_class->settings['shop_phone'] ) ? $transport_class->settings['shop_phone'] : '',
929 'email' => !empty( $transport_class->settings['shop_email'] ) ? $transport_class->settings['shop_email'] : '',
930 'country' => !empty( $transport_class->settings['shop_address_country'] ) ? $transport_class->settings['shop_address_country'] : '',
931 'city' => !empty( $transport_class->settings['shop_address_city'] ) ? $transport_class->settings['shop_address_city'] : '',
932 'street' => !empty( $transport_class->settings['shop_address_street'] ) ? $transport_class->settings['shop_address_street'] : '',
933 'postalCode' => !empty( $transport_class->settings['shop_postal_code'] ) ? $transport_class->settings['shop_postal_code'] : '',
934 ];
935
936 // Shipping additions
937 if ( !$label_creation ) {
938 $sender['building'] = !empty( $transport_class->settings['shop_building'] ) ? $transport_class->settings['shop_building'] : '';
939 $sender['apartment'] = !empty( $transport_class->settings['shop_apartment'] ) ? $transport_class->settings['shop_apartment'] : '';
940 }
941
942 // If every value in sender except for country is empty, stop request
943 // Country is a list, cant be empty after saving
944 if ( count( array_filter( $sender ) ) <= 1 ) {
945 return;
946 }
947
948 $shipping_information = $this->get_order_shipping_information( $order );
949
950 $sr_order = [
951 'carrier' => $carrier_uc,
952 'orderId' => $order->get_id(),
953 'recipient' => [
954 'name' => $shipping_information['recipient_name'],
955 'phone' => $shipping_information['phone'],
956 'email' => $shipping_information['email'],
957 ],
958 'sender' => $sender,
959 ];
960
961 // Either label or shipment registration
962 $label_creation ? $sr_order['shipmentId'] = $shipment_id : $sr_order['destination'] = [];
963
964 $m_service_type = null;
965
966 if ( $transport_class->carrier === 'omniva' && $transport_class->type === 'atp' ) {
967 $m_service_type = 'PA';
968 } elseif ( !empty( $transport_class->settings['registerOnPaymentCode'] ) ) {
969 $m_service_type = $transport_class->settings['registerOnPaymentCode'];
970 }
971
972 if ( $transport_class->type === 'cou' || $carrier_uc === 'LP_EXPRESS_LT' ) {
973 $sr_order['destination'] = [
974 'postalCode' => $order->get_shipping_postcode(),
975 'country' => $order->get_shipping_country(),
976 'county' => $order->get_shipping_state(),
977 'city' => $order->get_shipping_city(),
978 'street' => $order->get_shipping_address_1() . ' ' . $order->get_shipping_address_2(),
979 ];
980
981 if ( $shipping_class == "courier_smartpost" ) {
982 $delivery_time = $order->get_meta( '_delivery_time', true );
983
984 if ( $delivery_time ) {
985 $sr_order['destination']['timeWindow'] = $delivery_time;
986 }
987 }
988 }
989
990 if ( !empty( $machine_id ) ) {
991 $sr_order['destination']['destinationId'] = $machine_id;
992 }
993
994 if ( $m_service_type ) {
995 $sr_order['services'] = ['serviceType' => $m_service_type];
996 }
997
998 return $sr_order;
999 }
1000
1001 /**
1002 * Checks geocoding API key with request when key is changed in settings
1003 *
1004 * @since 3.3.0
1005 */
1006 public function mc_check_api_key() {
1007 // Test API key with geocode request and random address
1008 $response = wp_remote_get(
1009 'https://maps.googleapis.com/maps/api/geocode/json?address=niine,Tallinn&key=' .
1010 get_option( 'mc_map_geocoding_api_key', '' )
1011 );
1012
1013 if ( is_wp_error( $response ) ) {
1014 $this->add_google_api_key_db_entry( $response->get_error_message() );
1015
1016 return;
1017 }
1018
1019 $data = json_decode( wp_remote_retrieve_body( $response ) );
1020
1021 // Api key was accepted
1022 if ( $data->status === "OK" ) {
1023 // Delete error notice DB entry
1024 delete_user_meta( get_current_user_id(), 'mc_invalid_google_api_key');
1025
1026 return;
1027 }
1028
1029 $this->add_google_api_key_db_entry( $data->error_message );
1030 }
1031
1032 /**
1033 * Adds entry into DB to display a notice in admin view
1034 *
1035 * @since 3.3.0
1036 */
1037 public function add_google_api_key_db_entry( $message ) {
1038 $user_id = get_current_user_id();
1039
1040 // Unset the $_GET key to avoid removing the notice at the same time
1041 unset( $_GET['dismiss_mc_invalid_google_api_key'] );
1042
1043 if ( !get_user_meta( $user_id, 'mc_invalid_google_api_key' ) ) {
1044 add_user_meta( $user_id, 'mc_invalid_google_api_key', $message, true );
1045 } else {
1046 update_user_meta( $user_id, 'mc_invalid_google_api_key', $message );
1047 }
1048 }
1049
1050 /**
1051 * Adds an error to admin notices if the Google Javascript API key is wrong
1052 *
1053 * @since 3.3.0
1054 */
1055 public function invalid_api_key_notification() {
1056 $user_id = get_current_user_id();
1057
1058 // Dismissed then remove value from DB
1059 if ( isset( $_GET['dismiss_mc_invalid_google_api_key'] ) ) {
1060 delete_user_meta( $user_id, 'mc_invalid_google_api_key');
1061 return;
1062 }
1063
1064 // If DB does not contain value then do not display the error
1065 if ( !get_user_meta( $user_id, 'mc_invalid_google_api_key' ) ) {
1066 return;
1067 }
1068
1069 $message = trim( get_user_meta( $user_id, 'mc_invalid_google_api_key', true ) );
1070
1071 $_GET['dismiss_mc_invalid_google_api_key'] = '1';
1072
1073 $dismiss_href = esc_url( add_query_arg( $_GET ) );
1074
1075 // Display error
1076 echo '
1077 <div class="notice notice-error">
1078 <p>
1079 <a style="float: right; " href="' . $dismiss_href . '">' . __( 'Dismiss', 'wc_makecommerce_domain' ) . '</a>
1080 ' . __( 'Unable to use Google Geocoding:', 'wc_makecommerce_domain' ) .
1081 ' "' . $message . '" ' . __( 'Check your app settings or', 'wc_makecommerce_domain' ) . ' ' . '
1082 <a href=/wp-admin/admin.php?page=wc-settings&tab=advanced&section=mk_api>' .
1083 __( 'update the key here', 'wc_makecommerce_domain' ) . '
1084 </a>
1085 </p>
1086 </div>';
1087 }
1088 }
1089