Australia Post shipping plugin

Here is my version of an Australia Post shipping plugin. If you use it and it works for you please leave me some love in the form of reputation points and maybe I can get some free membership. This took a LOT of work and was very frustrating. There were no properly functioning alternatives out there that I could find and you will be paying more than a few dollars for a developer to write this for you.

This currently only works for domestic postage.

<?php

/*
Marketpress Australia Post Shipping Plugin
A simplified version where the Aus Post API key is hardcoded.
Calculates domestic postage only.
*/
class MP_Shipping_AusPost extends MP_Shipping_API{

var $plugin_name = 'auspost';
var $public_name = 'Australia Post';

//set to true if you need to use the shipping_metabox() method to add per-product shipping options
public $use_metabox = true;

//set to true if you want to add per-product extra shipping cost field
public $use_extra = true;

//set to true if you want to add per-product weight shipping field
public $use_weight = true;

// Defines the available shipping Services and their display names
public $domestic_services = array();

public $sandbox_uri = 'https://test.npe.auspost.com.au';

public $production_uri = 'https://auspost.com.au';
private $apikey = 'Put your Australia Post API key here';

private $domestic_shipper_url;
private $domestic_letter_services_url;
private $domestic_parcel_services_url;

private $settings = '';

private $auspost_settings;

function on_creation(){

	$this->public_name = __('Australia Post', 'mp');

	$this->domestic_shipper_url = "https://auspost.com.au/api/postage/parcel/domestic/calculate";
	$this->domestic_letter_services_url = "https://auspost.com.au/api/postage/letter/domestic/service.json?";
	$this->domestic_parcel_services_url = "https://auspost.com.au/api/postage/parcel/domestic/service.json?";

	//Australia Post Domestic services
		$this->domestic_services = array(

		'AUS_LETTER_REGULAR_SMALL' 		=> new Aus_Post_Service('AUS_LETTER_REGULAR_SMALL',			__('Regular Small Letter', 'mp'), 	'0.25'),
		'AUS_LETTER_REGULAR_LARGE_125G'	=> new Aus_Post_Service('AUS_LETTER_REGULAR_LARGE_125G',	__('Regular Large Letter 125g', 'mp'), '0.125'),
		'AUS_LETTER_REGULAR_LARGE_250G' => new Aus_Post_Service('AUS_LETTER_REGULAR_LARGE_250G',	__('Regular Large Letter 250g', 'mp'),	'0.25'),
		'AUS_LETTER_REGULAR_LARGE_500G'	=> new Aus_Post_Service('AUS_LETTER_REGULAR_LARGE_500G',	__('Regular Large Letter 500g', 'mp'),	'0.5'),
		'AUS_LETTER_EXPRESS_SMALL_250G'	=> new Aus_Post_Service('AUS_LETTER_EXPRESS_SMALL_250G',	__('Small Express Letter 250g', 'mp'),	'0.25'),
		'AUS_LETTER_EXPRESS_MEDIUM_500G' => new Aus_Post_Service('AUS_LETTER_EXPRESS_MEDIUM_500G',	__('Medium Express Letter 500g', 'mp'),	'0.5'),
		'AUS_LETTER_EXPRESS_LARGE_500G'	=> new Aus_Post_Service('AUS_LETTER_EXPRESS_LARGE_500G',	__('Large Express Letter 500g', 'mp'), 	'0.5'),
		'AUS_PARCEL_REGULAR'    		=> new Aus_Post_Service('AUS_PARCEL_REGULAR', 				__('Regular Parcel Post', 'mp'),	'22'),
		'AUS_PARCEL_EXPRESS'  			=> new Aus_Post_Service('AUS_PARCEL_EXPRESS', 				__('Express Parcel Post', 'mp'),  	'22'),

		);

	// Get settings for convenience sake
	$this->settings = get_option('mp_settings');
	$this->auspost_settings =& $this->settings['shipping']['auspost'];
	}

  /**
   * Echo anything you want to add to the top of the shipping screen
   */
function before_shipping_form($content) {
		return $content;
	}

  /**
   * Echo anything you want to add to the bottom of the shipping screen
   */
	function after_shipping_form($content) {
		return $content;
  }

  /**
   * Echo a table row with any extra shipping fields you need to add to the shipping checkout form
   */
	function extra_shipping_field($content) {
		return $content;
  }

