PluginProbe
MakeCommerce for WooCommerce / 3.0.9
MakeCommerce for WooCommerce v3.0.9
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 / method / method.php

method.php in MakeCommerce for WooCommerce 3.0.9, at shipping/method/method.php

595 lines 20.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace MakeCommerce\Shipping;
4
5 /**
6 * Creates minimal functionality needed for WooCommerce shipping method
7 *
8 * @since 3.0.0
9 */
10
11 abstract class Method extends \WC_Shipping_Method {
12
13 use \MakeCommerce\Shipping\Method\ShippingClasses;
14
15 public $id;
16 public $instance_id;
17
18 public $supports = array(
19 'shipping-zones',
20 'instance-settings',
21 'instance-settings-modal',
22 'settings'
23 );
24
25 /**
26 * Construct WooCommerce shipping method
27 *
28 * @since 3.0.0
29 */
30 public function __construct( $instance_id = 0 ) {
31
32 //set required properties
33 $this->instance_id = absint( $instance_id );
34 $this->id = $this->identifier . '_' . mb_strtolower( $this->carrier );
35 $this->ext = mb_strtolower( $this->carrier );
36 $this->title = $this->return_method_title();
37 $this->method_title = $this->title;
38 $this->name_ext = $this->title;
39
40 //get settings from WC_Shipping_Method
41 $this->init_settings();
42
43 //set default settings used by all shipping methods
44 $this->set_default_settings();
45
46 //initialize form fields for admin
47 $this->initialize_form_fields();
48
49 //set hooks
50 $this->set_hooks();
51
52 //initilize method type
53 $this->initialize();
54 }
55
56 /**
57 * Set hooks used by all WooCommerce shipping methods
58 *
59 * @since 3.0.0
60 */
61 final public function set_hooks() {
62
63 //update options
64 add_action( 'woocommerce_update_options_shipping_' . $this->id, array( $this, 'process_admin_options' ) );
65
66 //Woocommerce Multilingual overrides (change some titles)
67 if ( \MakeCommerce\i18n::using_language_plugins() ) {
68 add_filter( 'woocommerce_package_rates', array( $this, 'override_label_translation' ), 50 );
69 add_filter( 'woocommerce_order_get_items', array( $this, 'override_shipping_title_translation' ), 50, 2 );
70 }
71
72 //check if a parcelmachine has been chosen in checkout
73 add_action( 'woocommerce_checkout_process', array( $this, 'check_checkout_fields' ) );
74 add_action( 'woocommerce_after_checkout_validation', array( $this, 'check_checkout_fields' ) );
75 }
76
77 /**
78 * Add check for parcelmachine selectbox
79 * Checks if something is chosen
80 *
81 * @since 3.0.4
82 */
83 public function check_checkout_fields() {
84
85 //those checks are needed, otherwise the notification will be added more than once
86 static $added1 = false;
87 static $added2 = false;
88
89 $shipping_method = !empty( $_POST['shipping_method'] ) ? $_POST['shipping_method'] : false;
90
91 if ( !empty( $shipping_method[0] ) ) {
92 $shipping_method_ext = explode( ':', $shipping_method[0] );
93 }
94
95 if ( !$added1 && $shipping_method_ext[0] === $this->id && empty( $_POST[$shipping_method_ext[0]] ) && $this->type == "apt" ) {
96 wc_add_notice( __( '<strong>Parcel machine</strong> is a required field.', 'wc_makecommerce_domain' ), 'error' );
97 $added1 = true;
98 }
99
100 $shipping_phone_number = null;
101 if ( isset( $_POST['ship_to_different_address'] ) && isset( $_POST['shipping_phone'] ) ) {
102 $_POST['shipping_phone'] = $this->sanitize_phone_number( $_POST['shipping_phone'] );
103 $shipping_phone_number = $_POST['shipping_phone'];
104 } else {
105 $_POST['billing_phone'] = $this->sanitize_phone_number( $_POST['billing_phone'] );
106 $shipping_phone_number = $_POST['billing_phone'];
107 }
108
109 if ( $shipping_phone_number !== null ) {
110 if ( !$added2 && $shipping_method_ext[0] === $this->id && !$this->valid_phone_number( $shipping_phone_number ) ) {
111 wc_add_notice( $this->phone_number_validation_error(), 'error' );
112 $added2 = true;
113 }
114 }
115 }
116
117 /**
118 * Sanitize phone number
119 *
120 * @since 3.0.4
121 */
122 public function sanitize_phone_number( $phone_number ) {
123
124 $phone_number = filter_var ( $phone_number, FILTER_SANITIZE_NUMBER_INT );
125 $phone_number = trim( $phone_number, '-' );
126 //convert first 2 zeros to + if needed
127 if ( substr( $phone_number, 0, 2 ) == "00" ) {
128 $phone_number = '+' . substr( $phone_number, 2 );
129 }
130
131 return $phone_number;
132 }
133
134 /**
135 * Check if provided phonenumber is valid
136 *
137 * @since 3.0.4
138 */
139 public function valid_phone_number( $phone_number ) {
140
141 //could be that all that we need to check is international format
142 if ( $this->international_number_format ) {
143 return $this->check_international_number( $phone_number );
144 }
145
146 //allow all numbers if validation is not defined
147 if ( !isset( $this->valid_phonenumber_country_codes ) ) {
148 return true;
149 }
150
151 //remove + signs
152 $phone_number = trim( $phone_number, '+' );
153
154 //check if it contains country code
155 foreach ( $this->valid_phonenumber_country_codes as $country_code=>$valid_numbers ) {
156
157 //country code matched
158 if ( substr( $phone_number, 0, strlen( $country_code ) ) == $country_code ) {
159 return $this->check_number( substr( $phone_number, strlen( $country_code ) ), $valid_numbers );
160 }
161 }
162
163 //country code didn't match, there is nothing we can do but check if its valid in any of the provided countries
164 foreach ( $this->valid_phonenumber_country_codes as $country_code=>$valid_numbers ) {
165 if ( $this->check_number( $phone_number, $valid_numbers ) === true ) {
166 return true;
167 }
168 }
169
170 return false;
171 }
172
173 /**
174 * Check if phone number is international format
175 *
176 * This function could be improved. Either by using https://github.com/google/libphonenumber or creating our own library
177 *
178 * @since 3.0.4
179 */
180 public function check_international_number( $number ) {
181
182 //https://en.wikipedia.org/wiki/E.164 (Solomon islands has 8)
183 $min = 8;
184 $max = 15;
185
186 //without going into any more detail we are just going to check if the number starts with a + and has a minimum amount of numbers and a maximum
187 if ( substr( $number, 0, strlen( '+' ) ) && strlen( $number ) >= ( $min + 1 ) && strlen( $number ) <= ( $max + 1 ) ) {
188 return true;
189 }
190
191 return false;
192 }
193
194 /**
195 * Check if number is valid according to an array
196 *
197 * @since 3.0.4
198 */
199 public function check_number( $number, $valid_numbers ) {
200
201 foreach ( $valid_numbers as $start_digits=>$lenghts ) {
202 foreach ( $lenghts as $lenght ) {
203 if ( substr( $number, 0, strlen( $start_digits ) ) == $start_digits && strlen( $number ) == $lenght ) {
204 return true;
205 }
206 }
207 }
208
209 return false;
210 }
211
212 /**
213 * Label translation override for WPML (woocommerce_package_rates)
214 *
215 * @since 3.0.0
216 */
217 public function override_label_translation( $rates ) {
218
219 $id_instance = $this->id . ':' . $this->instance_id;
220
221 if ( array_key_exists( $id_instance, $rates ) ) {
222 $rates[$id_instance]->label = $this->title;
223 }
224
225 return $rates;
226 }
227
228 /**
229 * Title translation override for WPML (woocommerce_order_get_items)
230 *
231 * @since 3.0.0
232 */
233 public function override_shipping_title_translation( $items, $order ) {
234
235 foreach ( $items as $key => $item ) {
236
237 if ( $item['type'] == 'shipping' ) {
238 foreach ( $item['item_meta_array'] as $meta ) {
239
240 if ( $meta->key === 'method_id' ) {
241
242 $tmp = explode( ':', $meta->value );
243
244 if ( $tmp[0] == $this->id ) {
245 $items[$key]['name'] = $this->title;
246 }
247 }
248 }
249 }
250 }
251
252 return $items;
253 }
254
255 /**
256 * Sets default settings used by all shipping methods
257 *
258 * @since 3.0.0
259 */
260 final public function set_default_settings() {
261
262 $this->enable = !empty( $this->settings['active'] ) ? $this->settings['active'] : null;
263 $this->availability = 'specific';
264 $this->order_country = 'unknown';
265 $this->maximum_weight = !empty( $this->settings['maximum_weight']) ? ( double )$this->settings['maximum_weight'] : 0;
266 $this->free_shipping_min_amount = !empty( $this->settings['free_shipping_min_amount'] ) ? $this->settings['free_shipping_min_amount'] : 0;
267 $this->countries = !empty( $this->settings['countries'] ) ? $this->settings['countries'] : array();
268
269 //Overrides title if its set in settings already
270 $this->override_title();
271 }
272
273 /**
274 * Check if the shipping method is available (automatically called by parent \WC_Shipping_Method)
275 *
276 * @since 3.0.0
277 */
278 public function is_available( $package ) {
279
280 //check if cart weight exceeds max weight
281 if ( WC()->cart->cart_contents_weight > $this->maximum_weight ) {
282 return false;
283 }
284
285 $is_available = $this->enable === 'yes';
286
287 if ( !$is_available || !\MakeCommerce::is_api_set() ) {
288 return false;
289 }
290
291 $this->order_country = $package['destination']['country'];
292
293 return apply_filters( 'woocommerce_shipping_' . $this->id . '_is_available', $is_available, $package );
294 }
295
296 /**
297 * Calculate price for shipping
298 *
299 * @since 3.0.0
300 */
301 public function calculate_shipping( $package = array() ) {
302
303 $price = isset( $this->instance_settings['price'] ) ? $this->instance_settings['price'] : ( isset( $this->settings['price_'.$package['destination']['country']] ) ? $this->settings['price_'.$package['destination']['country']] : 0 );
304
305 $rate = array(
306 'id' => $this->get_rate_id(),
307 'label' => $this->title,
308 'cost' => $price,
309 'package' => $package,
310 'calc_tax' => 'per_order',
311 );
312
313 //check shippingclasses
314 $rate = $this->calculate_shipping_class_price( $rate, $package );
315
316 //check all free shipping options:
317 $free_shipping_min_amount = $this->instance_settings['free_shipping_min_amount'];
318
319 if ( $free_shipping_min_amount && $package['contents_cost'] >= $free_shipping_min_amount ) {
320 $rate["cost"] = 0;
321 }
322
323 //check only for parcelmachines
324 if ( $this->type == "apt" ) {
325
326 $free_shipping = true;
327 foreach ( $package['contents'] as $line ) {
328
329 $free_shipping = get_post_meta( $line['product_id'], '_no_shipping_cost', true ) === 'yes' ? $free_shipping : false;
330 }
331
332 if ( $free_shipping ) {
333 $rate["cost"] = 0;
334 }
335 }
336
337 //check if there is a free shipping coupon (if it's free then allow free shipping)
338 if ( isset( $package['applied_coupons'] ) && $this->instance_settings["allow_free_shipping_coupons"] === "yes" ) {
339 foreach ( $package['applied_coupons'] as $coupon_code ) {
340
341 $coupon = new \WC_Coupon( $coupon_code );
342 if ( $coupon->get_free_shipping() === true ) {
343 $rate["cost"] = 0;
344 break;
345 }
346 }
347 }
348
349 $this->add_rate( $rate );
350 }
351
352 /**
353 * This function overrides shipping method title
354 * if you have set language specific titles in admin.
355 *
356 * @since 3.0.0
357 */
358 final public function override_title() {
359
360 $language_code = \MakeCommerce\i18n::get_two_char_locale();
361
362 //default (no language)
363 if ( !empty( $this->settings['method_name'] ) ) {
364 $this->title = $this->settings['method_name'];
365 }
366
367 //if method name setting has been set with current language code
368 if ( !empty( $this->settings['method_name_' . $language_code] ) ) {
369 $this->title = $this->settings['method_name_' . $language_code];
370 }
371 }
372
373 /**
374 * Initializes basic fields used by all shipping methods.
375 *
376 * @since 3.0.0
377 */
378 public function initialize_form_fields() {
379
380 //Initialize instance form fields first
381 $this->initialize_instance_form_fields();
382
383 //Initialize basic form fields
384 $this->initialize_basic_form_fields();
385
386 //Initialize method specific form fields
387 $this->initialize_method_type_form_fields();
388
389 //Initialize return address fields
390 $this->initalize_return_addres_form_fields();
391 }
392
393 /**
394 * Initializes basic shared form fields
395 * Used by all shipping methods
396 *
397 * @since 3.0.0
398 */
399 final public function initialize_basic_form_fields() {
400
401 $this->form_fields = array();
402
403 $this->form_fields['logo'] = array(
404 'type' => 'title',
405 'description' => \MakeCommerce::get_logo_html()
406 );
407
408 $this->form_fields['generic'] = array(
409 'type' => 'title',
410 'title' => __( 'Generic and pricing options', 'wc_makecommerce_domain' ),
411 );
412
413 $this->form_fields['active'] = array(
414 'title' => __( 'Enable', 'wc_makecommerce_domain' ),
415 'type' => 'checkbox',
416 'label' => __( 'enabled', 'wc_makecommerce_domain' ),
417 'default' => 'no',
418 );
419
420 $this->form_fields['maximum_weight'] = array(
421 'title' => sprintf( __( 'Maximum weight allowed for shipping (%s)', 'wc_makecommerce_domain' ), get_option( 'woocommerce_weight_unit' ) ),
422 'type' => 'text',
423 'default' => $this->default_max_weight
424 );
425
426 $this->form_fields['look_and_feel'] = array(
427 'type' => 'title',
428 'title' => '<hr><br>'.__( 'Look and feel options', 'wc_makecommerce_domain' ),
429 'description' => __( 'Options for presentation on check-out page', 'wc_makecommerce_domain' )
430 );
431
432 //get a list of all active languages
433 $languages = \MakeCommerce\i18n::get_active_languages();
434
435 if ( empty( $languages ) ) {
436
437 $this->form_fields['method_name'] = array(
438 'title' => __( 'Shipping Method Title', 'wc_makecommerce_domain' ),
439 'type' => 'text',
440 'default' => $this->carrier . " " . \MakeCommerce\i18n::get_string_from_mo( $this->identifier, 'wc_makecommerce_domain', \MakeCommerce\i18n::get_two_char_locale() )
441 );
442 } else {
443 foreach ( $languages as $language_code => $language ) {
444 $this->form_fields['method_name_'.substr( $language_code, 0, 2 )] = array(
445 'title' => __('Shipping Method Title', 'wc_makecommerce_domain').sprintf(' (%s)', substr($language_code, 0, 2)),
446 'type' => 'text',
447 'default' => $this->carrier . " " . \MakeCommerce\i18n::get_string_from_mo( $this->identifier, 'wc_makecommerce_domain', substr( $language_code, 0, 2 ) )
448 );
449 }
450 }
451
452 $this->initialize_method_type_checkout_fields();
453
454 if ( \MakeCommerce::new_woo_version() ) {
455 $a = 'admin.php?page=wc-settings&tab=advanced&section=mk_api';
456 } else {
457 $a = 'admin.php?page=wc-settings&tab=api&section=mk_api';
458 }
459
460 $this->form_fields['api_access'] = array(
461 'type' => 'title',
462 'title' => '<hr><br>'.__( 'API access for', 'wc_makecommerce_domain' ).' '.$this->carrier,
463 'description' => sprintf(__('You can automatically create shipments into %s system and print the out the package labels right here, at the shop orders view. <br> Please set your %s web services account credentials below here. <br>(see more on <a href="https://makecommerce.net/en/integration-modules/makecommerce-woocommerce-payment-plugin/#carriers-integration">MakeCommerce plugin page</a>. Don\'t forget to enable also <a href="%s">MC API keys</a>!)', 'wc_makecommerce_domain' ), $this->carrier, $this->carrier, admin_url( $a ) )
464 );
465 }
466
467 /**
468 * Initializes basic instance fields used by all shipping methods.
469 * Automatically called by \WC_Shipping_Method
470 *
471 * @since 3.0.0
472 */
473 final public function initialize_instance_form_fields() {
474
475 $this->instance_form_fields = array();
476
477 $this->instance_form_fields['logo'] = array(
478 'type' => 'title',
479 'description' => \MakeCommerce::get_logo_html()
480 );
481
482 $this->instance_form_fields['price'] = array(
483 'title' => __('Shipping price', 'wc_makecommerce_domain'),
484 'type' => 'text',
485 'default' => $this->default_price
486 );
487
488 $this->instance_form_fields['free_shipping_min_amount'] = array(
489 'title' => __('Free shipping amount', 'wc_makecommerce_domain'),
490 'type' => 'number',
491 'default' => '0',
492 'desc_tip' => __( '(0 means no free shipping)', 'wc_makecommerce_domain' ),
493 );
494
495 $this->instance_form_fields['allow_free_shipping_coupons'] = array(
496 'title' => __( 'Free shipping coupons', 'wc_makecommerce_domain' ),
497 'type' => 'checkbox',
498 'default' => 'no',
499 'desc_tip' => __( 'Allow using free shipping coupons to be used with this method', 'wc_makecommerce_domain' ),
500 );
501
502 $this->instance_form_fields = $this->add_form_fields( $this->instance_form_fields );
503 }
504
505 /**
506 * Initializes return address form fields
507 * Used by all shipping methods
508 *
509 * @since 3.0.0
510 */
511 final public function initalize_return_addres_form_fields() {
512
513 $this->form_fields['return_address'] = array(
514 'type' => 'title',
515 'title' => __( 'Return address', 'wc_makecommerce_domain' ),
516 'description' => sprintf( __( 'Please define return address for %s shipments', 'wc_makecommerce_domain' ), $this->carrier )
517 );
518
519 $this->form_fields['shop_name'] = array(
520 'type' => 'text',
521 'title' => __( 'Shop name', 'wc_makecommerce_domain' ),
522 'class' => 'input-text regular-input',
523 );
524
525 $this->form_fields['shop_phone'] = array(
526 'type' => 'text',
527 'title' => __( 'Shop phone', 'wc_makecommerce_domain' ),
528 'class' => 'input-text regular-input',
529 );
530
531 $this->form_fields['shop_email'] = array(
532 'type' => 'text',
533 'title' => __( 'Shop email', 'wc_makecommerce_domain' ),
534 'class' => 'input-text regular-input',
535 );
536
537 $this->form_fields['shop_address_country'] = array(
538 'type' => 'select',
539 'title' => __( 'Shop address country', 'wc_makecommerce_domain' ),
540 'options' => array(
541 'EE' => 'EE',
542 'LV' => 'LV',
543 'LT' => 'LT',
544 ),
545 'default' => 'EE',
546 );
547
548 $this->form_fields['shop_address_city'] = array(
549 'type' => 'text',
550 'title' => __( 'Shop address city', 'wc_makecommerce_domain' ),
551 'class' => 'input-text regular-input',
552 );
553
554 $this->form_fields['shop_address_street'] = array(
555 'type' => 'text',
556 'title' => __( 'Shop address street', 'wc_makecommerce_domain' ),
557 'class' => 'input-text regular-input',
558 );
559
560 $this->form_fields['shop_postal_code'] = array(
561 'type' => 'text',
562 'title' => __( 'Shop postal code', 'wc_makecommerce_domain' ),
563 'class' => 'input-text regular-input',
564 );
565 }
566
567 /**
568 * Initializes method type, required function for all method types
569 *
570 * @since 3.0.0
571 */
572 abstract public function initialize();
573
574 /**
575 * Initializes method type form fields
576 *
577 * @since 3.0.0
578 */
579 abstract public function initialize_method_type_form_fields();
580
581 /**
582 * Sets title of the method
583 *
584 * @since 3.0.0
585 */
586 abstract public function return_method_title();
587
588 /**
589 * Returns phone validation error
590 *
591 * @since 3.0.4
592 */
593 abstract public function phone_number_validation_error();
594 }
595