Completed
Push — master ( cb6ae8...5ae7ff )
by Harald
03:13
created

zones::__construct()   B

Complexity

Conditions 5
Paths 16

Size

Total Lines 12
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 5
eloc 9
nc 16
nop 0
dl 0
loc 12
rs 8.8571
c 0
b 0
f 0
1
<?php
2
/**
3
  * osCommerce Online Merchant
4
  *
5
  * @copyright (c) 2016 osCommerce; https://www.oscommerce.com
6
  * @license MIT; https://www.oscommerce.com/license/mit.txt
7
  */
8
9
/*
10
  USAGE
11
  By default, the module comes with support for 1 zone.  This can be
12
  easily changed by editing the line below in the zones constructor
13
  that defines $this->num_zones.
14
15
  Next, you will want to activate the module by going to the Admin screen,
16
  clicking on Modules, then clicking on Shipping.  A list of all shipping
17
  modules should appear.  Click on the green dot next to the one labeled
18
  zones.php.  A list of settings will appear to the right.  Click on the
19
  Edit button.
20
21
  PLEASE NOTE THAT YOU WILL LOSE YOUR CURRENT SHIPPING RATES AND OTHER
22
  SETTINGS IF YOU TURN OFF THIS SHIPPING METHOD.  Make sure you keep a
23
  backup of your shipping settings somewhere at all times.
24
25
  If you want an additional handling charge applied to orders that use this
26
  method, set the Handling Fee field.
27
28
  Next, you will need to define which countries are in each zone.  Determining
29
  this might take some time and effort.  You should group a set of countries
30
  that has similar shipping charges for the same weight.  For instance, when
31
  shipping from the US, the countries of Japan, Australia, New Zealand, and
32
  Singapore have similar shipping rates.  As an example, one of my customers
33
  is using this set of zones:
34
    1: USA
35
    2: Canada
36
    3: Austria, Belgium, Great Britain, France, Germany, Greenland, Iceland,
37
       Ireland, Italy, Norway, Holland/Netherlands, Denmark, Poland, Spain,
38
       Sweden, Switzerland, Finland, Portugal, Israel, Greece
39
    4: Japan, Australia, New Zealand, Singapore
40
    5: Taiwan, China, Hong Kong
41
42
  When you enter these country lists, enter them into the Zone X Countries
43
  fields, where "X" is the number of the zone.  They should be entered as
44
  two character ISO country codes in all capital letters.  They should be
45
  separated by commas with no spaces or other punctuation. For example:
46
    1: US
47
    2: CA
48
    3: AT,BE,GB,FR,DE,GL,IS,IE,IT,NO,NL,DK,PL,ES,SE,CH,FI,PT,IL,GR
49
    4: JP,AU,NZ,SG
50
    5: TW,CN,HK
51
52
  Now you need to set up the shipping rate tables for each zone.  Again,
53
  some time and effort will go into setting the appropriate rates.  You
54
  will define a set of weight ranges and the shipping price for each
55
  range.  For instance, you might want an order than weighs more than 0
56
  and less than or equal to 3 to cost 5.50 to ship to a certain zone.
57
  This would be defined by this:  3:5.5
58
59
  You should combine a bunch of these rates together in a comma delimited
60
  list and enter them into the "Zone X Shipping Table" fields where "X"
61
  is the zone number.  For example, this might be used for Zone 1:
62
    1:3.5,2:3.95,3:5.2,4:6.45,5:7.7,6:10.4,7:11.85, 8:13.3,9:14.75,10:16.2,11:17.65,
63
    12:19.1,13:20.55,14:22,15:23.45
64
65
  The above example includes weights over 0 and up to 15.  Note that
66
  units are not specified in this explanation since they should be
67
  specific to your locale.
68
69
  CAVEATS
70
  At this time, it does not deal with weights that are above the highest amount
71
  defined.  This will probably be the next area to be improved with the
72
  module.  For now, you could have one last very high range with a very
73
  high shipping rate to discourage orders of that magnitude.  For
74
  instance:  999:1000
75
76
  If you want to be able to ship to any country in the world, you will
77
  need to enter every country code into the Country fields. For most
78
  shops, you will not want to enter every country.  This is often
79
  because of too much fraud from certain places. If a country is not
80
  listed, then the module will add a $0.00 shipping charge and will
81
  indicate that shipping is not available to that destination.
82
  PLEASE NOTE THAT THE ORDER CAN STILL BE COMPLETED AND PROCESSED!
83
84
  It appears that the osC shipping system automatically rounds the
85
  shipping weight up to the nearest whole unit.  This makes it more
86
  difficult to design precise shipping tables.  If you want to, you
87
  can hack the shipping.php file to get rid of the rounding.
88
89
  Lastly, there is a limit of 255 characters on each of the Zone
90
  Shipping Tables and Zone Countries.
91
92
*/
93
94
  use OSC\OM\HTML;
95
  use OSC\OM\OSCOM;
96
  use OSC\OM\Registry;
97
98
  class zones {
99
    var $code, $title, $description, $enabled, $num_zones;
100
101
// class constructor
102
    function __construct() {
103
      $this->code = 'zones';
104
      $this->title = OSCOM::getDef('module_shipping_zones_text_title');
105
      $this->description = OSCOM::getDef('module_shipping_zones_text_description');
106
      $this->sort_order = defined('MODULE_SHIPPING_ZONES_SORT_ORDER') ? (int)MODULE_SHIPPING_ZONES_SORT_ORDER : 0;
0 ignored issues
show
Bug introduced by
The property sort_order does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
107
      $this->icon = '';
0 ignored issues
show
Bug introduced by
The property icon does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
108
      $this->tax_class = defined('MODULE_SHIPPING_ZONES_TAX_CLASS') ? MODULE_SHIPPING_ZONES_TAX_CLASS : 0;
0 ignored issues
show
Bug introduced by
The property tax_class does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
109
      $this->enabled = (defined('MODULE_SHIPPING_ZONES_STATUS') && (MODULE_SHIPPING_ZONES_STATUS == 'True') ? true : false);
110
111
      // CUSTOMIZE THIS SETTING FOR THE NUMBER OF ZONES NEEDED
112
      $this->num_zones = 1;
113
    }
114
115
// class methods
116
    function quote($method = '') {
0 ignored issues
show
Unused Code introduced by
The parameter $method is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
117
      global $order, $shipping_weight, $shipping_num_boxes;
118
119
      $dest_country = $order->delivery['country']['iso_code_2'];
120
      $dest_zone = 0;
121
      $error = false;
122
123
      for ($i=1; $i<=$this->num_zones; $i++) {
124
        $countries_table = constant('MODULE_SHIPPING_ZONES_COUNTRIES_' . $i);
125
        $country_zones = preg_split("/[,]/", $countries_table);
126
        if (in_array($dest_country, $country_zones)) {
127
          $dest_zone = $i;
128
          break;
129
        }
130
      }
131
132
      if ($dest_zone == 0) {
133
        $error = true;
134
      } else {
135
        $shipping = -1;
136
        $zones_cost = constant('MODULE_SHIPPING_ZONES_COST_' . $dest_zone);
137
138
        $zones_table = preg_split("/[:,]/" , $zones_cost);
139
        $size = sizeof($zones_table);
140
        for ($i=0; $i<$size; $i+=2) {
141
          if ($shipping_weight <= $zones_table[$i]) {
142
            $shipping = $zones_table[$i+1];
143
            $shipping_method = OSCOM::getDef('module_shipping_zones_text_way') . ' ' . $dest_country . ' : ' . $shipping_weight . ' ' . OSCOM::getDef('module_shipping_zones_text_units');
144
            break;
145
          }
146
        }
147
148
        if ($shipping == -1) {
149
          $shipping_cost = 0;
150
          $shipping_method = OSCOM::getDef('module_shipping_zones_undefined_rate');
151
        } else {
152
          $shipping_cost = ($shipping * $shipping_num_boxes) + constant('MODULE_SHIPPING_ZONES_HANDLING_' . $dest_zone);
153
        }
154
      }
155
156
      $this->quotes = array('id' => $this->code,
0 ignored issues
show
Bug introduced by
The property quotes does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
157
                            'module' => OSCOM::getDef('module_shipping_zones_text_title'),
158
                            'methods' => array(array('id' => $this->code,
159
                                                     'title' => $shipping_method,
0 ignored issues
show
Bug introduced by
The variable $shipping_method does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
160
                                                     'cost' => $shipping_cost)));
0 ignored issues
show
Bug introduced by
The variable $shipping_cost does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
161
162 View Code Duplication
      if ($this->tax_class > 0) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
163
        $this->quotes['tax'] = tep_get_tax_rate($this->tax_class, $order->delivery['country']['id'], $order->delivery['zone_id']);
164
      }
165
166 View Code Duplication
      if (tep_not_null($this->icon)) $this->quotes['icon'] = HTML::image($this->icon, $this->title);
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
167
168
      if ($error == true) $this->quotes['error'] = OSCOM::getDef('module_shipping_zones_invalid_zone');
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like you are loosely comparing two booleans. Considering using the strict comparison === instead.

When comparing two booleans, it is generally considered safer to use the strict comparison operator.

Loading history...
169
170
      return $this->quotes;
171
    }
172
173
    function check() {
174
      return defined('MODULE_SHIPPING_ZONES_STATUS');
175
    }