  /**
   * Use this to process any additional field you may add. Use the $_POST global,
   *  and be sure to save it to both the cookie and usermeta if logged in.
   */
	function process_shipping_form() {

  }

	/**
   * Echo a settings meta box with whatever settings you need for you shipping module.
   *  Form field names should be prefixed with mp[shipping][plugin_name], like "mp[shipping][plugin_name][mysetting]".
   *  You can access saved settings via $settings array.
   */
	function shipping_settings_box($settings) {
		global $mp;

		$this->settings = $settings;
		$this->auspost_settings = $this->settings['shipping']['auspost'];
		$system = $this->settings['shipping']['system']; //Current Unit settings english | metric
		?>

		<div id="mp_ups_rate" class="postbox">
			<h3 class='hndle'><span><?php _e('Australia Post Settings', 'mp'); ?></span></h3>
			<div class="inside">
				<table class="form-table">
					<tbody>
						<tr>
							<th scop="row"><?php _e('Attention', 'mp') ?></th>
							<td>
								<p><?php _e('Australia Post uses your products weight and dimensions (length, width, height or thickness) to calculate shipping.  Please ensure you have your product details entered correctly.  ', 'mp') ?></p>
                                <p><?php _e('For best results enter your largest dimensions as length.', 'mp') ?></p>
								<p><strong><?php _e('If you have not set the weight of a product, then it will be calculated as FREE shipping for your buyer and you, as the seller, will absorb the cost of postage. ', 'mp') ?></strong></p>
								<p><?php _e('Domestic shipping also uses dimensions to calculate shipping.  If you do not enter the dimensions correctly you may get a surprise at the post office!   ', 'mp') ?></p>
								<p><?php _e('Remember to take into account your packing materials when calculating the package weight and dimensions.  Weight is measured in kilograms and dimensions are measured in cm.  ', 'mp') ?></p>
								<p><?php _e('If dimension are not entered a default of 10cm x 10cm x 10cm will be used.', 'mp') ?></p>
							</td>
						</tr>
                        <tr>
							<th scope="row"><?php _e('Australia Post Offered Domestic Services', 'mp') ?></th>
							<td>
								<?php foreach($this->domestic_services as $code => $service) : ?>
								<label>
                                <input type="checkbox" name="mp[shipping][auspost][domestic_services][<?php echo $code; ?>]" value="1" <?php checked($this->auspost_settings['domestic_services'][$code], 1); ?> />&nbsp;<?php echo $service->name; ?>
                                </label><br />
								<?php endforeach; ?>
							</td>
						</tr>
                        <tr>
							<th scope="row"><?php _e('Handling Charge per Domestic Package Shipped', 'mp') ?></th>
							<td>
								<input type="text" name="mp[shipping][auspost][domestic_handling]" value="<?php echo (empty($this->auspost_settings['domestic_handling']) ) ? '0.00' : esc_attr($this->auspost_settings['domestic_handling']); ?>" size="20" maxlength="20" />
							</td>
						</tr>
                     </tbody>
				</table>
			</div>
		</div>
		<?php

  }

  /**
   * Filters posted data from your form. Do anything you need to the $settings['shipping']['plugin_name']
   *  array. Don't forget to return!
   */
	function process_shipping_settings($settings) {
	//handle domestic services checkboxes
	foreach ( $this->domestic_services as $service => $code ) {
			if ( isset($_POST['mp']['shipping']['auspost']['domestic_services'][$service]) ) {
				$settings['shipping']['auspost']['domestic_services'][$service] = 1;
			} else {
				$settings['shipping']['auspost']['domestic_services'][$service] = 0;
			}
		}
    return $settings;
  }

  /**
   * Echo any per-product shipping fields you need to add to the product edit screen shipping metabox
   *
   * @param array $shipping_meta, the contents of the post meta. Use to retrieve any previously saved product meta
   * @param array $settings, access saved settings via $settings array.
   */
	function shipping_metabox($shipping_meta, $settings) {
	global $mp;

		// if weight of product is greater than 22kg then can't use Australia Post
		if ($shipping_meta['weight'] > 22){
			// need warning that Australia Post cannot be used.
			?><div class="mp_checkout_error">Products over 22kg cannot be shipped by Australia Post.  Please choose another shipping option such as pickup or set weight to zero which will calculate free postage and add handling to cover delivery costs.</div>
		<?php }
		echo '<p>';
		?>
		<label><?php _e('Length (cms)', 'mp'); ?>:<br />
		<input type="text" size="6" name="mp_shipping_length" value="<?php echo isset($shipping_meta['length']) ? $shipping_meta['length'] : '0'; ?>" />
		</label>
		</p><p>
		<label><?php _e('Width (cms)', 'mp'); ?>:<br />
		<input type="text" size="6" name="mp_shipping_width" value="<?php echo isset($shipping_meta['width']) ? $shipping_meta['width'] : '0'; ?>" />
		</label>
		</p><p>
		<label><?php _e('Height (cms)', 'mp'); ?>:<br />
		<input type="text" size="6" name="mp_shipping_height" value="<?php echo isset($shipping_meta['height']) ? $shipping_meta['height'] : '0'; ?>" />
		</label>
		<?php
		echo '</p>';

  }

  /**
   * Save any per-product shipping fields from the shipping metabox using update_post_meta
   *
   * @param array $shipping_meta, save anything from the $_POST global
   * return array $shipping_meta
   */
	function save_shipping_metabox($shipping_meta) {
	global $mp;
		$shipping_meta['length'] = (!empty($_POST['mp_shipping_length'])) ? round($_POST['mp_shipping_length'], 2) : 0;
		$shipping_meta['width'] = (!empty($_POST['mp_shipping_width'])) ? round($_POST['mp_shipping_width'], 2) : 0;
		$shipping_meta['height'] = (!empty($_POST['mp_shipping_height'])) ? round($_POST['mp_shipping_height'], 2) : 0;

    return $shipping_meta;
  }

	/**
	*Function to return whether the package is domestic letter sized
	*If the package is a letter the dimensions of the packages length, width and height are put in mid, max, min order to fit the dimensions needed to calculate letter postage rates.
	*return boolean $letter
	*
	**/
	private function is_domestic_letter() {

		$max = '';
		$mid = '';
		$min = '';
		$letter = false;

		//find smallest dimension
		$max_dim = max($this->length, $this->width, $this->height);
		if ($this->weight <= 0.5 ){
			if ($max_dim <= 36){
				if ($max_dim == $this->height){
					$max = $this->height;
					if ($this->width >= $this->length){
						$mid = $this->width;
						$min = $this->length;
					}
					else {
						$mid = $this->length;
						$min = $this->width;
					}
				}
				elseif ($max_dim == $this->width){
					$max = $this->width;
					if ($this->height >= $this->length){
						$mid = $this->height;
						$min = $this->length;
					}
					else {
						$mid = $this->length;
						$min = $this->height;
					}
				}
				else {
					if ($this->height >= $this->width){
						$max = $this->length;
						$mid = $this->height;
						$min = $this->width;
					}
					else {
						$max = $this->length;
						$mid = $this->width;
						$min = $this->height;
					}
				}
				if (($mid <= 26) && ($min <= 2)){
					$letter = true;
					$this->length = $mid;
					$this->width = $max;
					$this->height = $min;
				}
				else {
					$letter = false;
				}
			}
			else {
				$letter = false;
			}
		}
		return $letter;
	}

  /**
		* Use this function to return your calculated price as an integer or float
		*
		* @param int $price, always 0. Modify this and return
		* @param float $total, cart total after any coupons and before tax
		* @param array $cart, the contents of the shopping cart for advanced calculations
		* @param string $address1
		* @param string $address2
		* @param string $city
		* @param string $state, state/province/region
		* @param string $zip, postal code
		* @param string $country, ISO 3166-1 alpha-2 country code
		* @param string $selected_option, if a calculated shipping module, passes the currently selected sub shipping option if set
		*
		* return float $price
		*/
	function calculate_shipping($price, $total, $cart, $address1, $address2, $city, $state, $zip, $country, $selected_option) {
		global $mp;

		if(! $this->crc_ok())
		{
			//Price added to this object
			$this->shipping_options($cart, $address1, $address2, $city, $state, $zip, $country);
		}

		$price = floatval($_SESSION['mp_shipping_info']['shipping_cost']);
		return $price;

	}

	/**
		* For calculated shipping modules, use this method to return an associative array of the sub-options. The key will be what's saved as selected
		*  in the session. Note the shipping parameters won't always be set. If they are, add the prices to the labels for each option.
		*
		* @param array $cart, the contents of the shopping cart for advanced calculations
		* @param string $address1
		* @param string $address2
		* @param string $city
		* @param string $state, state/province/region
		* @param string $zip, postal code
		* @param string $country, ISO 3166-1 alpha-2 country code
		*
		* return array $shipping_options
		*/
	function shipping_options($cart, $address1, $address2, $city, $state, $zip, $country) {
		$shipping_options = array();

		$this->address1 = $address1;
		$this->address2 = $address2;
		$this->city = $city;
		$this->state = $state;
		$this->destination_zip = $zip;
		$this->country = $country;
		$too_heavy = false;

		//set weight, length, width and thickness to zero if not set in the shipping meta
		$shipping_meta['weight'] = (is_numeric($shipping_meta['weight']) ) ? $shipping_meta['weight'] : 0;
		$shipping_meta['length'] = (is_numeric($shipping_meta['length']) ) ? $shipping_meta['length'] : 0;
		$shipping_meta['height'] = (is_numeric($shipping_meta['height']) ) ? $shipping_meta['height'] : 0;
		$shipping_meta['width'] = (is_numeric($shipping_meta['width']) ) ? $shipping_meta['width'] : 0;

		// for each item in the cart using the product_id as the key
		foreach ($cart as $product_id => $variations) {
			// get the shipping meta for that product
			$shipping_meta = get_post_meta($product_id, 'mp_shipping', true);
			// for each product variation using as the key
			foreach($variations as $variation => $product) {
				$qty = $product['quantity'];
				$weight = $shipping_meta['weight'];
				// need to check here whether item is too heavy?
				// add the weight of the product * the qty to the shopping cart weight
				$this->weight += floatval($weight) * $qty;
				$length = $shipping_meta['length'];
				$this->length = max($length, $this->length);
				$height = $shipping_meta['height'];
				$this->height = max($height, $this->height);
				$width = $shipping_meta['width'];
				$this->width += $width * $qty;
			  }
		  }

		//If whole shipment is zero weight then there's nothing to ship. Return Free Shipping
		if($this->weight == 0){ //Nothing to ship
				$_SESSION['mp_shipping_info']['shipping_sub_option'] = __('Free Shipping', 'mp');
				$_SESSION['mp_shipping_info']['shipping_cost'] =  0;
				return array(__('Free Shipping', 'mp') => __('Free Shipping - 0.00', 'mp') );
		}

		// if a single item too heavy for Australia Post.  Sale will not go through.
		if(($this->weight > 22) && (count($cart)==1)){
			return array('error' => '<div class="mp_checkout_error">Too heavy for Australia Post.  Choose pickup if available or contact seller.</div>');

		}
		//Multiple item cart too heavy for Australia Post.  Sale will not go through.
		if(($this->weight > 22) && (count($cart)>1)){
			return array('error' => '<div class="mp_checkout_error">Too heavy for Australia Post.  Please divide your purchase into multiple carts.</div>');
		}

		if (!$country){
			$country = "AU";
			}
		if ($country == "AU"){
		 	//call get domestic list
			$shipping_options = $this->rate_request();
		}

		return $shipping_options;
	}

	/**For uasort below
	*/
	function compare_rates($a, $b){
		if($a['rate'] == $b['rate']) return 0;
		return ($a['rate'] < $b['rate']) ? -1 : 1;
	}

	/**
	* Domestic rate_request - Makes the actual call to Australia Post
	*/
	function rate_request() {
		global $mp;

		$letter = false;
		$shipping_options = array();

		//figure out whether letter or parcel
		$letter = $this->is_domestic_letter();

		if ($letter){
			// change measurements to mm and grams from cm and kg and Australia Post letters are measured by length, width and thickness
			$letter_length = $this->length * 10;
			$letter_width = $this->width* 10;
			$letter_thickness = $this->height* 10;
			$letter_weight = $this->weight * 1000;
			$shipping_options = $this->get_domestic_letter_rates($letter_length, $letter_thickness, $letter_width, $letter_weight);
		}

		else{
			$shipping_options = $this->get_domestic_parcel_rates($this->settings['base_zip'], $this->destination_zip, $this->length, $this->height, $this->width, $this->weight);
		}

		return $shipping_options;

	}

	/* Function to get Australia Post domestic letter rates.  The Australia Post API requires length, width, thickness and weight for letters.
		Values for length, height and thickness should be in the order mid, max, min.  Maximum dimensions allowable are 360mm x 260mm x 20mm.
		Maximum weight is 500g.  Measurements are in mm and grams.
	*/
	  private function get_domestic_letter_rates( $length, $thickness, $width, $weight ){
		global $mp;
		$no_postcode_set = false;

		//gets the shipping options that are set as available?
		$shipping_options = array_filter($this->auspost_settings['domestic_services'], create_function('$val', 'return ($val == 1);'));

		$ch = curl_init();	

		// if $to_postcode is NULL set it to 4000 but return the list of service options without prices?
		if($to_postcode == NULL){
			$to_postcode = 4000;  // you might want to change this to your shop's postcode as a default
			$no_postcode_set = true;
		}
		// set the query params
		$queryParams = array(
			"length" => $length,
			"thickness" => $thickness,
			"width" => $width,
			"weight" => $weight
			);

		// Set the URL for the Domestic Letter Size service
		$postageTypesURL = $this->domestic_letter_services_url . http_build_query($queryParams);

		// Lookup available domestic letter delivery service types
		curl_setopt($ch, CURLOPT_URL, $postageTypesURL);
		curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
		curl_setopt($ch, CURLOPT_HTTPHEADER, array('AUTH-KEY: ' . $this->apikey));
		$rawBody = curl_exec($ch);

		// Check the response; if the body is empty then an error has occurred
		if(!$rawBody){
			//echo "!rawbody";
			die('<div class="mp_checkout_error">Australia Post: ' . curl_error(ch) . '" - Code: ' . curl_errno($ch));
			//die('Error: "' . curl_error($ch) . '" - Code: ' . curl_errno($ch));
		}

		// All good, lets parse the response into a JSON object
		$servicesJSON = json_decode($rawBody, true);

		if (!$servicesJSON){
			//get data
			return array('error' => '<div class="mp_checkout_error">Australia Post: ' . $servicesJSON['error']['errorMessage'] . '</div>');
        }

		//Clear any old price
		unset($_SESSION['mp_shipping_info']['shipping_cost']);

		//Good to go
		//Make SESSION copy with just prices and delivery

		if(!is_array($shipping_options)) $shipping_options = array();
		$mp_shipping_options = $shipping_options;

		foreach($mp_shipping_options as $key => $value){

			// test whether option returned from Australia Post is one of the options allowed by store
			foreach ($servicesJSON[services][service] as $k => $v){
				if ($servicesJSON[services][service][$k][code] == $key){

					//if(array_search($mp_shipping_options[$key], $servicesJSON)){

					//get price
					$price = $servicesJSON[services][service][$k][price];
					$handling = floatval($this->auspost_settings['domestic_handling']) * $this->pkg_count; // Add handling times number of packages.
					$mp_shipping_options[$key] = array('price' => $price, 'handling' => $handling);

					//match it up if there is already a selection
					if (! empty($_SESSION['mp_shipping_info']['shipping_sub_option'])){
						if ($_SESSION['mp_shipping_info']['shipping_sub_option'] == $key){
							$_SESSION['mp_shipping_info']['shipping_cost'] =  $price + $handling;
						}
					}
				break;
				}
				else {
					//remove from options
					unset($mp_shipping_options[$key]);
				}
			}
		}			

		// sort shipping options by cost
		uasort($mp_shipping_options, array($this,'compare_rates') );

		// copy sorted array back into shipping options array
		$shipping_options = array();
		if ($no_postcode_set){
			foreach($mp_shipping_options as $service => $options){
				$shipping_options[$service] = $this->format_shipping_choices($service);
			}
		}
		else {
			foreach($mp_shipping_options as $service => $options){
				$shipping_options[$service] = $this->format_shipping_option($service, $options['price'], $options['handling']);
			}
		}

		//Update the session. Save the currently calculated CRCs
		$_SESSION['mp_shipping_options'] = $mp_shipping_options;
		$_SESSION['mp_cart_crc'] = $this->crc($mp->get_cart_cookie());
		$_SESSION['mp_shipping_crc'] = $this->crc($_SESSION['mp_shipping_info']);

		return $shipping_options;

	  }

