Re: [Released] Australia Post Shipping Module (Read 1st post
Posted: Tue Sep 11, 2012 10:00 am
That worked great. Thank you.
Sorry for the late reply.
Sorry for the late reply.
OpenCart Community Forum - Discuss shopping cart and e-commerce solutions.
https://forum.opencart.com/
I have the same issue too - with orders of some long items and some wide items.tecktipsaaran wrote:
Yes splitting the items when the weight is over 20kg is working OK.
I need to be able to split the items into separate packages when the girth is >=140cm.
Should it work? Or is there extra code required?
Hey,tecktipsaaran wrote:
tora0515 wrote:
Having problems with dimensions.
I have some large products that are often bought in multiples. When more than 2 products are added to the cart, the dimensions exceed auspost's values. My customers receive the error: The dimensions exceed the maximum girth of 140cm.
Is there a way to split this into 2 shipments? Maybe using length and cubic volume?
Thanks
I am having the same problem.
Does anyone have a solution for this?
Thanks
Aaran
Code: Select all
if($qnty >= 2 && $parcels[$parcel_num]['weight'] + $product_weight >= 20000) {
if ($parcels[$parcel_num]['weight'] == 0){
$item_placed = true;
}else{
$parcel_num++;
if($parcel_num == count($parcels)){
$parcels[$parcel_num]['weight'] = 0;
$parcels[$parcel_num]['items'] = 0;
$parcels[$parcel_num]['single_w'] = 0;
$parcels[$parcel_num]['single_h'] = 0;
$parcels[$parcel_num]['single_l'] = 0;
$parcels[$parcel_num]['cubed'] = 0;
$parcels[$parcel_num]['price'] = 0;
$item_placed = true;
}
}
}
elseif ($qnty >= 2 && $parcels[$parcel_num]['weight'] + $product_weight <= 20000) {
$parcel_num++;
$parcels[$parcel_num]['weight'] = $product_weight;
$parcels[$parcel_num]['items'] = $qnty;
$parcels[$parcel_num]['price'] = $cartitem['price'];
$parcels[$parcel_num]['cubed'] = ($item_width * $item_height * $item_length);
$parcels[$parcel_num]['single_w'] = $item_width;
$parcels[$parcel_num]['single_h'] = $item_height;
$parcels[$parcel_num]['single_l'] = $item_length;
$item_placed = true;
}
Code: Select all
//There is an offset by 1, so it's really if parcel_num is more than parcels
if($parcel_num == count($parcels)) {
$parcels[$parcel_num]['weight'] = 0;
$parcels[$parcel_num]['items'] = 0;
$parcels[$parcel_num]['single_w'] = 0;
$parcels[$parcel_num]['single_h'] = 0;
$parcels[$parcel_num]['single_l'] = 0;
$parcels[$parcel_num]['cubed'] = 0;
$parcels[$parcel_num]['price'] = 0;
}
}
}
Code: Select all
<?php
/*
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
---------------------------------------------------------------------
SuperJuice (Sam) opencart@pixeldrift.net
OpenCart 1.5.1.1 Australia Post Module 1.5.1.1u4
If you're going to use the code, give me some credit.. it's simple
*/
class ModelShippingAuspost extends Model {
public function getQuote($address) {
$this->load->language('shipping/auspost');
if ($this->config->get('auspost_status')) {
$query = $this->db->query("SELECT * FROM " . DB_PREFIX . "zone_to_geo_zone WHERE geo_zone_id = '" . (int)$this->config->get('auspost_geo_zone_id') . "' AND country_id = '" . (int)$address['country_id'] . "' AND (zone_id = '" . (int)$address['zone_id'] . "' OR zone_id = '0')");
if (!$this->config->get('auspost_geo_zone_id')) {
$status = TRUE;
} elseif ($query->num_rows) {
$status = TRUE;
} else {
$status = FALSE;
}
} else {
$status = FALSE;
}
if ($status && ($this->config->get('auspost_standard') || $this->config->get('auspost_registered') || $this->config->get('auspost_insured') || $this->config->get('auspost_express') || $this->config->get('auspost_sea') || $this->config->get('auspost_air') || $this->config->get('auspost_satchreg') || $this->config->get('auspost_satcheby') || $this->config->get('auspost_satchexp') || $this->config->get('auspost_satchpla'))) {
//Query to find id of grams (g) as 1.5.1.1 removed the availability of the named unit
$unit_query = $this->db->query("SELECT weight_class_id FROM " . DB_PREFIX . "weight_class_description where LOWER(unit) = 'g'");
if ($unit_query->num_rows) {$unit_g = $unit_query->row['weight_class_id'];}
$weight = intval($this->weight->convert($this->cart->getWeight(), $this->config->get('config_weight_class_id'), $unit_g));
$this->load->model('localisation/country');
$country_info = $this->model_localisation_country->getCountry($address['country_id']);
//Initialise variables
$method_data = array();
$quote_data = array();
$error = FALSE;
//These errors will clobber each other, so only one error will be displayed at a time
if (intval($weight) == 0) { $error = 'The cart weight is 0g, unable to calculate shipping costs';}
if ((intval($weight) > 20000) && !$this->config->get('auspost_multiple')) {
$error = 'Your cart is too heavy to ship with Australia Post (20kg+)';
} else {
//Still need to check if there is a single item > 20kg
foreach ($this->cart->getProducts() as $weightcheck) {
if(($this->weight->convert($weightcheck['weight'], $weightcheck['weight_class_id'], $unit_g) / $weightcheck['quantity']) > 20000) {
$error = 'There is a single item in your cart that is too heavy to ship with Australia Post (20kg)';
}
}
}
if($country_info['iso_code_2'] == 'AU') {
if (!preg_match('/^[0-9]{4}$/', $address['postcode'])) { $error = 'Your post code is not valid in Australia';}
$validmethods = array("standard","registered","insured","express");
} else {
$validmethods = array("sea","air");
}
//Break the items up in to multiple parcels ready to be sent off to the quote function
if((@count($validmethods) > 0) && $error == FALSE) {
//Query to find out if mm are configured in the database because OpenCart developers thought it wasn't needed in the API (no error condition if it doesn't exist)
$unit_query = $this->db->query("SELECT length_class_id FROM " . DB_PREFIX . "length_class_description where LOWER(unit) = 'mm'");
if ($unit_query->num_rows) {$unit_mm = $unit_query->row['length_class_id'];}
//Set the total cubed amount to 0
$cartcubed = 0;
//Setup the parcel array to take the contents from the cart
$parcels = array();
$parcels[0]['weight'] = 0;
$parcels[0]['items'] = 0;
$parcels[0]['single_w'] = 0;
$parcels[0]['single_h'] = 0;
$parcels[0]['single_l'] = 0;
$parcels[0]['cubed'] = 0;
$parcels[0]['price'] = 0;
foreach ($this->cart->getProducts() as $cartitem) {
//Split everything into parcels for multiple parcel shipping (all items now use this method)
$product_weight = $this->weight->convert($cartitem['weight'], $cartitem['weight_class_id'], $unit_g) / $cartitem['quantity'];
//TODO: Place heavy items before light ones for optimal distribution (sort cart item array by weight before placing in parcels)
//Always try and fill at the first parcel, then move to the next
$parcel_num = 0;
for ($qnty = 1; $qnty <= $cartitem['quantity']; $qnty++) {
// echo $cartitem['quantity'] ;
// echo $parcels['parcel_num']['weight'];
$item_placed = false;
while(!$item_placed) {
if(($product_weight) >20000) {
if($parcels[$parcel_num]['weight'] == 0) {
//The parcel is empty but can't fit 20kg in it.. this should never happen, but this is here just in case! (possible rounding error?)
//This item will never fit in a parcel, tell the loop to exit gracefully
$item_placed = true;
// echo " 0g " ;
} else {
//This parcel can't fit the item, move to the next parcel
$parcel_num++;
// echo " 20kg " ;
//There is an offset by 1, so it's really if parcel_num is more than parcels
if($parcel_num == count($parcels)) {
$parcels[$parcel_num]['weight'] = 0;
$parcels[$parcel_num]['items'] = 0;
$parcels[$parcel_num]['single_w'] = 0;
$parcels[$parcel_num]['single_h'] = 0;
$parcels[$parcel_num]['single_l'] = 0;
$parcels[$parcel_num]['cubed'] = 0;
$parcels[$parcel_num]['price'] = 0;
// echo " also 20KG " ;
}
}
}
else {
//Check the length class, if it isn't mm we need to convert it
//If the length value is 0 we use 100mm (10cm) as a fallback
if($cartitem['width'] != 0) {
$item_width = $this->length->convert($cartitem['width'], $cartitem['length_class_id'], $unit_mm);
} else {
$item_width = 100;
}
if($cartitem['height'] != 0) {
$item_height = $this->length->convert($cartitem['height'], $cartitem['length_class_id'], $unit_mm);
} else {
$item_height = 100;
}
if($cartitem['length'] != 0) {
$item_length = $this->length->convert($cartitem['length'], $cartitem['length_class_id'], $unit_mm);
} else {
$item_length = 100;
}
$parcels[$parcel_num]['weight'] = $product_weight;
$parcels[$parcel_num]['items'] = $cartitem['quantity'];
//Price is used only for insurance (per parcel)
$parcels[$parcel_num]['price'] = $cartitem['price'];
//Cubed is used if there is more than one item in this parcel
$parcels[$parcel_num]['cubed'] = ($item_width * $item_height * $item_length);
//Single values are clobbered everytime an item is put into this parcel, single values are only used if this parcel contains a single item
$parcels[$parcel_num]['single_w'] = $item_width;
$parcels[$parcel_num]['single_h'] = $item_height;
$parcels[$parcel_num]['single_l'] = $item_length;
//We have placed the item in a parcel
$item_placed = true;
$parcel_num++;
// echo "else";
}
}
}
}
}
foreach ($validmethods as $postmethod) {
if($this->config->get('auspost_' . $postmethod) && $error == FALSE) {
$combined_postcharge = 0;
for($plp = 0; $plp < count($parcels); $plp++) {
if($parcels[$plp]['items'] == 1) {
$postcharge = $this->getAuspostQuote($address['postcode'], $postmethod, $parcels[$plp]['weight'], $country_info['iso_code_2'], $parcels[$plp]['single_w'], $parcels[$plp]['single_h'], $parcels[$plp]['single_l'] , $parcels[$plp]['price']);
// echo "1 post";
} else {
// echo "2 post";
$postcharge = $this->getAuspostQuote($address['postcode'], $postmethod, $parcels[$plp]['weight'], $country_info['iso_code_2'], $parcels[$plp]['single_w'], $parcels[$plp]['single_h'], $parcels[$plp]['single_l'] , $parcels[$plp]['price']);
//$postcharge = $this->getAuspostQuote($address['postcode'], $postmethod, $parcels[$plp]['weight'], $country_info['iso_code_2'], round(pow($parcels[$plp]['cubed'],1/3)), round(pow($parcels[$plp]['cubed'],1/3)), round(pow($parcels[$plp]['cubed'],1/3)), $parcels[$plp]['price']);
}
if($postcharge[0] < 0) {
$error = $postcharge[1];
} else {
$combined_postcharge += $postcharge[0];
}
}
if($error == FALSE) {
$quote_data['auspost_' . $postmethod] = array(
'code' => 'auspost.auspost_' . $postmethod,
'title' => $this->language->get('text_' . $postmethod). $postcharge[1],
'cost' => $combined_postcharge,
'tax_class_id' => $this->config->get('auspost_tax_class_id'),
'text' => '$' . sprintf('%.2f', ($this->tax->calculate($combined_postcharge, $this->config->get('auspost_tax_class_id'), $this->config->get('config_tax'))))
);
}
}
}
//Code for prepaid satchels
//Satchels do not feedback any errors, they are just displayed if the weight fits in the criteria and the method is enabled
if($country_info['iso_code_2'] == 'AU') {
foreach (array("satchreg", "satcheby", "satchexp", "satchpla") as $postmethod) {
if($this->config->get('auspost_' . $postmethod) && $error == FALSE) {
$satcharge = $this->getAuspostSatchel($postmethod, $weight);
if($satcharge > 0) {
$quote_data['auspost_' . $postmethod] = array(
'code' => 'auspost.auspost_' . $postmethod,
'title' => $this->language->get('text_' . $postmethod),
'cost' => $satcharge,
'tax_class_id' => $this->config->get('auspost_tax_class_id'),
'text' => '$' . sprintf('%.2f', ($this->tax->calculate($satcharge, $this->config->get('auspost_tax_class_id'), $this->config->get('config_tax'))))
);
}
}
}
}
//If there are no postage quotes, we don't want to return an empty set (but we do want to make sure errors are displayed)
if((count($quote_data) != 0) || ($error != FALSE && $this->config->get('auspost_errdisplay'))) {
$method_data = array(
'code' => 'auspost',
'title' => $this->language->get('text_title'),
'quote' => $quote_data,
'sort_order' => $this->config->get('auspost_sort_order'),
'error' => $error
);
}
return $method_data;
} //End Auspost module is enabled
} //End of getQuote function
private function getAuspostQuote($dst_postcode, $service, $weight, $country, $width, $height, $length, $parcel_value) {
$ch = curl_init();
//Registered and Registered (Insured) are both the 'standard' shipping method with additional fees added
if($service == "registered" || $service == "insured") {
$req_service = "standard";
} else {
$req_service = $service;
}
//Australia Post appear to have some undocumented minimum values for different dimensions, check that items passed aren't below the minimums
if($width < 30) {$width = 30;}
if($height < 50) {$height = 50;}
if($length < 50) {$length = 50;}
$request_url = 'http://drc.edeliver.com.au/ratecalc.asp?pickup_postcode=' . $this->config->get('auspost_postcode') . '&width=' . $width . '&height=' . $height . '&length=' . $length . '&country=' . $country . '&service_type=' . $req_service . '&quantity=1&weight=' . $weight;
if(strtolower($country) == "au") {
$request_url .= '&destination_postcode=' . $dst_postcode;
}
curl_setopt($ch, CURLOPT_URL,$request_url);
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$get_quote = curl_exec($ch);
curl_close($ch);
if (strstr($get_quote, 'err_msg=OK') == FALSE) {
//This is going to be returned as an error, set the value to less than 0
$auspost_quote[0] = -1;
//Check if the string is even remotely what we are looking for (if so, we know Auspost doesn't like the combo)
if(strstr($get_quote, 'err_msg=') == FALSE) {
$auspost_quote[1] = 'Error interfacing with Australia Post (connection)';
} else {
if(strstr($get_quote, 'Weight Outside Valid Range') != FALSE) {
//Special case where destination country won't accept parcels over a certain weight, give the customer a better explanation
$auspost_quote[1] = 'Cart is too heavy to ship to this destination';
} else {
//If it's not a special case, feed back the Australia Post error directly
$auspost_quote[1] = substr(strstr($get_quote,'err_msg='),8);
}
}
} else {
$get_quote_charge = preg_match('/^charge=([0-9]{1,3}\.?[0-9]{0,2})/', $get_quote, $quote_charge);
if (!isset($quote_charge[1])) {
$auspost_quote[0] = -1;
$auspost_quote[1] = 'Error interfacing with Australia Post (charge)';
} else {
$post_charge = sprintf('%.2f', $quote_charge[1]);
//Calculate additional values for registered / insured
if($service == "registered" || $service == "insured") {
$post_charge = sprintf('%2.f', $post_charge + 3.15);
}
//Calculate additional insurance cost if the item is over $100AUD (first $100AUD is covered by standard registered post)
if(($service == "insured") && ($parcel_value > 100)) {
$post_charge = sprintf('%.2f', $post_charge + floatval(ceil(($parcel_value - 100) / 100) * 1.50));
}
if (floatval($this->config->get('auspost_handling')) > 0) {
$post_charge = sprintf('%.2f', $post_charge + floatval($this->config->get('auspost_handling')));
}
if ($this->config->get('auspost_stripgst')) {
$auspost_quote[0] = sprintf('%.2f', ($post_charge / 11) * 10);
} else {
$auspost_quote[0] = sprintf('%.2f', $post_charge);
}
$get_post_estimate = preg_match('/days=([0-9]{1,2})/', $get_quote, $post_estimate);
$auspost_quote[1] = '';
if ($this->config->get('auspost_estimate') && isset($post_estimate[1])) {
//Added check for 0 as Australia Post modified their gateway to return 0 for international estimates as they no longer provide them
if (is_numeric($post_estimate[1]) && $post_estimate[1] !=0) {
if($post_estimate[1] == 1) {
$auspost_quote[1] = ' (est. ' . $post_estimate[1] . ' day delivery)';
} else {
$auspost_quote[1] = ' (est. ' . $post_estimate[1] . ' days delivery)';
}
}
}
}
}
return $auspost_quote;
}
private function getAuspostSatchel($service, $weight) {
//Define the different satchel sizes / prices (0 represents unavailable) - Updated April 2012
$satchel = array("satchreg" => array(0 => 7.20, 1 => 11.40, 2 => 14.50),
"satcheby" => array(0 => 6.20, 1=> 10.55, 2=> 0),
"satchexp" => array(0 => 9.55, 1 => 13.05, 2 => 21.65),
"satchpla" => array(0 => 13.90, 1 => 18.35, 2 => 0));
//Default to return 0
$satch_quote = 0;
if($weight <= 500) { $satch_quote = $satchel[$service][0];}
if(($weight > 500) && ($weight <= 3000)) { $satch_quote = $satchel[$service][1];}
if(($weight > 3000) && ($weight <=5000)) { $satch_quote = $satchel[$service][2];}
//Added > 0 check to ensure handling wasn't added if no satchel was suitable
if ((floatval($this->config->get('auspost_handling')) > 0) && $satch_quote > 0 ) {
$satch_quote = sprintf('%.2f', $satch_quote + floatval($this->config->get('auspost_handling')));
}
if ($this->config->get('auspost_stripgst')) {$satch_quote = (($satch_quote / 11) * 10);}
return $satch_quote;
}
}
?>