australiapost

WP eCommerce Australia Post shipping module - http://auspost.com.au.

Defined (1)

The class is defined in the following location(s).

/wpsc-shipping/australiapost.php  
  1. class australiapost { 
  2. var $internal_name, $name; 
  3.  
  4. /** 
  5. * List of Valid Australia Post services 
  6. * @var Array 
  7. */ 
  8. var $services = array(); 
  9.  
  10. /** 
  11. * Shipping module settings 
  12. * @var Array 
  13. */ 
  14. var $settings; 
  15.  
  16. var $base_country; 
  17. var $base_zipcode; 
  18.  
  19. /** 
  20. * Constructor 
  21. */ 
  22. function australiapost () { 
  23. $this->internal_name = "australiapost"; 
  24. $this->name = __( 'Australia Post', 'wpsc' ); 
  25. $this->is_external = true; 
  26. $this->requires_weight = true; 
  27. $this->needs_zipcode = true; 
  28. $this->debug = false; // change to true to log (to the PHP error log) the API URLs and responses for each active service 
  29.  
  30. // Initialise the list of available postage services 
  31.  
  32. // DOMESTIC (Australia only) 
  33. $this->services['STANDARD'] = __('Standard Parcel Post', 'wpsc'); 
  34. $this->services['EXPRESS'] = __('Express Post', 'wpsc'); 
  35.  
  36. // INTERNATIONAL 
  37. $this->services['AIR'] = __('Air Mail', 'wpsc'); 
  38. $this->services['SEA'] = __('Sea Mail', 'wpsc'); 
  39. $this->services['ECI_M'] = __('Express Courier International', 'wpsc'); // Express Courier International Merchandise 
  40. $this->services['EPI'] = __('Express Post International', 'wpsc'); 
  41.  
  42. // Attempt to load the existing settings 
  43. $this->settings = get_option("wpsc_australiapost_settings"); 
  44.  
  45. $this->base_country = get_option('base_country'); 
  46. $this->base_zipcode = get_option('base_zipcode'); 
  47.  
  48. if (!$this->settings) { 
  49. // Initialise the settings 
  50. $this->settings = array(); 
  51. foreach ($this->services as $code => $value) { 
  52. $this->settings['services'][$code] = true; 
  53. update_option('wpsc_australiapost_settings', $this->settings); 
  54.  
  55. return true; 
  56.  
  57. function getId() { 
  58.  
  59. function setId($id) { 
  60.  
  61. function getName() { 
  62. return $this->name; 
  63.  
  64. function getInternalName() { 
  65. return $this->internal_name; 
  66.  
  67. function getForm() { 
  68. $output = ''; 
  69. // Only for Australian merchants 
  70. if ($this->base_country != 'AU') { 
  71. return "<tr><td colspan='2'>" . __('This shipping module only works if the base country in settings, region is set to Australia.', 'wpsc') . "</td></tr>"; 
  72.  
  73. // Base postcode must be set 
  74. if (strlen($this->base_zipcode) != 4) { 
  75. return "<tr><td colspan='2'>" .__('You must set your base postcode above before this shipping module will work.', 'wpsc') . "</td></tr>"; 
  76.  
  77. $output .= "<tr><td>" . __('Select the Australia Post services that you want to offer during checkout:', 'wpsc') . "</td></tr>"; 
  78. $output .= "<tr><td>"; 
  79. foreach ($this->services as $code => $value) { 
  80. $checked = $this->settings['services'][$code] ? "checked='checked'" : ''; 
  81. $output .= "<label style=\"margin-left: 50px;\">"; 
  82. $output .= "<input type='checkbox' {$checked} name='wpsc_australiapost_settings[services][{$code}]'/> "; 
  83. $output .= $this->services[$code]; 
  84. $output .= "</label><br />"; 
  85. $output .= "<input type='hidden' name='{$this->internal_name}_updateoptions' value='true'>"; 
  86. $output .= "</td></tr>"; 
  87. $output .= "<tr><td><h4>" . __('Notes:', 'wpsc') . "</h4>"; 
  88. $output .= __('1. The actual services quoted to the customer during checkout will depend on the destination country. Not all methods are available to all destinations.', 'wpsc') . "<br />"; 
  89. $output .= __('2. Each product must have a valid weight configured. When editing a product, use the weight field.', 'wpsc') . "<br />"; 
  90. $output .= __('3. To ensure accurate quotes, each product must valid dimensions configured. When editing a product, use the height, width and length fields.', 'wpsc') . "<br />"; 
  91. $output .= __('4. The combined dimensions are estimated by calculating the volume of each item, and then calculating the cubed root of the overall order volume which becomes width, length and height.', 'wpsc') . "<br />"; 
  92. $output .= __('5. If no product dimensions are defined, then default package dimensions of 100mm x 100mm x 100mm will be used.', 'wpsc') . "<br />"; 
  93. $output .= "</tr></td>"; 
  94. return $output; 
  95.  
  96. function submit_form() { 
  97. $this->settings['services'] = array(); 
  98.  
  99. // Only continue if this module's options were updated 
  100. if ( !isset($_POST["{$this->internal_name}_updateoptions"]) || !$_POST["{$this->internal_name}_updateoptions"] ) return; 
  101.  
  102. if (isset($_POST['wpsc_australiapost_settings'])) { 
  103. if (isset($_POST['wpsc_australiapost_settings']['services'])) { 
  104. foreach ($this->services as $code => $name) { 
  105. $this->settings['services'][$code] = isset($_POST['wpsc_australiapost_settings']['services'][$code]) ? true : false; 
  106.  
  107. update_option('wpsc_australiapost_settings', $this->settings); 
  108. return true; 
  109.  
  110. function getQuote() { 
  111. global $wpdb, $wpsc_cart; 
  112.  
  113. if ($this->base_country != 'AU' || strlen($this->base_zipcode) != 4 || !count($wpsc_cart->cart_items)) return; 
  114.  
  115. $dest = wpsc_get_customer_meta( 'shipping_country' ); 
  116.  
  117. $destzipcode = (string) wpsc_get_customer_meta( 'shipping_zip' ); 
  118. if( isset($_POST['zipcode'] ) ) { 
  119. $destzipcode = $_POST['zipcode']; 
  120. wpsc_update_customer_meta( 'shipping_zip', $destzipcode ); 
  121.  
  122. if ($dest == 'AU' && strlen($destzipcode) != 4) { 
  123. // Invalid Australian Post Code entered, so just return an empty set of quotes instead of wasting time contactin the Aus Post API 
  124. return array(); 
  125.  
  126. /** 
  127. 3 possible scenarios: 
  128.   
  129. 1. 
  130. Cart consists of only item(s) that have "disregard shipping" ticked. 
  131.   
  132. In this case, WPEC doesn't mention shipping at all during checkout, and this shipping module probably won't be executed at all. 
  133.   
  134. Just in case it does get queried, we should still query the Australia Post API for valid shipping estimates,  
  135. and then override the quoted price(s) to $0.00 so the customer is able to get free shipping. 
  136.   
  137.   
  138. 2. 
  139. Cart consists of only item(s) where "disregard shipping" isn't ticked (ie. all item(s) attract shipping charges). 
  140.   
  141. In this case, we should query the Australia Post API as per normal. 
  142.   
  143.   
  144. 3. 
  145. Cart consists of one or more "disregard shipping" product(s), and one or more other products that attract shipping charges. 
  146.   
  147. In this case, we should query the Aus Post API, only taking into account the product(s) that attract shipping charges. 
  148. Products with "disregard shipping" ticked shouldn't have their weight or dimensions included in the quote. 
  149. */ 
  150.  
  151.  
  152. // Obtain the total combined weight for all items(s) in the cart (excluding items that have the "Disregard Shipping for this product" option ticked) 
  153. // Weight is in grams 
  154. $weight = wpsc_convert_weight($wpsc_cart->calculate_total_weight(true), 'pound', 'gram'); 
  155.  
  156. // Calculate the total cart dimensions by adding the volume of each product then calculating the cubed root 
  157. $volume = 0; 
  158.  
  159. // Total number of item(s) in the cart 
  160. $numItems = count($wpsc_cart->cart_items); 
  161.  
  162. if ($numItems == 0) { 
  163. // The customer's cart is empty. This probably shouldn't occur, but just in case! 
  164. return array(); 
  165.  
  166. // Total number of item(s) that don't attract shipping charges. 
  167. $numItemsWithDisregardShippingTicked = 0; 
  168.  
  169. foreach($wpsc_cart->cart_items as $cart_item) { 
  170.  
  171. if ( !$cart_item->uses_shipping ) { 
  172. // The "Disregard Shipping for this product" option is ticked for this item. 
  173. // Don't include it in the shipping quote. 
  174. $numItemsWithDisregardShippingTicked++; 
  175. continue; 
  176.  
  177. // If we are here then this item attracts shipping charges. 
  178.  
  179. $meta = get_product_meta($cart_item->product_id, 'product_metadata', true); 
  180. $meta = $meta['dimensions']; 
  181.  
  182. if ($meta && is_array($meta)) { 
  183. $productVolume = 1; 
  184. foreach (array('width', 'height', 'length') as $dimension) { 
  185. // default dimension to 100mm 
  186. if ( empty( $meta[$dimension] ) ) { 
  187. $meta[$dimension] = 100; 
  188. $meta["{$dimension}_unit"] = 'mm'; 
  189. switch ($meta["{$dimension}_unit"]) { 
  190. // we need the units in mm 
  191. case 'cm': 
  192. // convert from cm to mm 
  193. $meta[$dimension] *= 10; 
  194. break; 
  195. case 'meter': 
  196. // convert from m to mm 
  197. $meta[$dimension] *= 1000; 
  198. break; 
  199. case 'in': 
  200. // convert from in to mm 
  201. $meta[$dimension] *= 25.4; 
  202. break; 
  203.  
  204. $productVolume *= $meta[$dimension]; 
  205.  
  206. $volume += floatval($productVolume) * $cart_item->quantity; 
  207.  
  208. // If there's only one item in the cart, its dimensions will be used 
  209. // But if there are multiple items, cubic root of total volume will be used instead 
  210. if ( $wpsc_cart->get_total_shipping_quantity() == 1 ) { 
  211. $height = $meta['height']; 
  212. $width = $meta['width']; 
  213. $length = $meta['length']; 
  214. } else { 
  215. // Calculate the cubic root of the total volume, rounding up 
  216. $cuberoot = ceil(pow($volume, 1 / 3)); 
  217.  
  218. if ($cuberoot > 0) 
  219. $height = $width = $length = $cuberoot; 
  220.  
  221. // As per http://auspost.com.au/personal/parcel-dimensions.html: if the parcel is box-shaped, both its length and width must be at least 15cm. 
  222. if ($length < 150) $length = 150; 
  223. if ($width < 150) $width = 150; 
  224.  
  225. // By default we should use Australia Post's quoted rate(s) 
  226. $shippingPriceNeedsToBeZero = false; 
  227.  
  228. if ($numItemsWithDisregardShippingTicked == $numItems) { 
  229. // The cart consists of entirely "disregard shipping" products, so the shipping quote(s) should be $0.00 
  230. // Set the weight to 1 gram so that we can obtain valid Australia Post quotes (which we will then ignore the quoted price of) 
  231. $weight = 1; 
  232. $shippingPriceNeedsToBeZero = true; 
  233.  
  234. // API Documentation: http://drc.edeliver.com.au/ 
  235. $url = "http://drc.edeliver.com.au/ratecalc.asp"; 
  236.  
  237. $params = array( 
  238. 'Pickup_Postcode' => $this->base_zipcode 
  239. , 'Destination_Postcode' => $destzipcode 
  240. , 'Quantity' => 1 
  241. , 'Weight' => $weight 
  242. , 'Height' => $height 
  243. , 'Width' => $width 
  244. , 'Length' => $length 
  245. , 'Country' => $dest 
  246. ); 
  247.  
  248. // URL encode the parameters to prevent issues where postcodes contain spaces (eg London postcodes) 
  249. $params = array_map('urlencode', $params); 
  250.  
  251. $url = add_query_arg($params, $url); 
  252.  
  253. $log = ''; 
  254. $methods = array(); 
  255. foreach ($this->services as $code => $service) { 
  256. if (!$this->settings['services'][$code]) continue; 
  257.  
  258. $fullURL = esc_url_raw( add_query_arg('Service_Type', $code, $url ) ); 
  259.  
  260. // This cache key should be unique for a cart with these contents and destination 
  261. // Needs to be less than 45 characters (as per http://core.trac.wordpress.org/ticket/15058) 
  262. $cacheKey = 'wpec_apq_' . md5($fullURL); 
  263.  
  264. // See if this Australia Post quote is cached 
  265. $cachedResult = get_transient($cacheKey); 
  266.  
  267. if ( false === $cachedResult ) { 
  268.  
  269. // Quote isn't cached -> query the Australia Post API and then cache the result for 10 minutes 
  270.  
  271. $response = wp_remote_get($fullURL); 
  272.  
  273. // Silently ignore any API server errors 
  274. if ( is_wp_error($response) || $response['response']['code'] != '200' || empty($response['body']) ) continue; 
  275.  
  276. if ($this->debug) { 
  277. $log .=" {$fullURL}\n " . $response['body'] . "\n"; 
  278.  
  279. $lines = explode("\n", $response['body']); 
  280.  
  281. foreach($lines as $line) { 
  282. if ( empty( $line ) ) 
  283. continue; 
  284. list($key, $value) = explode('=', $line); 
  285. $key = trim($key); 
  286. $value = trim($value); 
  287. switch ($key) { 
  288. case 'charge': 
  289. if ($shippingPriceNeedsToBeZero) { 
  290. // All shipping prices quoted should be zero 
  291. $methods[$code]['charge'] = 0.00; 
  292. $log .=" NB: the price for the above quote has been overridden to $0.00\n\n"; 
  293. } else { 
  294. // Use the Australia Post quoted price 
  295. $methods[$code]['charge'] = floatval($value); 
  296. break; 
  297. case 'days': 
  298. $methods[$code]['days'] = floatval($value); 
  299. break; 
  300. case 'err_msg': 
  301. $methods[$code]['err_msg'] = trim($value); 
  302. break; 
  303. $methods[$code]['name'] = $this->services[$code]; 
  304.  
  305. // Cache this quote for 10 minutes 
  306. set_transient($cacheKey, $methods[$code], 600); 
  307.  
  308. } else { 
  309. // This quote is cached so use that result instead 
  310. $methods[$code] = $cachedResult; 
  311. if ( $this->debug && strlen($log) ) 
  312. error_log( 'WP eCommerce Australia Post shipping quotes for ' . home_url() . ":\n----------\n$log----------" ); 
  313.  
  314. // Allow another WordPress plugin to override the quoted method(s)/amount(s) 
  315.  
  316. $methods = apply_filters('wpsc_australia_post_methods', $methods, $this->base_zipcode, $destzipcode, $dest, $weight); 
  317.  
  318. $quotedMethods = array(); 
  319.  
  320. foreach ($methods as $code => $data) { 
  321. // Only include methods with an OK response 
  322. if ($data['err_msg'] != 'OK') continue; 
  323.  
  324. if ($data['days']) { 
  325. // If the estimated number of days is specified, so include it in the quote 
  326. $text = sprintf(_n('%1$s (estimated delivery time: %2$d business day)', '%1$s (estimated delivery time: %2$d business days)', $data['days'], 'wpsc'), $data['name'], $data['days']); 
  327. } else { 
  328. // No time estimate 
  329. $text = $data['name']; 
  330. $quotedMethods[$text] = $data['charge']; 
  331. return $quotedMethods; 
  332.  
  333. function get_item_shipping() {