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