Mileage based shipping module?
Hi,
I have a portable building manufacturing business and need a shipping module that calculates the mileage from our factory to the customer's delivery address, and then adds a shipping charge cost per mile.
Does anyone know of a shipping module that can do this?
Thanks!
Re: Mileage based shipping module?
Re: Mileage based shipping module?
Quote:
Originally Posted by
Fjolsvith
Hi,
I have a portable building manufacturing business and need a shipping module that calculates the mileage from our factory to the customer's delivery address, and then adds a shipping charge cost per mile.
Does anyone know of a shipping module that can do this?
None that I'm aware of, but it is quite possible that you could use the 'zones' shipping module for this. I'm not sure how easy/hard it would be to configure for your needs though. The way I envisage it is zone#1 = within a 1mile radius, Zone#2 = within a 2mile radius ........ Zone#50 = within a 50mile radius.
Just a thought.
Cheers
RodG
Re: Mileage based shipping module?
I found a snippet of code at http://www.paul-norman.co.uk/2009/07...ce-time-in-php that uses google maps to calculate driving distance in PHP.
Anybody have any idea how to bash this into a shipping module?
Thanks
Re: Mileage based shipping module?
Okay, so I tried my hand at writing a shipping module but it doesn't seem to work. Here is the code:
In includes/modules/shipping/mileageship.php:
Code:
<?php
/**
* @package shippingMethod
* @copyright Copyright 2003-2006 Zen Cart Development Team
* @copyright Portions Copyright 2016 James Plotts
* @license http://www.zen-cart.com/license/2_0.txt GNU Public License V2.0
* @version $Id: mileage.php
* 1/25/2007 - for Zen-Cart 1.5.4
*/
/*
USAGE
*/
class mileageship {
var $code, $title, $description, $enabled, $num_zones;
// class constructor
function mileageship() {
$this->code = 'mileageship';
$this->title = MODULE_SHIPPING_MILEAGESHIP_TEXT_TITLE;
$this->description = MODULE_SHIPPING_MILEAGESHIP_TEXT_DESCRIPTION;
$this->sort_order = MODULE_SHIPPING_MILEAGESHIP_SORT_ORDER;
$this->icon = '';
$this->tax_class = MODULE_SHIPPING_MILEAGESHIP_TAX_CLASS;
$this->tax_basis = MODULE_SHIPPING_MILEAGESHIP_TAX_BASIS;
$this->enabled = ((MODULE_SHIPPING_MILEAGESHIP_STATUS == 'True') ? true : false);
/*// disable only when entire cart is free shipping
if (zen_get_shipping_enabled($this->code)) {
$this->enabled = ((MODULE_SHIPPING_MILEAGESHIP_STATUS == 'True') ? true : false);
}*/
}
// class methods
function quote($method = '') {
global $order, $shipping_weight, $shipping_num_boxes, $total_count;
$dest_mileagecode = $order->delivery['postcode'];
$dest_zone = 0;
$error = false;
try
{
$info = get_driving_information('67653', $dest_mileagecode, false);
echo $info['distance'];
$shipping_cost = $info['distance'];
$shipping_method = MODULE_SHIPPING_MILEAGESHIP_TEXT_WAY . ' ' . $dest_mileagecode;
$done = true;
break;
}
catch(Exception $e)
{
echo 'Caught exception: '.$e->getMessage()."\n";
$error = true;
}
$this->quotes = array('id' => $this->code,
'module' => MODULE_SHIPPING_MILEAGESHIP_TEXT_TITLE,
'methods' => array(array('id' => $this->code,
'title' => $shipping_method,
'cost' => $shipping_cost)));
if ($this->tax_class > 0) {
$this->quotes['tax'] = zen_get_tax_rate($this->tax_class, $order->delivery['country']['id'], $order->delivery['zone_id']);
}
if (zen_not_null($this->icon)) $this->quotes['icon'] = zen_image($this->icon, $this->title);
if ($error == true) $this->quotes['error'] = MODULE_SHIPPING_MILEAGESHIP_INVALID_CODE;
return $this->quotes;
}
function check() {
global $db;
if (!isset($this->_check)) {
$check_query = $db->Execute("select configuration_value from " . TABLE_CONFIGURATION . " where configuration_key = 'MODULE_SHIPPING_MILEAGESHIP_STATUS'");
$this->_check = $check_query->RecordCount();
}
return $this->_check;
}
function install() {
global $db;
$db->Execute("insert into " . TABLE_CONFIGURATION . " (configuration_title, configuration_key, configuration_value, configuration_description, configuration_group_id, sort_order, set_function, date_added) VALUES ('Enable Zip Code Method', 'MODULE_SHIPPING_MILEAGESHIP_STATUS', 'True', 'Do you want to offer mileage code base shipping?', '6', '0', 'zen_cfg_select_option(array(\'True\', \'False\'), ', now())");
//$db->Execute("insert into " . TABLE_CONFIGURATION . " (configuration_title, configuration_key, configuration_value, configuration_description, configuration_group_id, sort_order, set_function, date_added) VALUES ('Calculation Method', 'MODULE_SHIPPING_MILEAGESHIP_METHOD', 'Weight', 'Calculate cost based on Weight, Price or Item?', '6', '0', 'zen_cfg_select_option(array(\'Weight\', \'Price\', \'Item\'), ', now())");
$db->Execute("insert into " . TABLE_CONFIGURATION . " (configuration_title, configuration_key, configuration_value, configuration_description, configuration_group_id, sort_order, use_function, set_function, date_added) values ('Tax Class', 'MODULE_SHIPPING_MILEAGESHIP_TAX_CLASS', '0', 'Use the following tax class on the shipping fee.', '6', '0', 'zen_get_tax_class_title', 'zen_cfg_pull_down_tax_classes(', now())");
$db->Execute("insert into " . TABLE_CONFIGURATION . " (configuration_title, configuration_key, configuration_value, configuration_description, configuration_group_id, sort_order, set_function, date_added) values ('Tax Basis', 'MODULE_SHIPPING_MILEAGESHIP_TAX_BASIS', 'Shipping', 'On what basis is Shipping Tax calculated. Options are<br />Shipping - Based on customers Shipping Address<br />Billing Based on customers Billing address<br />Store - Based on Store address if Billing/Shipping Zone equals Store zone', '6', '0', 'zen_cfg_select_option(array(\'Shipping\', \'Billing\', \'Store\'), ', now())");
$db->Execute("insert into " . TABLE_CONFIGURATION . " (configuration_title, configuration_key, configuration_value, configuration_description, configuration_group_id, sort_order, date_added) values ('Sort Order', 'MODULE_SHIPPING_MILEAGESHIP_SORT_ORDER', '0', 'Sort order of display.', '6', '0', now())");
$db->Execute("insert into " . TABLE_CONFIGURATION . " (configuration_title, configuration_key, configuration_value, configuration_description, configuration_group_id, sort_order, set_function, date_added) values ('Skip Zipcodes, use a comma separated list of the five character Zip codes', 'MODULE_SHIPPING_MILEAGESHIP_SKIPPED', '', 'Disable for the following Zip Codes:', '6', '0', 'zen_cfg_textarea(', now())");
/*for ($i = 1; $i <= $this->num_zones; $i++) {
$default_mileagecodes = '';
if ($i == 1) {
$default_mileagecodes = '33801,33803,33809';
}
$db->Execute("insert into " . TABLE_CONFIGURATION . " (configuration_title, configuration_key, configuration_value, configuration_description, configuration_group_id, sort_order, set_function, date_added) values ('Zone " . $i ." Zip Codes', 'MODULE_SHIPPING_MILEAGESHIP_CODES_" . $i ."', '" . $default_mileagecodes . "', 'Comma separated list of five character mileage codes that are part of Zone " . $i . ".<br />Set as 00000 to indicate all five character mileage codes that are not specifically defined.', '6', '0', 'zen_cfg_textarea(', now())");
$db->Execute("insert into " . TABLE_CONFIGURATION . " (configuration_title, configuration_key, configuration_value, configuration_description, configuration_group_id, sort_order, set_function, date_added) values ('Zone " . $i ." Shipping Table', 'MODULE_SHIPPING_MILEAGESHIP_COST_" . $i ."', '50:5.50,51:0', 'Shipping rates to Zone " . $i . " destinations based on a group of maximum order weights/prices. Example: 3:8.50,7:10.50,... Weight/Price less than or equal to 3 would cost 8.50 for Zone " . $i . " destinations.', '6', '0', 'zen_cfg_textarea(', now())");
$db->Execute("insert into " . TABLE_CONFIGURATION . " (configuration_title, configuration_key, configuration_value, configuration_description, configuration_group_id, sort_order, date_added) values ('Zone " . $i ." Handling Fee', 'MODULE_SHIPPING_MILEAGESHIP_HANDLING_" . $i."', '0', 'Handling Fee for this shipping zone', '6', '0', now())");
}*/
}
function remove() {
global $db;
$db->Execute("delete from " . TABLE_CONFIGURATION . " where configuration_key in ('" . implode("', '", $this->keys()) . "')");
}
function keys() {
$keys = array('MODULE_SHIPPING_MILEAGESHIP_STATUS', 'MODULE_SHIPPING_MILEAGESHIP_METHOD', 'MODULE_SHIPPING_MILEAGESHIP_TAX_CLASS', 'MODULE_SHIPPING_MILEAGESHIP_TAX_BASIS', 'MODULE_SHIPPING_MILEAGESHIP_SORT_ORDER', 'MODULE_SHIPPING_MILEAGESHIP_SKIPPED');
for ($i=1; $i<=$this->num_zones; $i++) {
$keys[] = 'MODULE_SHIPPING_MILEAGESHIP_CODES_' . $i;
$keys[] = 'MODULE_SHIPPING_MILEAGESHIP_COST_' . $i;
$keys[] = 'MODULE_SHIPPING_MILEAGESHIP_HANDLING_' . $i;
}
return $keys;
}
function get_driving_information($start, $finish, $raw = false)
{
if(strcmp($start, $finish) == 0)
{
$time = 0;
if($raw)
{
$time .= ' seconds';
}
return array('distance' => 0, 'time' => $time);
}
$start = urlencode($start);
$finish = urlencode($finish);
$distance = 'unknown';
$time = 'unknown';
$url = 'http://maps.googleapis.com/maps/api/directions/xml?origin='.$start.'&destination='.$finish.'&sensor=false';
if($data = file_get_contents($url))
{
$xml = new SimpleXMLElement($data);
if(isset($xml->route->leg->duration->value) AND (int)$xml->route->leg->duration->value > 0)
{
if($raw)
{
$distance = (string)$xml->route->leg->distance->text;
$time = (string)$xml->route->leg->duration->text;
}
else
{
$distance = (int)$xml->route->leg->distance->value / 1000 / 1.609344;
$time = (int)$xml->route->leg->duration->value;
}
}
else
{
throw new Exception('Could not find that route');
}
return array('distance' => $distance, 'time' => $time);
}
else
{
throw new Exception('Could not resolve URL');
}
}
}
?>
And in the includes/languages/modules/shipping/mileageship.php:
Code:
<?php
//
// +----------------------------------------------------------------------+
// |zen-cart Open Source E-commerce |
// +----------------------------------------------------------------------+
// | Copyright (c) 2003 The zen-cart developers |
// | |
// | http://www.zen-cart.com/index.php |
// | |
/*
// $Id: mileageship.php,v 1.0 2016
// ecw, Eternal Codeworks
// modified for Zen-Cart v 1.5.4 - by James Plotts
//
// Copyright (c) 2016 James Plotts
//
// Released under the GNU General Public License
*/
define('MODULE_SHIPPING_MILEAGESHIP_TEXT_TITLE', 'Mileage Rate');
define('MODULE_SHIPPING_MILEAGESHIP_TEXT_DESCRIPTION', 'Mileage-Based Rate');
define('MODULE_SHIPPING_MILEAGESHIP_TEXT_WAY', 'Deliver To Zipcode: ');
define('MODULE_SHIPPING_MILEAGESHIP_TEXT_UNITS', 'lb(s)');
define('MODULE_SHIPPING_MILEAGESHIP_INVALID_ZONE', 'No delivery/shipping available to the selected zipcode.');
define('MODULE_SHIPPING_MILEAGESHIP_UNDEFINED_RATE', 'The delivery/shipping fee cannot be determined at this time');
define('MODULE_SHIPPING_MILEAGESHIP_INVALID_CODE', 'Sorry. Free Shipping not available in your area.');
?>
Can anyone tell me what is not working?
Re: Mileage based shipping module?
Your function:
get_driving_information
Should be outside of the class, at the bottom of the file ...
Next,, you cannot use the break on line 50 ...
See if that gets you headed in the right direction ...
Would love to see this when it is complete ... :smile:
Re: Mileage based shipping module?
Okay, its still broke. When I pull up the Modules -> Shipping Modules page, it doesn't have the right side panel showing.
Also, when I click on the shipping estimator button, the popup is blank.
I also have Paypal Express configured, and when trying to checkout with paypal, when paypal redirects back to the shopping cart, it fails saying my site is not configured properly.
Re: Mileage based shipping module?
This is what I have so far on the file:
/includes/modules/shipping/mileageship.php
Code:
<?php
/**
* @package shippingMethod
* @copyright Copyright 2003-2006 Zen Cart Development Team
* @copyright Portions Copyright 2016 James Plotts
* @license http://www.zen-cart.com/license/2_0.txt GNU Public License V2.0
* @version $Id: mileage.php
* 1/25/2007 - for Zen-Cart 1.5.4
*/
/*
USAGE
*/
class mileageship {
var $code, $title, $description, $enabled, $num_zones;
// class constructor
function mileageship() {
$this->code = 'mileageship';
$this->title = MODULE_SHIPPING_MILEAGESHIP_TEXT_TITLE;
$this->description = MODULE_SHIPPING_MILEAGESHIP_TEXT_DESCRIPTION;
$this->sort_order = MODULE_SHIPPING_MILEAGESHIP_SORT_ORDER;
$this->icon = '';
$this->tax_class = MODULE_SHIPPING_MILEAGESHIP_TAX_CLASS;
$this->tax_basis = MODULE_SHIPPING_MILEAGESHIP_TAX_BASIS;
$this->enabled = ((MODULE_SHIPPING_MILEAGESHIP_STATUS == 'True') ? true : false);
/*// disable only when entire cart is free shipping
if (zen_get_shipping_enabled($this->code)) {
$this->enabled = ((MODULE_SHIPPING_MILEAGESHIP_STATUS == 'True') ? true : false);
}*/
}
// class methods
function quote($method = '') {
global $order, $shipping_weight, $shipping_num_boxes, $total_count;
$dest_mileagecode = $order->delivery['postcode'];
$dest_zone = 0;
$error = false;
try
{
$info = get_driving_information('67653', $dest_mileagecode, false);
echo $info['distance'];
$shipping_cost = $info['distance'];
$shipping_method = MODULE_SHIPPING_MILEAGESHIP_TEXT_WAY . ' ' . $dest_mileagecode;
$done = true;
// break;
}
catch(Exception $e)
{
echo 'Caught exception: '.$e->getMessage()."\n";
$error = true;
}
$this->quotes = array('id' => $this->code,
'module' => MODULE_SHIPPING_MILEAGESHIP_TEXT_TITLE,
'methods' => array(array('id' => $this->code,
'title' => $shipping_method,
'cost' => $shipping_cost)));
if ($this->tax_class > 0) {
$this->quotes['tax'] = zen_get_tax_rate($this->tax_class, $order->delivery['country']['id'], $order->delivery['zone_id']);
}
if (zen_not_null($this->icon)) $this->quotes['icon'] = zen_image($this->icon, $this->title);
if ($error == true) $this->quotes['error'] = MODULE_SHIPPING_MILEAGESHIP_INVALID_CODE;
return $this->quotes;
}
function check() {
global $db;
if (!isset($this->_check)) {
$check_query = $db->Execute("select configuration_value from " . TABLE_CONFIGURATION . " where configuration_key = 'MODULE_SHIPPING_MILEAGESHIP_STATUS'");
$this->_check = $check_query->RecordCount();
}
return $this->_check;
}
function install() {
global $db;
$db->Execute("insert into " . TABLE_CONFIGURATION . " (configuration_title, configuration_key, configuration_value, configuration_description, configuration_group_id, sort_order, set_function, date_added) VALUES ('Enable Zip Code Method', 'MODULE_SHIPPING_MILEAGESHIP_STATUS', 'True', 'Do you want to offer mileage code base shipping?', '6', '0', 'zen_cfg_select_option(array(\'True\', \'False\'), ', now())");
//$db->Execute("insert into " . TABLE_CONFIGURATION . " (configuration_title, configuration_key, configuration_value, configuration_description, configuration_group_id, sort_order, set_function, date_added) VALUES ('Calculation Method', 'MODULE_SHIPPING_MILEAGESHIP_METHOD', 'Weight', 'Calculate cost based on Weight, Price or Item?', '6', '0', 'zen_cfg_select_option(array(\'Weight\', \'Price\', \'Item\'), ', now())");
$db->Execute("insert into " . TABLE_CONFIGURATION . " (configuration_title, configuration_key, configuration_value, configuration_description, configuration_group_id, sort_order, use_function, set_function, date_added) values ('Tax Class', 'MODULE_SHIPPING_MILEAGESHIP_TAX_CLASS', '0', 'Use the following tax class on the shipping fee.', '6', '0', 'zen_get_tax_class_title', 'zen_cfg_pull_down_tax_classes(', now())");
$db->Execute("insert into " . TABLE_CONFIGURATION . " (configuration_title, configuration_key, configuration_value, configuration_description, configuration_group_id, sort_order, set_function, date_added) values ('Tax Basis', 'MODULE_SHIPPING_MILEAGESHIP_TAX_BASIS', 'Shipping', 'On what basis is Shipping Tax calculated. Options are<br />Shipping - Based on customers Shipping Address<br />Billing Based on customers Billing address<br />Store - Based on Store address if Billing/Shipping Zone equals Store zone', '6', '0', 'zen_cfg_select_option(array(\'Shipping\', \'Billing\', \'Store\'), ', now())");
$db->Execute("insert into " . TABLE_CONFIGURATION . " (configuration_title, configuration_key, configuration_value, configuration_description, configuration_group_id, sort_order, date_added) values ('Sort Order', 'MODULE_SHIPPING_MILEAGESHIP_SORT_ORDER', '0', 'Sort order of display.', '6', '0', now())");
$db->Execute("insert into " . TABLE_CONFIGURATION . " (configuration_title, configuration_key, configuration_value, configuration_description, configuration_group_id, sort_order, set_function, date_added) values ('Skip Zipcodes, use a comma separated list of the five character Zip codes', 'MODULE_SHIPPING_MILEAGESHIP_SKIPPED', '', 'Disable for the following Zip Codes:', '6', '0', 'zen_cfg_textarea(', now())");
/*for ($i = 1; $i <= $this->num_zones; $i++) {
$default_mileagecodes = '';
if ($i == 1) {
$default_mileagecodes = '33801,33803,33809';
}
$db->Execute("insert into " . TABLE_CONFIGURATION . " (configuration_title, configuration_key, configuration_value, configuration_description, configuration_group_id, sort_order, set_function, date_added) values ('Zone " . $i ." Zip Codes', 'MODULE_SHIPPING_MILEAGESHIP_CODES_" . $i ."', '" . $default_mileagecodes . "', 'Comma separated list of five character mileage codes that are part of Zone " . $i . ".<br />Set as 00000 to indicate all five character mileage codes that are not specifically defined.', '6', '0', 'zen_cfg_textarea(', now())");
$db->Execute("insert into " . TABLE_CONFIGURATION . " (configuration_title, configuration_key, configuration_value, configuration_description, configuration_group_id, sort_order, set_function, date_added) values ('Zone " . $i ." Shipping Table', 'MODULE_SHIPPING_MILEAGESHIP_COST_" . $i ."', '50:5.50,51:0', 'Shipping rates to Zone " . $i . " destinations based on a group of maximum order weights/prices. Example: 3:8.50,7:10.50,... Weight/Price less than or equal to 3 would cost 8.50 for Zone " . $i . " destinations.', '6', '0', 'zen_cfg_textarea(', now())");
$db->Execute("insert into " . TABLE_CONFIGURATION . " (configuration_title, configuration_key, configuration_value, configuration_description, configuration_group_id, sort_order, date_added) values ('Zone " . $i ." Handling Fee', 'MODULE_SHIPPING_MILEAGESHIP_HANDLING_" . $i."', '0', 'Handling Fee for this shipping zone', '6', '0', now())");
}*/
}
function remove() {
global $db;
$db->Execute("delete from " . TABLE_CONFIGURATION . " where configuration_key in ('" . implode("', '", $this->keys()) . "')");
}
function keys() {
$keys = array('MODULE_SHIPPING_MILEAGESHIP_STATUS', 'MODULE_SHIPPING_MILEAGESHIP_METHOD', 'MODULE_SHIPPING_MILEAGESHIP_TAX_CLASS', 'MODULE_SHIPPING_MILEAGESHIP_TAX_BASIS', 'MODULE_SHIPPING_MILEAGESHIP_SORT_ORDER', 'MODULE_SHIPPING_MILEAGESHIP_SKIPPED');
for ($i=1; $i<=$this->num_zones; $i++) {
$keys[] = 'MODULE_SHIPPING_MILEAGESHIP_CODES_' . $i;
$keys[] = 'MODULE_SHIPPING_MILEAGESHIP_COST_' . $i;
$keys[] = 'MODULE_SHIPPING_MILEAGESHIP_HANDLING_' . $i;
}
return $keys;
}
}
function get_driving_information($start, $finish, $raw = false)
{
if(strcmp($start, $finish) == 0)
{
$time = 0;
if($raw)
{
$time .= ' seconds';
}
return array('distance' => 0, 'time' => $time);
}
$start = urlencode($start);
$finish = urlencode($finish);
$distance = 'unknown';
$time = 'unknown';
$url = 'http://maps.googleapis.com/maps/api/directions/xml?origin='.$start.'&destination='.$finish.'&sensor=false';
if($data = file_get_contents($url))
{
$xml = new SimpleXMLElement($data);
if(isset($xml->route->leg->duration->value) AND (int)$xml->route->leg->duration->value > 0)
{
if($raw)
{
$distance = (string)$xml->route->leg->distance->text;
$time = (string)$xml->route->leg->duration->text;
}
else
{
$distance = (int)$xml->route->leg->distance->value / 1000 / 1.609344;
$time = (int)$xml->route->leg->duration->value;
}
}
else
{
throw new Exception('Could not find that route');
}
return array('distance' => $distance, 'time' => $time);
}
else
{
throw new Exception('Could not resolve URL');
}
}
Re: Mileage based shipping module?
Yes, except missing the final "?>".
When I rename the two *.php files to *.ph_, the shipping modules list comes back up properly in Modules -> Shipping Modules. So, something is not right with the install function or in my db.
Re: Mileage based shipping module?
You do not need the closing php tag ?> ... so I deleted it ...
Try a rename on the old file:
mileage.php_somethinghere
as these are self loading directories and you want to avoid errors etc.
The file I posted seems to work fine. I would suggest on code change, there are many that I would add to this file, but for starters, I commented out the original line and change the Zip Code to be the one set in Configuration ... Shipping ...
Code:
// $info = get_driving_information('67653', $dest_mileagecode, false);
$info = get_driving_information(SHIPPING_ORIGIN_ZIP, $dest_mileagecode, false);
This just avoids needing to edit the file for a Zip code change ... (thinking about the future of this one plus many other things to jazz it up) :cool: