abstract-wc-shipping-method.php
6.59 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
<?php
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly
}
/**
* WooCommerce Shipping Method Class.
*
* Extended by shipping methods to handle shipping calculations etc.
*
* @class WC_Shipping_Method
* @version 2.3.0
* @package WooCommerce/Abstracts
* @category Abstract Class
* @author WooThemes
*/
abstract class WC_Shipping_Method extends WC_Settings_API {
/** @var string Unique ID for the shipping method - must be set. */
public $id;
/** @var int Optional instance ID. */
public $number;
/** @var string Method title */
public $method_title;
/** @var string User set title */
public $title;
/** @var bool True if the method is available. */
public $availability;
/** @var array Array of countries this method is enabled for. */
public $countries = array();
/** @var string If 'taxable' tax will be charged for this method (if applicable) */
public $tax_status = 'taxable';
/** @var mixed Fees for the method */
public $fee = 0;
/** @var float Minimum fee for the method */
public $minimum_fee = null;
/** @var bool Enabled for disabled */
public $enabled = false;
/** @var bool Whether the method has settings or not (In WooCommerce > Settings > Shipping) */
public $has_settings = true;
/** @var array Features this method supports. */
public $supports = array();
/** @var array This is an array of rates - methods must populate this array to register shipping costs */
public $rates = array();
/**
* Whether or not we need to calculate tax on top of the shipping rate.
*
* @return boolean
*/
public function is_taxable() {
return ( wc_tax_enabled() && $this->tax_status == 'taxable' && ! WC()->customer->is_vat_exempt() );
}
/**
* Add a rate.
*
* Add a shipping rate. If taxes are not set they will be calculated based on cost.
*
* @param array $args (default: array())
*/
public function add_rate( $args = array() ) {
$args = wp_parse_args( $args, array(
'id' => '', // ID for the rate
'label' => '', // Label for the rate
'cost' => '0', // Amount or array of costs (per item shipping)
'taxes' => '', // Pass taxes, nothing to have it calculated for you, or 'false' to calc no tax
'calc_tax' => 'per_order' // Calc tax per_order or per_item. Per item needs an array of costs
) );
// Id and label are required
if ( ! $args['id'] || ! $args['label'] ) {
return;
}
// Total up the cost
$total_cost = is_array( $args['cost'] ) ? array_sum( $args['cost'] ) : $args['cost'];
$taxes = $args['taxes'];
// Taxes - if not an array and not set to false, calc tax based on cost and passed calc_tax variable
// This saves shipping methods having to do complex tax calculations
if ( ! is_array( $taxes ) && $taxes !== false && $total_cost > 0 && $this->is_taxable() ) {
$taxes = array();
switch ( $args['calc_tax'] ) {
case "per_item" :
// If we have an array of costs we can look up each items tax class and add tax accordingly
if ( is_array( $args['cost'] ) ) {
$cart = WC()->cart->get_cart();
foreach ( $args['cost'] as $cost_key => $amount ) {
if ( ! isset( $cart[ $cost_key ] ) ) {
continue;
}
$item_taxes = WC_Tax::calc_shipping_tax( $amount, WC_Tax::get_shipping_tax_rates( $cart[ $cost_key ]['data']->get_tax_class() ) );
// Sum the item taxes
foreach ( array_keys( $taxes + $item_taxes ) as $key ) {
$taxes[ $key ] = ( isset( $item_taxes[ $key ] ) ? $item_taxes[ $key ] : 0 ) + ( isset( $taxes[ $key ] ) ? $taxes[ $key ] : 0 );
}
}
// Add any cost for the order - order costs are in the key 'order'
if ( isset( $args['cost']['order'] ) ) {
$item_taxes = WC_Tax::calc_shipping_tax( $args['cost']['order'], WC_Tax::get_shipping_tax_rates() );
// Sum the item taxes
foreach ( array_keys( $taxes + $item_taxes ) as $key ) {
$taxes[ $key ] = ( isset( $item_taxes[ $key ] ) ? $item_taxes[ $key ] : 0 ) + ( isset( $taxes[ $key ] ) ? $taxes[ $key ] : 0 );
}
}
}
break;
default :
$taxes = WC_Tax::calc_shipping_tax( $total_cost, WC_Tax::get_shipping_tax_rates() );
break;
}
}
// Round the total cost after taxes have been calculated.
$total_cost = wc_format_decimal( $total_cost, wc_get_price_decimals() );
$this->rates[] = new WC_Shipping_Rate( $args['id'], $args['label'], $total_cost, $taxes, $this->id );
}
/**
* Check if the shipping method has settings or not.
*
* @return bool
*/
public function has_settings() {
return $this->has_settings;
}
/**
* Check if shipping method is available or not.
*
* @param array $package
* @return bool
*/
public function is_available( $package ) {
if ( 'no' == $this->enabled ) {
return false;
}
// Country availability
$countries = is_array( $this->countries ) ? $this->countries : array();
switch ( $this->availability ) {
case 'specific' :
case 'including' :
$ship_to_countries = array_intersect( $countries, array_keys( WC()->countries->get_shipping_countries() ) );
break;
case 'excluding' :
$ship_to_countries = array_diff( array_keys( WC()->countries->get_shipping_countries() ), $countries );
break;
default :
$ship_to_countries = array_keys( WC()->countries->get_shipping_countries() );
break;
}
if ( ! in_array( $package['destination']['country'], $ship_to_countries ) ) {
return false;
}
return apply_filters( 'woocommerce_shipping_' . $this->id . '_is_available', true, $package );
}
/**
* Return the shipping method title.
*
* @return string
*/
public function get_title() {
return apply_filters( 'woocommerce_shipping_method_title', $this->title, $this->id );
}
/**
* Get fee for the shipping method.
*
* @param mixed $fee
* @param mixed $total
* @return float
*/
public function get_fee( $fee, $total ) {
if ( strstr( $fee, '%' ) ) {
$fee = ( $total / 100 ) * str_replace( '%', '', $fee );
}
if ( ! empty( $this->minimum_fee ) && $this->minimum_fee > $fee ) {
$fee = $this->minimum_fee;
}
return $fee;
}
/**
* Check if a shipping method supports a given feature.
*
* Methods should override this to declare support (or lack of support) for a feature.
*
* @param $feature string The name of a feature to test support for.
* @return bool True if the gateway supports the feature, false otherwise.
* @since 1.5.7
*/
public function supports( $feature ) {
return apply_filters( 'woocommerce_shipping_method_supports', in_array( $feature, $this->supports ) ? true : false, $feature, $this );
}
}