	/* Function to get Australia Post domestic parcel rates.  The Australia Post API requires to and from postcodes, length, height, width and weight.
		Maximum weight is 22kg.  Maximum length is 105cm.  Maximum dimensions is 0.25m3.  Australia Post Domestic parcels are charged according to actual weight or cubic weight, whichever is greater.
		See http://auspost.com.au/parcels-mail/size-and-weight-guidelines.html for details.
		Measurements are in cm and kgs.
	*/
	private function get_domestic_parcel_rates($from_postcode, $to_postcode, $length, $height, $width, $weight){
		global $mp;
		$no_postcode_set = false;

		//gets the shipping options that are set as available?
		$shipping_options = array_filter($this->auspost_settings['domestic_services'], create_function('$val', 'return ($val == 1);'));

		$ch = curl_init();	

		// if $to_postcode is NULL set it to 4000 but return the list of service options without prices
		if($to_postcode == NULL){
			$to_postcode = 4000;  // you might want to change this to your shop's postcode as a default
			$no_postcode_set = true;
		}

		// Set the query params
		$queryParams = array(
		  "from_postcode" => $from_postcode,
		  "to_postcode" => $to_postcode,
		  "length" => $length,
		  "width" => $width,
		  "height" => $height,
		  "weight" => $weight
		);

		// Set the URL for the Domestic Parcel Size service
		$postageTypesURL = $this->domestic_parcel_services_url . http_build_query($queryParams);

		// Lookup available domestic parcel delivery service types
		curl_setopt($ch, CURLOPT_URL, $postageTypesURL);
		curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
		curl_setopt($ch, CURLOPT_HTTPHEADER, array('AUTH-KEY: ' . $this->apikey));
		$rawBody = curl_exec($ch);

		// Check the response; if the body is empty then an error has occurred
		if(!$rawBody){
			//echo "!rawbody";
			die('<div class="mp_checkout_error">Australia Post: ' . curl_error(ch) . '" - Code: ' . curl_errno($ch));
			//die('Error: "' . curl_error($ch) . '" - Code: ' . curl_errno($ch));
		}

		// All good, lets parse the response into a JSON object
		$servicesJSON = json_decode($rawBody, true);

		if (!$servicesJSON){
			//get data
			return array('error' => '<div class="mp_checkout_error">Australia Post: ' . $servicesJSON['error']['errorMessage'] . '</div>');
        }

		//Clear any old price
		unset($_SESSION['mp_shipping_info']['shipping_cost']);

		//Good to go
		//Make SESSION copy with just prices and delivery

		if(!is_array($shipping_options)) $shipping_options = array();
		$mp_shipping_options = $shipping_options;

		foreach($mp_shipping_options as $key => $value){

			// test whether option returned from Australia Post is one of the options allowed by store
			foreach ($servicesJSON[services][service] as $k => $v){
				if ($servicesJSON[services][service][$k][code] == $key){

					//if(array_search($mp_shipping_options[$key], $servicesJSON)){

					//get price
					$price = $servicesJSON[services][service][$k][price];
					$handling = floatval($this->auspost_settings['domestic_handling']) * $this->pkg_count; // Add handling times number of packages.
					$mp_shipping_options[$key] = array('price' => $price, 'handling' => $handling);

					//match it up if there is already a selection
					if (! empty($_SESSION['mp_shipping_info']['shipping_sub_option'])){
						if ($_SESSION['mp_shipping_info']['shipping_sub_option'] == $key){
							$_SESSION['mp_shipping_info']['shipping_cost'] =  $price + $handling;
						}
					}
				break;
				}
				else {
					//remove from options
					unset($mp_shipping_options[$key]);
				}
			}
		}			

		// sort shipping options by cost
		uasort($mp_shipping_options, array($this,'compare_rates') );

		// copy sorted array back into shipping options array
		$shipping_options = array();
		if ($no_postcode_set){
			foreach($mp_shipping_options as $service => $options){
				//echo"foreach";
				$shipping_options[$service] = $this->format_shipping_choices($service);
			}
		}
		else {
			foreach($mp_shipping_options as $service => $options){
				//echo"foreach";
				$shipping_options[$service] = $this->format_shipping_option($service, $options['price'], $options['handling']);
			}
		}

		//Update the session. Save the currently calculated CRCs
		$_SESSION['mp_shipping_options'] = $mp_shipping_options;
		$_SESSION['mp_cart_crc'] = $this->crc($mp->get_cart_cookie());
		$_SESSION['mp_shipping_crc'] = $this->crc($_SESSION['mp_shipping_info']);

		//echo"<p>end of parcel rates function</p>";

		return $shipping_options;
	}

