_db =& $GLOBALS['db'];
$this->_basket = $basket;
$this->_settings = $GLOBALS['config']->get(__CLASS__);
$this->_config = $GLOBALS['config'];
$this->_weight = (float)$this->_basket['weight'];
// XXX May want to add some weight for packaging, i.e.
// $this->_weight += ($this->_settings['packagingWeight'] > 0) ? $this->_settings['packagingWeight'] : 0;
$this->_value = (float)$this->_basket['subtotal'];
// XXX May want to remove coupon discount, i.e.
// $this->_value -= $this->_basket['discount'];
$this->_item_count = 0;
foreach ($this->_basket['contents'] as $item) {
// XXX May want to exclude digital products from the item count, i.e.
// if ($item['digital']) continue;
$this->_item_count += $item['quantity'];
}
$this->_all_zones = $this->_db->select('CubeCart_shipping_zones', false, false, 'sort_order, id');
$this->_all_rates = $this->_db->select('CubeCart_shipping_rates', false, false, 'zone_id, id');
$this->_debug_lines = array();
}
private function debug($debug, $debug_level = 1) {
if ($this->_settings['debug'] >= $debug_level) {
$this->_debug_lines[] = $debug;
}
}
private function debugH($debug, $debug_level = 1) {
if ($this->_settings['debug'] >= $debug_level) {
$this->_debug_lines[] = '';
$this->_debug_lines[] = $debug;
$this->_debug_lines[] = '';
}
}
private function echo_debug() {
if ($this->_settings['debug']) {
echo '
';
echo 'THIS INFORMATION IS BEING PRINTED BECAUSE : The "All In One Shipping Module now Postage" has debug mode enabled.
';
echo '
TO HIDE THIS INFORMATION : Log into Admin and go to Shipping Methods > All In One Shipping then disable the debug setting.
';
echo implode('
', $this->_debug_lines);
echo '
';
}
}
private function matching_zone_ids() {
$delivery = (isset($this->_basket['delivery_address'])) ? $this->_basket['delivery_address'] : $this->_basket['billing_address'];
// Crazy bug work around
if($delivery['state_abbrev']==$delivery['state'] && $delivery['state_abbrev']=$delivery['state_id']) {
$delivery['state_abbrev'] = getStateFormat($delivery['state'], 'name', 'abbrev');
} elseif(strlen($delivery['state_abbrev'])>4) {
$delivery['state_abbrev'] = getStateFormat($delivery['state_id'], 'id', 'abbrev');
}
if (! $this->_all_zones) {
$this->debugH('SHIPPING ZONES');
$this->debug('No shipping zones setup. Same shipping rates will be used regardless of delivery destination.');
return array(0);
}
$this->debugH('ADDRESS SUMMARY (*** Note: May be shop location if customer has not provided an address)');
$this->debug(sprintf('Country: %s', $delivery['country_iso']));
$this->debug(sprintf('State: %s', $delivery['state_abbrev']));
$this->debug(sprintf('Postcode: %s', $delivery['postcode']));
$country_iso = $delivery['country_iso'];
$state_id = is_numeric($delivery['state_id']) ? $delivery['state_id'] : 0;
$state_abbrev = sprintf('%s',$delivery['state_abbrev']);
// postcodes
$del_postcode = $delivery['postcode'];
$del_postcode = strtoupper(preg_replace('/[^a-zA-Z0-9]/', '', $del_postcode));
if ($country_iso == 'GB' && strlen($del_postcode) >= 5) {
$del_postcode_district = substr($del_postcode,0,-3);
$del_postcode_area = '';
if (preg_match('/^([a-zA-Z]{1,2})/', $del_postcode_district, $matches)) {
$del_postcode_area = $matches[1];
}
$this->debug('(UK only) Delivery postcode split into area/district/rest: '.$del_postcode_area.' '.str_replace($del_postcode_area, '', $del_postcode_district).' '.substr($del_postcode,-3,3));
} elseif ($country_iso == 'US') {
// Force US zip codes to 5 digit
$del_postcode = substr($del_postcode,0 , 5);
}
$this->debugH('SHIPPING ZONES');
$this->debug('All zones:', $debug_level=2);
$this->debug(''.print_r($this->_all_zones, true).'
', $debug_level=2);
$closest_match = 0;
$closest_match_zone_id = 0;
for ($i=0; $i_all_zones); $i++) {
$debug_zone = sprintf('%s [Zone ID %s]', $this->_all_zones[$i]['zone_name'], $this->_all_zones[$i]['id']);
if (preg_match(sprintf('/\b%s\b/',$country_iso), $this->_all_zones[$i]['countries'])) {
// postcodes
if (!empty($this->_all_zones[$i]['postcodes'])) {
if (empty($del_postcode)) {
$this->debug($debug_zone.' --- Country matched but this is a postcode zone and no postcode was provided - incomplete match.');
continue;
}
$res = false;
$pc_debug = array();
$postcodes = str_replace(array("\r\n", "\n", ","), '|', $this->_all_zones[$i]['postcodes']);
$postcodes = preg_replace('/[^a-zA-Z0-9\*\-\|%_]/', '', $postcodes);
if (is_numeric($del_postcode) && preg_match_all('/([0-9]+)[\-]([0-9]+)/', $postcodes, $matches, PREG_SET_ORDER)) {
for ($m=0; !$res && $m$closest_match) {
$this->debug('Best match so far is "'.$match.'"');
$closest_match_zone_id = $this->_all_zones[$i]['id'];
}
}
}
$res = $res || preg_match($search, $del_postcode_area, $matches);
if(is_array($matches)) {
foreach($matches as $match) {
$match_len = strlen($match);
if($match_len>$closest_match) {
$this->debug('Best match so far is "'.$match.'"');
$closest_match_zone_id = $this->_all_zones[$i]['id'];
}
}
}
}
$pc_debug[] = '- Postcode string search: '.$search.' '.($res?'(MATCHED!)':'(Didn\'t match)');
}
}
if ($res == false) {
$this->debug($debug_zone.' --- Country matched but postcode search didn\'t match...');
for ($j=0; $pc_debug && $jdebug($pc_debug[$j]);
}
continue;
}
$this->debug($debug_zone.' --- Country matched and postcode matched...');
for ($j=0; $pc_debug && $jdebug($pc_debug[$j]);
}
} else if (!empty($this->_all_zones[$i]['states'])) {
if (empty($state_abbrev)) {
$this->debug($debug_zone.' --- Country matched but this is a state/province zone and no state/province was provided - incomplete match.');
continue;
}
if (!preg_match('/\b'.$state_abbrev.'\b/', $this->_all_zones[$i]['states'])) {
$this->debug($debug_zone.sprintf(' --- Country matched but state/province didn\'t match [%s]', $this->_all_zones[$i]['states']));
continue;
}
$this->debug($debug_zone.sprintf(' --- Country matched and state/province matched! [%s]', $this->_all_zones[$i]['states']));
} else {
$this->debug($debug_zone.sprintf(' --- Country matched! [%s]', $this->_all_zones[$i]['countries']));
}
// If made it this far, we have found a matching zone!
if (!isset($zone_ids)) $zone_ids = array();
$zone_ids[] = $this->_all_zones[$i]['id'];
$this->debug(sprintf('>>> Shipping zone [ID %s] matches the delivery address! Use this zone for shipping calculations.', $this->_all_zones[$i]['id']));
if ($this->_settings['multiple_zones'] == 'first') {
$this->debug('Looking for first matching zone of best match (instead of searching for all matching zones - see AIOS module settings)');
} else {
$this->debug('Searching for all matching shipping zones (instead of stopping at first matching zone - see AIOS module settings)');
}
}
else $this->debug($debug_zone.sprintf(' --- Country didn\'t match [%s]', $this->_all_zones[$i]['countries']));
}
if($this->_settings['multiple_zones'] == 'first' && $closest_match_zone_id>0) {
$zone_ids = array($closest_match_zone_id);
}
if (!isset($zone_ids)) {
$this->debug('>>> Use Rest of World zone for shipping calculations.');
$zone_ids = array(0);
}
return $zone_ids;
}
private function matching_rates($zone_ids) {
if (!is_array($zone_ids)) {
return array();
}
$this->debugH('SHIPPING RATES');
$this->debug('All rates:', $debug_level=2);
$this->debug(''.print_r($this->_all_rates, true).'
', $debug_level=2);
$this->debug(sprintf('Looking at the shipping rates for zone(s) [ID %s]', implode(', ',$zone_ids)));
// resulting matching rates (if any)
$rates = array();
$count = count($this->_all_rates);
for ($i=0; !empty($this->_all_rates) && $i<$count; $i++) {
$r = $this->_all_rates[$i];
if (in_array($r['zone_id'], $zone_ids)) {
$ok = true;
if ($this->_settings['range_weight']) {
/* if ($this->_weight <= $r['min_weight'] && $r['min_weight'] > 0) { */
if ($this->_weight < $r['min_weight'] && $r['min_weight'] > 0) {
$ok = false;
} else if ($this->_weight > $r['max_weight'] && $r['max_weight'] > 0) {
$ok = false;
}
if (!$ok) $this->debug(sprintf('Rate [ID: %d] [%s] --- Weight range [%s < weight <= %s] doesn\'t match basket weight [%s]', $r['id'], $r['method_name'], $r['min_weight'], $r['max_weight'], $this->_weight));
}
if ($ok && $this->_settings['range_subtotal']) {
if ($this->_value <= $r['min_value'] && $r['min_value'] > 0) {
$ok = false;
} else if ($this->_value > $r['max_value'] && $r['max_value'] > 0) {
$ok = false;
}
if (!$ok) $this->debug(sprintf('Rate [ID: %d] [%s] --- Subtotal range [%s < subtotal <= %s] doesn\'t match basket subtotal [%s]', $r['id'], $r['method_name'], $r['min_value'], $r['max_value'], $this->_value));
}
if ($ok && $this->_settings['range_items']) {
if ($this->_item_count < $r['min_items'] && $r['min_items'] > 0) {
$ok = false;
} else if ($this->_item_count > $r['max_items'] && $r['max_items'] > 0) {
$ok = false;
}
if (!$ok) $this->debug(sprintf('Rate [ID: %d] [%s] --- Total Quantity range [%s < total quantity < %s] doesn\'t match basket total quantity [%s]', $r['id'], $r['method_name'], $r['min_items'], $r['max_items'], $this->_item_count));
}
if ($ok) {
$this->debug(sprintf('Rate [ID: %d] [%s] --- Shipping rate is valid for this basket!', $r['id'], $r['method_name']));
$rates[] = $r;
}
}
}
return $rates;
}
public function calculate() {
$this->debugH('BASKET TOTALS');
$this->debug(sprintf('Basket weight: %.3F', $this->_weight));
$this->debug(sprintf('Basket value: %.2F', $this->_value));
$this->debug(sprintf('Basket item count: %d', $this->_item_count));
$zone_ids = $this->matching_zone_ids();
$rates = $this->matching_rates($zone_ids);
// CALCULATE PRICE FOR EACH SHIPPING METHOD
$this->_package = array();
for ($i=0; !empty($rates) && $i_settings['use_flat']) $price += $rates[$i]['flat_rate'];
if ($this->_settings['use_weight']) $price += $rates[$i]['weight_rate'] * $this->_weight;
if ($this->_settings['use_item']) $price += $rates[$i]['item_rate'] * $this->_item_count;
if ($this->_settings['use_percent']) $price += $rates[$i]['percent_rate']/100 * $this->_value;
$this->_package[] = array(
'name' => $rates[$i]['method_name'],
'value' => sprintf('%.2F', $price),
'tax_id' => (int)$this->_settings['tax'],
'tax_inclusive' => (int)$this->_settings['tax_included'],
## Delivery times not applicable to this module
'shipping' => '',
'delivery' => '',
'next_day' => ''
);
}
if (!empty($this->_package)) {
$this->debugH('FINAL SHIPPING OPTIONS FOR THIS ADDRESS AND BASKET');
foreach ($this->_package as $p)
$this->debug(sprintf('%s: %s', $p['name'], $p['value']));
} else {
$this->debugH('All In One Shipping module has no shipping options for this address and basket!');
}
$this->echo_debug();
return !empty($this->_package) ? $this->_package : false;
}
public function tracking($tracking_id = false) {
return false;
}
}
?>