176
177
    function install() {
178
      $OSCOM_Db = Registry::get('Db');
179
180
      $OSCOM_Db->save('configuration', [
181
        'configuration_title' => 'Enable Zones Method',
182
        'configuration_key' => 'MODULE_SHIPPING_ZONES_STATUS',
183
        'configuration_value' => 'True',
184
        'configuration_description' => 'Do you want to offer zone rate shipping?',
185
        'configuration_group_id' => '6',
186
        'sort_order' => '1',
187
        'set_function' => 'tep_cfg_select_option(array(\'True\', \'False\'), ',
188
        'date_added' => 'now()'
189
      ]);
190
191
      $OSCOM_Db->save('configuration', [
192
        'configuration_title' => 'Tax Class',
193
        'configuration_key' => 'MODULE_SHIPPING_ZONES_TAX_CLASS',
194
        'configuration_value' => '0',
195
        'configuration_description' => 'Use the following tax class on the shipping fee.',
196
        'configuration_group_id' => '6',
197
        'sort_order' => '1',
198
        'use_function' => 'tep_get_tax_class_title',
199
        'set_function' => 'tep_cfg_pull_down_tax_classes(',
200
        'date_added' => 'now()'
201
      ]);
202
203
      $OSCOM_Db->save('configuration', [
204
        'configuration_title' => 'Sort Order',
205
        'configuration_key' => 'MODULE_SHIPPING_ZONES_SORT_ORDER',
206
        'configuration_value' => '0',
207
        'configuration_description' => 'Sort order of display. Lowest is displayed first.',
208
        'configuration_group_id' => '6',
209
        'sort_order' => '0',
210
        'date_added' => 'now()'
211
      ]);
212
213
      for ($i = 1; $i <= $this->num_zones; $i++) {
214
        $default_countries = '';
215
        if ($i == 1) {
216
          $default_countries = 'US,CA';
217
        }
218
219
        $OSCOM_Db->save('configuration', [
220
          'configuration_title' => 'Zone ' . $i . ' Countries',
221
          'configuration_key' => 'MODULE_SHIPPING_ZONES_COUNTRIES_' . $i,
222
          'configuration_value' => $default_countries,
223
          'configuration_description' => 'Comma separated list of two character ISO country codes that are part of Zone ' . $i . '.',
224
          'configuration_group_id' => '6',
225
          'sort_order' => '0',
226
          'date_added' => 'now()'
227
        ]);
228
229
        $OSCOM_Db->save('configuration', [
230
          'configuration_title' => 'Zone ' . $i . ' Shipping Table',
231
          'configuration_key' => 'MODULE_SHIPPING_ZONES_COST_' . $i,
232
          'configuration_value' => '3:8.50,7:10.50,99:20.00',
233
          'configuration_description' => 'Shipping rates to Zone ' . $i . ' destinations based on a group of maximum order weights. Example: 3:8.50,7:10.50,... Weights less than or equal to 3 would cost 8.50 for Zone ' . $i . ' destinations.',
234
          'configuration_group_id' => '6',
235
          'sort_order' => '0',
236
          'date_added' => 'now()'
237
        ]);
238
239
        $OSCOM_Db->save('configuration', [
240
          'configuration_title' => 'Zone ' . $i . ' Handling Fee',
241
          'configuration_key' => 'MODULE_SHIPPING_ZONES_HANDLING_' . $i,
242
          'configuration_value' => '0',
243
          'configuration_description' => 'Handling Fee for this shipping zone',
244
          'configuration_group_id' => '6',
245
          'sort_order' => '0',
246
          'date_added' => 'now()'
247
        ]);
248
      }
249
    }
250
251
    function remove() {
252
      return Registry::get('Db')->exec('delete from :table_configuration where configuration_key in ("' . implode('", "', $this->keys()) . '")');
253
    }
254
255
    function keys() {
256
      $keys = array('MODULE_SHIPPING_ZONES_STATUS', 'MODULE_SHIPPING_ZONES_TAX_CLASS', 'MODULE_SHIPPING_ZONES_SORT_ORDER');
257
258
      for ($i=1; $i<=$this->num_zones; $i++) {
259
        $keys[] = 'MODULE_SHIPPING_ZONES_COUNTRIES_' . $i;
260
        $keys[] = 'MODULE_SHIPPING_ZONES_COST_' . $i;
261
        $keys[] = 'MODULE_SHIPPING_ZONES_HANDLING_' . $i;
262
      }
263
264
      return $keys;
265
    }
266
  }
267
?>
0 ignored issues
show
Best Practice introduced by
It is not recommended to use PHP's closing tag ?> in files other than templates.

Using a closing tag in PHP files that only contain PHP code is not recommended as you might accidentally add whitespace after the closing tag which would then be output by PHP. This can cause severe problems, for example headers cannot be sent anymore.

A simple precaution is to leave off the closing tag as it is not required, and it also has no negative effects whatsoever.

Loading history...
268