	/**
	* Formats a choice for the Shipping options dropdown
	* @param array $shipping_option, a $this->services key
	* @param float $price, the price to display
	*
	* @return string, Formatted string with shipping method name delivery time and price
	*
	*/
	private function format_shipping_option($shipping_option = '', $price = '', $delivery = '', $handling=''){
		global $mp;
		if ( isset($this->services[$shipping_option])){
			$option = $this->services[$shipping_option]->name;
		}
		elseif ( isset($this->intl_services[$shipping_option])){
			$option = $this->intl_services[$shipping_option]->name;
		}

		$price = is_numeric($price) ? $price : 0;
		$handling = is_numeric($handling) ? $handling : 0;
		$total = $price + $handling;

		if ( $mp->get_setting('tax->tax_inclusive') && $mp->get_setting('tax->tax_shipping') ) {
			$total = $mp->shipping_tax_price($total);
		}
		$service = $this->domestic_services[$shipping_option]->name;
		$option .=  sprintf(__(' %1$s - %2$s', 'mp'), $service, $mp->format_currency('', $total) );
		return $option;
	}

	/* function to return shipping choices with no prices if no postcode is provided
	*/
	private function format_shipping_choices($shipping_option = ''){
		global $mp;
		if (isset($this->services[$shipping_option])){
			$option = $this->services[$shipping_option]->name;
		}

		$service = $this->domestic_services[$shipping_option]->name;
		$option .= sprintf(__(' %1$s', 'mp'), $service);
		return $option;
		}	

	/**Used to detect changes in shopping cart between calculations
	* @param (mixed) $item to calculate CRC of
	*
	* @return CRC32 of the serialized item
	*/
	public function crc($item = ''){
		return crc32(serialize($item));
	}

	/**
	* Tests the $_SESSION cart cookie and mp_shipping_info to see if the data changed since last calculated
	* Returns true if the either the crc for cart or shipping info has changed
	*
	* @return boolean true | false
	*/
	private function crc_ok(){
		global $mp;

		//Assume it changed
		$result = false;

		//Check the shipping options to see if we already have a valid shipping price
		if(isset($_SESSION['mp_shipping_options'])){
			//We have a set of prices. Are they still valid?
			//Did the cart change since last calculation
			if ( is_numeric($_SESSION['mp_shipping_info']['shipping_cost'])){

				if($_SESSION['mp_cart_crc'] == $this->crc($mp->get_cart_cookie())){
					//Did the shipping info change
					if($_SESSION['mp_shipping_crc'] == $this->crc($_SESSION['mp_shipping_info'])){
						$result = true;
					}
				}
			}
		}
		return $result;
	}

}
// End MP_Shipping_AusPost

if(! class_exists('Aus_Post_Service') ):
class Aus_Post_Service
{
	public $code;
	public $name;
	public $max_weight;

	function __construct($code, $name, $max_weight = null)
	{
		$this->code = $code;
		$this->name = $name;
		$this->max_weight = $max_weight;

	}
}
endif;

//register plugin as calculated. Only in Australia
$settings = get_option('mp_settings');
if ( in_array( $settings['base_country'], array('AU') ) ) {
	mp_register_shipping_plugin( 'MP_Shipping_AusPost', 'auspost', __('Australia Post', 'mp'), true );
}

Nat.

  • Tyler Postle
    • CGO

    Wow, awesome contribution Nat! Thanks for sharing it with the rest of the community :slight_smile:

    Sending some points your way.

    I remember you posting a couple threads on this during development, glad to see you got it finished - that must feel satisfying :slight_smile:

    Thanks again for sharing.

    Have a great rest of your day!

    Cheers,
    Tyler

  • naz_rimmer
    • New Recruit

    Hi Nat
    Does this give Austpost as one of the calculated options? I need to be able to offer Pickup & Austpost or even pickup & flatrate. I don't seem to be able to offer both and this is why I bought the subscription.
    If it does and I use your code what will happen when the plugin updates? Should still work?

  • Natalie
    • Site Builder, Child of Zeus

    Hi.
    It is a calculated option so will function the same as any other calculated option with flat rate/pickup. I don't think you can have both. I would like to be able to offer pickup or Australia post myself. If a seller wants to offer only pickup they can make the postage free and make sure the seller indicates that pickup is required in the items details but I can't see a way to offer the buyer the choice between post or pickup.

    This code will be removed in a Marketpress update if you put it in the folder with all of the other existing shipping options. Just keep a local copy and put it back in when you do an update.

    I am going to change it to its on plugin when I have time. I understand your frustration with choosing ecommerce solutions especially when you are new to it and don't know what questions to ask before you start playing with it. I've been very happy with the support here but have made some compromises on my initial desires. I'm not sure any out of the box ecommerce solution does everything for everyone though.

    I hope that helps.

  • naz_rimmer
    • New Recruit

    Thanks Nat. I started testing it yesterday and it might do what I need. :slight_smile: Thanks for that!
    Yes just having free postage for pickup will work for some people. A site I built last week does that and it should work out fine for her.
    Another I am about to do will need all the weight, size etc so hopefully this will be okay but then I bet they are going to want courier options as well as they have huge items. Like you said though its never going to have everything!

  • johnnymestizo
    • HummingBird

    Does this still work?

    A client is very upset that Marketpress does not interface directly with the Australia Post API.

    I have recently found out how incredibly complex Australian domestic post shipping is:

    Dependent on which location you are in australia:
    http://auspost.com.au/parcels-mail/downloadable-post-guides.html

    and the location of the sell and how cubic heavy the parcel is, and the location of the customer:
    http://auspost.com.au/media/documents/Parcel-Post-guide-MS101-Sydney-N1-02Mar2015.pdf

    Will determine how much shipping costs.

    Marketpress users cannot be expected to enter this in anywhere... so Australia Post have an API.
    https://developers.auspost.com.au

    Will the above code work with the API ? Will WPMUDEV be supporting an Australia Post Marketpress shipping 'calculated options' ?

    Cheers,

    Johnny

    • Natalie
      • Site Builder, Child of Zeus

      Hi Johnny.
      It should work for you. I'm using it on my site. The only issue I have found is a logic bug if your seller chooses not to offer all the parcel/letter sizes then it says there may not be a post option because I need to change it to go to the next size up. The easy way to fix this is to make sure that the seller is offering all parcel/letter options (don't need to offer express though). I will fix this error when I have time.

      Also be aware that the 'extra shipping fee' will get added to the postage cost in the last step of the checkout process which can be confusing as it looks like the postage suddenly jumps by that much if your seller has added an extra shipping fee.

      The Australia Post API is very confusing and, as I was learning PHP as I went, nearly brought me to tears on several occasions. I was ready to go postal!!! The documentation is not very good and believe it or not there are actually errors in the documentation, specifically in relation to the calls you make to the API. I tried contacting support but just kept getting pointed back to the documentation and online API tester (which has conflicting info to the documentation). It basically took trial and error to sort it out.

      There is another person with an Australia Post plugin on the Wordpress site I think but I haven't tried it.

      I hope this helps! Good luck.
      Nat.

  • Natalie
    • Site Builder, Child of Zeus

    No I have not. Looking to do some testing of various things over the next week or two. I'm hoping to get a more complete version of this out soon. I've made a few additions since this code. I've got no idea whether anyone is actually using it apart from myself.

  • Natalie
    • Site Builder, Child of Zeus

    Hi. Thanks. Yes if I have your details on my system for the sale I will send you updates. I know it's not perfect but I didn't want to go the whole license activation key with a separate website etc. for one plugin that I don't know the market for.

    I have another site I'm setting up that I have the new Marketpress beta loaded on to so hopefully I will get time to provide a version for that soon.
    Nat

Thank NAME, for their help.

Let NAME know exactly why they deserved these points.

Gift a custom amount of points.