rules_shipping_base.php 60.9 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<?php

defined ('_JEXEC') or die('Restricted access');

/**
 * Shipment plugin for general, rules-based shipments, like regular postal services with complex shipping cost structures
 *
 * @version $Id$
 * @package VirtueMart
 * @subpackage Plugins - shipment
 * @copyright Copyright (C) 2004-2012 VirtueMart Team - All rights reserved.
 * @copyright Copyright (C) 2013 Reinhold Kainhofer, reinhold@kainhofer.com
 * @license http://www.gnu.org/copyleft/gpl.html GNU/GPL, see LICENSE.php
 * VirtueMart is free software. This version may have been modified pursuant
 * to the GNU General Public License, and as distributed it includes or
 * is derivative of works licensed under the GNU General Public License or
 * other free or open source software licenses.
 * See /administrator/components/com_virtuemart/COPYRIGHT.php for copyright notices and details.
 *
 * http://virtuemart.org
 * @author Reinhold Kainhofer, based on the weight_countries shipping plugin by Valerie Isaksen
 *
 */
if (!class_exists ('vmPSPlugin')) {
	require(JPATH_VM_PLUGINS . DS . 'vmpsplugin.php');
}
// Only declare the class once...
Reinhold Kainhofer's avatar
Reinhold Kainhofer committed
28
if (class_exists ('plgVmShipmentRules_Shipping_Base')) {
29
30
	return;
}
31

32

33
34
35
function is_equal($a, $b) {
	if (is_array($a) && is_array($b)) {
		return !array_diff($a, $b) && !array_diff($b, $a);
36
37
	} elseif (is_string($a) && is_string($b)) {
		return strcmp($a,$b) == 0;
38
39
40
41
	} else {
		return $a == $b;
	}
}
42
43


44
/** Shipping costs according to general rules.
Reinhold Kainhofer's avatar
Reinhold Kainhofer committed
45
 *  Supported Variables: Weight, ZIP, Amount, Products (1 for each product, even if multiple ordered), Articles
46
47
48
 *  Assignable variables: Shipping, Name
 */
class plgVmShipmentRules_Shipping_Base extends vmPSPlugin {
49
50
51
52
	// Store the parsed and possibly evaluated rules for each method (method ID is used as key)
	protected $rules = array();
	protected $match = array();
	var $custom_functions = array ();
53
54
55
56
57
58
59
60
61
62
63
64
65
66

	/**
	 * @param object $subject
	 * @param array  $config
	 */
	function __construct (& $subject, $config) {
		parent::__construct ($subject, $config);

		$this->_loggable = TRUE;
		$this->_tablepkey = 'id';
		$this->_tableId = 'id';
		$this->tableFields = array_keys ($this->getTableSQLFields ());
		$varsToPush = $this->getVarsToPush ();
		$this->setConfigParameterable ($this->_configTableFieldName, $varsToPush);
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
		
		// PLUGIN FUNCTIONALITY:
		// Let other plugins add custom functions! 
		// The onVmShippingRulesRegisterCustomFunctions() trigger is expected to return an array of the form:
		//   array ('functionname1' => 'function-to-be-called',
		//          'functionname2' => array($classobject, 'memberfunc')),
		//          ...);
		JPluginHelper::importPlugin('vmshipmentrules');
		$dispatcher = JDispatcher::getInstance();
		$custfuncdefs = $dispatcher->trigger('onVmShippingRulesRegisterCustomFunctions',array());
		// Loop through the return values of all plugins:
		foreach ($custfuncdefs as $custfuncs) {
			if (empty($custfuncs))
				continue;
			if (!is_array($custfuncs)) {
				$this->printWarning(JText::sprintf('VMSHIPMENT_RULES_CUSTOMFUNCTIONS_NOARRAY', $method->rule_name));
			}
			// Now loop through all custom function definitions of this plugin
			// If a function was registered before, print a warning and use the first definition
			foreach ($custfuncs as $fname => $func) {
				if (isset($this->custom_functions[$fname])) {
					$this->printWarning(JText::sprintf('VMSHIPMENT_RULES_CUSTOMFUNCTIONS_ALREADY_DEFINED', $fname));
				} else {
					vmDebug("Defining custom function $fname");
					$this->custom_functions[strtolower($fname)] = $func;
				}
			}
		}
95
96
97
98
99
100
101
102
103
104
	}

	/**
	 * Create the table for this plugin if it does not yet exist.
	 *
	 * @author Valérie Isaksen
	 */
	public function getVmPluginCreateTableSQL () {
		return $this->createTableSQL ('Shipment Rules Table');
	}
105
106
	
	public function printWarning($message) {
107
		// Keep track of warning messages, so we don't print them twice:
108
		global $printed_warnings;
109
110
		if (!isset($printed_warnings))
			$printed_warnings = array();
111
112
113
114
115
		if (!in_array($message, $printed_warnings)) {
			JFactory::getApplication()->enqueueMessage($message, 'error');
			$printed_warnings[] = $message;
		}
	}
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175

	/**
	 * @return array
	 */
	function getTableSQLFields () {
		$SQLfields = array(
			'id'                           => 'int(1) UNSIGNED NOT NULL AUTO_INCREMENT',
			'virtuemart_order_id'          => 'int(11) UNSIGNED',
			'order_number'                 => 'char(32)',
			'virtuemart_shipmentmethod_id' => 'mediumint(1) UNSIGNED',
			'shipment_name'                => 'varchar(5000)',
			'rule_name'                    => 'varchar(500)',
			'order_weight'                 => 'decimal(10,4)',
			'order_articles'               => 'int(1)',
			'order_products'               => 'int(1)',
			'shipment_weight_unit'         => 'char(3) DEFAULT \'KG\'',
			'shipment_cost'                => 'decimal(10,2)',
			'tax_id'                       => 'smallint(1)'
		);
		return $SQLfields;
	}

	/**
	 * This method is fired when showing the order details in the frontend.
	 * It displays the shipment-specific data.
	 *
	 * @param integer $virtuemart_order_id The order ID
	 * @param integer $virtuemart_shipmentmethod_id The selected shipment method id
	 * @param string  $shipment_name Shipment Name
	 * @return mixed Null for shipments that aren't active, text (HTML) otherwise
	 * @author Valérie Isaksen
	 * @author Max Milbers
	 */
	public function plgVmOnShowOrderFEShipment ($virtuemart_order_id, $virtuemart_shipmentmethod_id, &$shipment_name) {
		$this->onShowOrderFE ($virtuemart_order_id, $virtuemart_shipmentmethod_id, $shipment_name);
	}

	/**
	 * This event is fired after the order has been stored; it gets the shipment method-
	 * specific data.
	 *
	 * @param int    $order_id The order_id being processed
	 * @param object $cart  the cart
	 * @param array  $order The actual order saved in the DB
	 * @return mixed Null when this method was not selected, otherwise true
	 * @author Valerie Isaksen
	 */
	function plgVmConfirmedOrder (VirtueMartCart $cart, $order) {

		if (!($method = $this->getVmPluginMethod ($order['details']['BT']->virtuemart_shipmentmethod_id))) {
			return NULL; // Another method was selected, do nothing
		}
		if (!$this->selectedThisElement ($method->shipment_element)) {
			return FALSE;
		}
		$values['virtuemart_order_id'] = $order['details']['BT']->virtuemart_order_id;
		$values['order_number'] = $order['details']['BT']->order_number;
		$values['virtuemart_shipmentmethod_id'] = $order['details']['BT']->virtuemart_shipmentmethod_id;
		$values['shipment_name'] = $this->renderPluginName ($method);
		$values['rule_name'] = $method->rule_name;
176
177
178
// 		$values['order_weight'] = $this->getOrderWeight ($cart, $method->weight_unit);
// 		$values['order_articles'] = $this->getOrderArticles ($cart);
// 		$values['order_products'] = $this->getOrderProducts ($cart);
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
		$values['shipment_weight_unit'] = $method->weight_unit;
		$values['shipment_cost'] = $method->cost;
		$values['tax_id'] = $method->tax_id;
		$this->storePSPluginInternalData ($values);

		return TRUE;
	}

	/**
	 * This method is fired when showing the order details in the backend.
	 * It displays the shipment-specific data.
	 * NOTE, this plugin should NOT be used to display form fields, since it's called outside
	 * a form! Use plgVmOnUpdateOrderBE() instead!
	 *
	 * @param integer $virtuemart_order_id The order ID
	 * @param integer $virtuemart_shipmentmethod_id The order shipment method ID
	 * @param object  $_shipInfo Object with the properties 'shipment' and 'name'
	 * @return mixed Null for shipments that aren't active, text (HTML) otherwise
	 * @author Valerie Isaksen
	 */
	public function plgVmOnShowOrderBEShipment ($virtuemart_order_id, $virtuemart_shipmentmethod_id) {
		if (!($this->selectedThisByMethodId ($virtuemart_shipmentmethod_id))) {
			return NULL;
		}
		$html = $this->getOrderShipmentHtml ($virtuemart_order_id);
		return $html;
	}

	/**
	 * @param $virtuemart_order_id
	 * @return string
	 */
	function getOrderShipmentHtml ($virtuemart_order_id) {

		$db = JFactory::getDBO ();
		$q = 'SELECT * FROM `' . $this->_tablename . '` '
			. 'WHERE `virtuemart_order_id` = ' . $virtuemart_order_id;
		$db->setQuery ($q);
		if (!($shipinfo = $db->loadObject ())) {
			vmWarn (500, $q . " " . $db->getErrorMsg ());
			return '';
		}

		if (!class_exists ('CurrencyDisplay')) {
			require(JPATH_VM_ADMINISTRATOR . DS . 'helpers' . DS . 'currencydisplay.php');
		}

		$currency = CurrencyDisplay::getInstance ();
		$tax = ShopFunctions::getTaxByID ($shipinfo->tax_id);
		$taxDisplay = is_array ($tax) ? $tax['calc_value'] . ' ' . $tax['calc_value_mathop'] : $shipinfo->tax_id;
		$taxDisplay = ($taxDisplay == -1) ? JText::_ ('COM_VIRTUEMART_PRODUCT_TAX_NONE') : $taxDisplay;

		$html = '<table class="adminlist">' . "\n";
		$html .= $this->getHtmlHeaderBE ();
		$html .= $this->getHtmlRowBE ('RULES_SHIPPING_NAME', $shipinfo->shipment_name);
		$html .= $this->getHtmlRowBE ('RULES_WEIGHT', $shipinfo->order_weight . ' ' . ShopFunctions::renderWeightUnit ($shipinfo->shipment_weight_unit));
		$html .= $this->getHtmlRowBE ('RULES_ARTICLES', $shipinfo->order_articles . '/' . $shipinfo->order_products);
		$html .= $this->getHtmlRowBE ('RULES_COST', $currency->priceDisplay ($shipinfo->shipment_cost));
		$html .= $this->getHtmlRowBE ('RULES_TAX', $taxDisplay);
		$html .= '</table>' . "\n";

		return $html;
	}
	
	/** Include the rule name in the shipment name */
	protected function renderPluginName ($plugin) {
		$return = '';
		$plugin_name = $this->_psType . '_name';
		$plugin_desc = $this->_psType . '_desc';
		$description = '';
		// 		$params = new JParameter($plugin->$plugin_params);
		// 		$logo = $params->get($this->_psType . '_logos');
		$logosFieldName = $this->_psType . '_logos';
		$logos = $plugin->$logosFieldName;
		if (!empty($logos)) {
			$return = $this->displayLogos ($logos) . ' ';
		}
		if (!empty($plugin->$plugin_desc)) {
257
			$description = '<span class="' . $this->_type . '_description">' . $plugin->$plugin_desc . '</span>';
258
259
260
		}
		$rulename='';
		if (!empty($plugin->rule_name)) {
261
			$rulename=" (".htmlspecialchars($plugin->rule_name).")";
262
		}
263
		$pluginName = $return . '<span class="' . $this->_type . '_name">' . $plugin->$plugin_name . $rulename.'</span>' . $description;
264
265
266
267
		return $pluginName;
	}


268
269
270
	/** This function evaluates all rules, one after the other until it finds a matching rule that
	 *  defines shipping costs (or uses NoShipping). If a modifier or definition is encountered,
	 *  its effect is stored, but the loop continues */
271
272
	protected function evaluateMethodRules ($cart, $method, $cart_prices) {
		// $method->match will cache the matched rule and the modifiers
273
274
		if (isset($this->match[$method->virtuemart_shipmentmethod_id])) {
			return $this->match[$method->virtuemart_shipmentmethod_id];
275
276
277
278
		} else {
			// Evaluate all rules and find the matching ones (including modifiers and definitions!)
			$result = array("rule"=>Null, "rule_name"=>"", "modifiers_add"=>array(), "modifiers_multiply"=>array());
			$cartvals = $this->getCartValues ($cart, $cart->products, $method, $cart_prices);
279
			// Pass a callback function to the rules to obtain the cartvals for a subset of the products
280
281
282
283
			$this_class = $this;
			$cartvals_callback = function ($products) use ($this_class, $cart, $method, $cart_prices) {
				return $this_class->getCartValues ($cart, $products, $method, NULL);
			};
284
			foreach ($this->rules[$method->virtuemart_shipmentmethod_id] as $r) {
285
				if ($r->matches($cartvals, $cart->products, $cartvals_callback)) {
286
287
					$rtype = $r->getType();
					switch ($rtype) {
288
289
290
291
						case 'shipping': 
						case 'shippingwithtax':
						case 'noshipping': 
								$result["rule"] = $r;
292
								$result["rule_name"] = $r->getRuleName();
293
								break;
294
295
296
						case 'modifiers_add':
						case 'modifiers_multiply':
								$result[$rtype][] = $r;
297
								break;
298
						case 'definition': // A definition updates the $cartvals, but has no other effects
299
								$cartvals[strtolower($r->getRuleName())] = $r->getValue();
300
301
								break;
						default:
302
								$this->printWarning(JText::sprintf('VMSHIPMENT_RULES_UNKNOWN_TYPE', $r->getType(), $r->rulestring));
303
304
305
306
								break;
					}
				}
				if (!is_null($result["rule"])) {
307
					$this->match[$method->virtuemart_shipmentmethod_id] = $result;
308
309
					return $result; // <- This also breaks out of the foreach loop!
				}
310
311
			}
		}
312
313
		// None of the rules matched, so return NULL, but keep the evaluated results;
		$this->match[$method->virtuemart_shipmentmethod_id] = $result;
314
315
316
317
318
319
320
321
322
323
		return NULL;
	}

	/**
	 * @param \VirtueMartCart $cart
	 * @param int             $method
	 * @param array           $cart_prices
	 * @return bool
	 */
	protected function checkConditions ($cart, $method, $cart_prices) {
324
		if (!isset($this->rules[$method->virtuemart_shipmentmethod_id])) 
325
326
			$this->parseMethodRules($method);
		$match = $this->evaluateMethodRules ($cart, $method, $cart_prices);
327
328
329
		if ($match) {
			$method->rule_name = $match["rule_name"];
			// If NoShipping is set, this method should NOT offer any shipping at all, so return FALSE, otherwise TRUE
330
			// If the rule has a name, print it as warning (otherwise don't print anything)
331
			if ($match['rule']->isNoShipping()) {
332
333
				if (!empty($method->rule_name))
					$this->printWarning(JText::sprintf('VMSHIPMENT_RULES_NOSHIPPING_MESSAGE', $method->rule_name));
334
				vmdebug('checkConditions '.$method->shipment_name.' indicates NoShipping for this method, specified by rule "'.$method->rule_name.'" ('.$match['rule']->rulestring.').');
335
336
337
338
339
				return FALSE;
			} else {
				return TRUE;
			}
		}
340
		vmdebug('checkConditions '.$method->shipment_name.' does not fulfill all conditions, no rule matches');
341
342
343
		return FALSE;
	}

344
345
346
347
348
349
350
	/**
	 * @param VirtueMartCart $cart
	 * @param                $method
	 * @param                $cart_prices
	 * @return int
	 */
	function getCosts (VirtueMartCart $cart, $method, $cart_prices) {
351
352
		if (!isset($this->rules[$method->virtuemart_shipmentmethod_id])) 
			$this->parseMethodRules($method);
353
		$match = $this->evaluateMethodRules ($cart, $method, $cart_prices);
354
355
		if ($match) {
			$r = $match["rule"];
356
			vmdebug('Rule ' . $match["rule_name"] . ' ('.$r->rulestring.') matched.');
357
			$method->tax_id = $r->tax_id;
358
			// TODO: Shall we include the name of the modifiers, too?
359
360
361
362
			$method->rule_name = $match["rule_name"];
			// Final shipping costs are calculated as:
			//   Shipping*ExtraShippingMultiplier + ExtraShippingCharge
			// with possibly multiple modifiers
363
			$method->cost = $r->getShippingCosts();
364
			foreach ($match['modifiers_multiply'] as $modifier) {
365
				$method->cost *= $modifier->getValue();
366
367
			}
			foreach ($match['modifiers_add'] as $modifier) {
368
				$method->cost += $modifier->getValue();
369
			}
370
371
			$method->includes_tax = $r->includes_tax;
			return $method->cost;
372
373
374
375
376
377
		}
		
		vmdebug('getCosts '.$method->name.' does not return shipping costs');
		return 0;
	}

378

379
	/**
380
381
382
383
384
	 * update the plugin cart_prices
	 *
	 * Override the plugin's setCartPrices to allow reverse tax calculation (i.e. shipping costs are 
	 * given with taxes, the net price and the tax is calculated from the gross shipping costs)-
	 *  We need separate versions for VM2 and VM3.
385
386
387
388
389
390
391
	 *
	 * @author Valérie Isaksen (original), Reinhold Kainhofer (tax calculations from shippingWithTax)
	 *
	 * @param $cart_prices: $cart_prices['salesPricePayment'] and $cart_prices['paymentTax'] updated. Displayed in the cart.
	 * @param $value :   fee
	 * @param $tax_id :  tax id
	 */
392
393
394
	function setCartPrices (VirtueMartCart $cart, &$cart_prices, $method, $progressive = true) {
		// Copied and adjusted from VirtueMart 2.6.2
		// Lines 984ff, File administrator/components/com_virtuemart/plugins/vmpsplugin.php
395

396
		if (!class_exists ('calculationHelper')) {
397
398
399
400
401
			if(!defined('VM_VERSION') or VM_VERSION < 3){ // VM2:
				require(JPATH_VM_ADMINISTRATOR . DS . 'helpers' . DS . 'calculationh.php');
			} else { // VM 3:
				require(VMPATH_ADMIN . DS . 'helpers' . DS . 'calculationh.php');
			}
402
403
		}
		$_psType = ucfirst ($this->_psType);
404
		$calculator = calculationHelper::getInstance ();
405

406
		$cart_prices[$this->_psType . 'Value'] = $calculator->roundInternal ($this->getCosts ($cart, $method, $cart_prices), 'salesPrice');
407
408
409
410
411
412
413
414
		// BEGIN_RK_CHANGES
		$includes_tax = $method->includes_tax;
		if ($includes_tax) {
			$cart_prices['salesPrice' . $_psType] = $cart_prices[$this->_psType . 'Value'];
		}
		// END_RK_CHANGES
		if(!isset($cart_prices[$this->_psType . 'Value'])) $cart_prices[$this->_psType . 'Value'] = 0.0;
		if(!isset($cart_prices[$this->_psType . 'Tax'])) $cart_prices[$this->_psType . 'Tax'] = 0.0;
415
416
417

		if($this->_psType=='payment'){
			$cartTotalAmountOrig=$this->getCartAmount($cart_prices);
418
419
420
421
422
423
424
425
426
427
428
			if(!$progressive){
				//Simple
				$cartTotalAmount=($cartTotalAmountOrig + $method->cost_per_transaction) * (1 +($method->cost_percent_total * 0.01));
				//vmdebug('Simple $cartTotalAmount = ('.$cartTotalAmountOrig.' + '.$method->cost_per_transaction.') * (1 + ('.$method->cost_percent_total.' * 0.01)) = '.$cartTotalAmount );
				//vmdebug('Simple $cartTotalAmount = '.($cartTotalAmountOrig + $method->cost_per_transaction).' * '. (1 + $method->cost_percent_total * 0.01) .' = '.$cartTotalAmount );
			} else {
				//progressive
				$cartTotalAmount = ($cartTotalAmountOrig + $method->cost_per_transaction) / (1 -($method->cost_percent_total * 0.01));
				//vmdebug('Progressive $cartTotalAmount = ('.$cartTotalAmountOrig.' + '.$method->cost_per_transaction.') / (1 - ('.$method->cost_percent_total.' * 0.01)) = '.$cartTotalAmount );
				//vmdebug('Progressive $cartTotalAmount = '.($cartTotalAmountOrig + $method->cost_per_transaction) .' / '. (1 - $method->cost_percent_total * 0.01) .' = '.$cartTotalAmount );
			}
429
430
431
			$cart_prices[$this->_psType . 'Value'] = $cartTotalAmount - $cartTotalAmountOrig;
		}

432
		if(!isset($cart_prices['salesPrice' . $_psType])) $cart_prices['salesPrice' . $_psType] = $cart_prices[$this->_psType . 'Value'];
433
434

		$taxrules = array();
435
436
437
		if(isset($method->tax_id) and (int)$method->tax_id === -1){

		} else if (!empty($method->tax_id)) {
438
439
440
441
442
443
			$cart_prices[$this->_psType . '_calc_id'] = $method->tax_id;

			$db = JFactory::getDBO ();
			$q = 'SELECT * FROM #__virtuemart_calcs WHERE `virtuemart_calc_id`="' . $method->tax_id . '" ';
			$db->setQuery ($q);
			$taxrules = $db->loadAssocList ();
444

445
446
447
448
449
450
451
			if(!empty($taxrules) ){
				foreach($taxrules as &$rule){
					if(!isset($rule['subTotal'])) $rule['subTotal'] = 0;
					if(!isset($rule['taxAmount'])) $rule['taxAmount'] = 0;
					$rule['subTotalOld'] = $rule['subTotal'];
					$rule['taxAmountOld'] = $rule['taxAmount'];
					$rule['taxAmount'] = 0;
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
					// BEGIN_RK_CHANGES
					if ($includes_tax) {
						$calculator->setRevert (true);
						$rule['subTotal'] = $cart_prices[$this->_psType . 'Value'];
						$valueWithoutTax = $calculator->roundInternal ($calculator->interpreteMathOp($rule, $rule['subTotal']));
						$cart_prices[$this->_psType . 'TaxPerID'][$rule['virtuemart_calc_id']] = $calculator->roundInternal($rule['subTotal'] - $valueWithoutTax, 'salesPrice');
						$calculator->setRevert (false);
					} else {
					// END_RK_CHANGES
						$rule['subTotal'] = $cart_prices[$this->_psType . 'Value'];
						$cart_prices[$this->_psType . 'TaxPerID'][$rule['virtuemart_calc_id']] = $calculator->roundInternal($calculator->roundInternal($calculator->interpreteMathOp($rule, $rule['subTotal'])) - $rule['subTotal'], 'salesPrice');
					// BEGIN_RK_CHANGES
					}
					// END_RK_CHANGES
					$cart_prices[$this->_psType . 'Tax'] += $cart_prices[$this->_psType . 'TaxPerID'][$rule['virtuemart_calc_id']];
467
468
469
				}
			}
		} else {
470
471
472
473
474
			if(!defined('VM_VERSION') or VM_VERSION < 3){ // VM2:
				$taxrules = array_merge($calculator->_cartData['VatTax'],$calculator->_cartData['taxRulesBill']);
			} else { // VM3:
				$taxrules = array_merge($cart->cartData['VatTax'],$cart->cartData['taxRulesBill']);
			}
475

476
477
			if(!empty($taxrules) ){
				$denominator = 0.0;
478
				foreach($taxrules as &$rule){
479
					//$rule['numerator'] = $rule['calc_value']/100.0 * $rule['subTotal'];
480
481
					if(!isset($rule['subTotal'])) $rule['subTotal'] = 0;
					if(!isset($rule['taxAmount'])) $rule['taxAmount'] = 0;
482
483
484
485
486
487
488
489
490
					// BEGIN_RK_CHANGES
					if ($includes_tax) {
						$denominator += $rule['subTotal'];
					} else {
					// END_RK_CHANGES
						$denominator += ($rule['subTotal']-$rule['taxAmount']);
					// BEGIN_RK_CHANGES
					}
					// END_RK_CHANGES
491
492
493
494
495
496
497
498
					$rule['subTotalOld'] = $rule['subTotal'];
					$rule['subTotal'] = 0;
					$rule['taxAmountOld'] = $rule['taxAmount'];
					$rule['taxAmount'] = 0;
					//$rule['subTotal'] = $cart_prices[$this->_psType . 'Value'];
				}
				if(empty($denominator)){
					$denominator = 1;
499
500
501
				}

				foreach($taxrules as &$rule){
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
					// BEGIN_RK_CHANGES
					if ($includes_tax) {
						$calculator->setRevert (true);
						$frac = $rule['subTotalOld']/$denominator;
						$rule['subTotal'] = $cart_prices[$this->_psType . 'Value'] * $frac;
						$valueWithoutTax = $calculator->roundInternal ($calculator->interpreteMathOp($rule, $rule['subTotal']));
						$cart_prices[$this->_psType . 'TaxPerID'][$rule['virtuemart_calc_id']] = $calculator->roundInternal($rule['subTotal'] - $valueWithoutTax, 'salesPrice');
						$calculator->setRevert (false);
					} else {
					// END_RK_CHANGES
						$frac = ($rule['subTotalOld']-$rule['taxAmountOld'])/$denominator;
						$rule['subTotal'] = $cart_prices[$this->_psType . 'Value'] * $frac;
						//vmdebug('Part $denominator '.$denominator.' $frac '.$frac,$rule['subTotal']);
						$cart_prices[$this->_psType . 'TaxPerID'][$rule['virtuemart_calc_id']] = $calculator->roundInternal($calculator->roundInternal($calculator->interpreteMathOp($rule, $rule['subTotal'])) - $rule['subTotal'], 'salesPrice');
					// BEGIN_RK_CHANGES
					}
					if(!isset($cart_prices[$this->_psType . 'Tax'])) $cart_prices[$this->_psType . 'Tax'] = 0.0;
					// END_RK_CHANGES
					$cart_prices[$this->_psType . 'Tax'] += $cart_prices[$this->_psType . 'TaxPerID'][$rule['virtuemart_calc_id']];
521
522
				}
			}
523
524
		}

525

526
527
528
529
530
531
		if(empty($method->cost_per_transaction)) $method->cost_per_transaction = 0.0;
		if(empty($method->cost_percent_total)) $method->cost_percent_total = 0.0;

		if (count ($taxrules) > 0 ) {

			// BEGIN_RK_CHANGES
532
533
			if ($includes_tax) {
				// Calculate the net shipping cost by removing all taxes:
534
				$calculator->setRevert (true);
535
				$cart_prices[$this->_psType . 'Value'] = $calculator->roundInternal ($calculator->executeCalculation($taxrules, $cart_prices[$this->_psType . 'Value'], true), 'salesPrice');
536
537
				$calculator->setRevert (false);
			} else {
538
			// END_RK_CHANGES
539
540
541
				$cart_prices['salesPrice' . $_psType] = $calculator->roundInternal ($calculator->executeCalculation ($taxrules, $cart_prices[$this->_psType . 'Value'],true,false), 'salesPrice');
				//vmdebug('I am in '.get_class($this).' and have this rules now',$taxrules,$cart_prices[$this->_psType . 'Value'],$cart_prices['salesPrice' . $_psType]);
//				$cart_prices[$this->_psType . 'Tax'] = $calculator->roundInternal (($cart_prices['salesPrice' . $_psType] -  $cart_prices[$this->_psType . 'Value']), 'salesPrice');
542
			// BEGIN_RK_CHANGES
543
			}
544
			// END_RK_CHANGES
545
			reset($taxrules);
546
547
//			$taxrule =  current($taxrules);
//			$cart_prices[$this->_psType . '_calc_id'] = $taxrule['virtuemart_calc_id'];
548
549

			foreach($taxrules as &$rule){
550
551
				if(!isset($cart_prices[$this->_psType . '_calc_id']) or !is_array($cart_prices[$this->_psType . '_calc_id'])) $cart_prices[$this->_psType . '_calc_id'] = array();
				$cart_prices[$this->_psType . '_calc_id'][] = $rule['virtuemart_calc_id'];
552
553
554
555
				if(isset($rule['subTotalOld'])) $rule['subTotal'] += $rule['subTotalOld'];
				if(isset($rule['taxAmountOld'])) $rule['taxAmount'] += $rule['taxAmountOld'];
			}

556
		} else {
557
			$cart_prices['salesPrice' . $_psType] = $cart_prices[$this->_psType . 'Value'];
558
559
560
			$cart_prices[$this->_psType . 'Tax'] = 0;
			$cart_prices[$this->_psType . '_calc_id'] = 0;
		}
561

562
		return $cart_prices['salesPrice' . $_psType];
563

564
	}
565

566
	protected function createMethodRule ($r, $countries, $tax) {
567
		return new ShippingRule($this, $r, $countries, $tax);
568
569
570
571
572
573
574
	}

	private function parseMethodRule ($rulestring, $countries, $tax, &$method) {
		$rules1 = preg_split("/(\r\n|\n|\r)/", $rulestring);
		foreach ($rules1 as $r) {
			// Ignore empty lines
			if (empty($r)) continue;
575
			$this->rules[$method->virtuemart_shipmentmethod_id][] = $this->createMethodRule ($r, $countries, $tax);
576
577
578
579
		}
	}
	
	protected function parseMethodRules (&$method) {
580
581
		if (!isset($this->rules[$method->virtuemart_shipmentmethod_id])) 
			$this->rules[$method->virtuemart_shipmentmethod_id] = array();
582
583
584
585
586
587
588
589
590
591
		$this->parseMethodRule ($method->rules1, $method->countries1, $method->tax_id1, $method);
		$this->parseMethodRule ($method->rules2, $method->countries2, $method->tax_id2, $method);
		$this->parseMethodRule ($method->rules3, $method->countries3, $method->tax_id3, $method);
		$this->parseMethodRule ($method->rules4, $method->countries4, $method->tax_id4, $method);
		$this->parseMethodRule ($method->rules5, $method->countries5, $method->tax_id5, $method);
		$this->parseMethodRule ($method->rules6, $method->countries6, $method->tax_id6, $method);
		$this->parseMethodRule ($method->rules7, $method->countries7, $method->tax_id7, $method);
		$this->parseMethodRule ($method->rules8, $method->countries8, $method->tax_id8, $method);
	}

592
593
594
595
596
	/** Functions to calculate all the different variables for the given cart and given (sub)set of products in the cart */
	protected function getOrderArticles (VirtueMartCart $cart, $products) {
		$articles = 0;
		foreach ($products as $product) {
			$articles += $product->quantity;
597
598
599
600
		}
		return $articles;
	}

601
602
	protected function getOrderProducts (VirtueMartCart $cart, $products) {
		return count($products);
603
604
	}

605
	protected function getOrderDimensions (VirtueMartCart $cart, $products, $length_dimension) {
606
		/* Cache the value in a static variable and calculate it only once! */
607
		$dimensions=array(
608
609
			'volume' => 0,
			'maxvolume' => 0, 'minvolume' => 9999999999,
610
611
612
			'maxlength' => 0, 'minlength' => 9999999999, 'totallength' => 0,
			'maxwidth'  => 0, 'minwidth' => 9999999999,  'totalwidth'  => 0,
			'maxheight' => 0, 'minheight' => 9999999999, 'totalheight' => 0,
613
			'maxpackaging' => 0, 'minpackaging' => 9999999999, 'totalpackaging' => 0,
614
		);
615
		foreach ($products as $product) {
616
	
617
618
619
620
621
622
623
624
			$l = ShopFunctions::convertDimensionUnit ($product->product_length, $product->product_lwh_uom, $length_dimension);
			$w = ShopFunctions::convertDimensionUnit ($product->product_width, $product->product_lwh_uom, $length_dimension);
			$h = ShopFunctions::convertDimensionUnit ($product->product_height, $product->product_lwh_uom, $length_dimension);

			$volume = $l * $w * $h;
			$dimensions['volume'] += $volume * $product->quantity;
			$dimensions['maxvolume'] = max ($dimensions['maxvolume'], $volume);
			$dimensions['minvolume'] = min ($dimensions['minvolume'], $volume);
625
				
626
627
628
629
630
631
632
633
634
635
636
637
			$dimensions['totallength'] += $l * $product->quantity;
			$dimensions['maxlength'] = max ($dimensions['maxlength'], $l);
			$dimensions['minlength'] = min ($dimensions['minlength'], $l);
			$dimensions['totalwidth'] += $w * $product->quantity;
			$dimensions['maxwidth'] = max ($dimensions['maxwidth'], $w);
			$dimensions['minwidth'] = min ($dimensions['minwidth'], $w);
			$dimensions['totalheight'] += $h * $product->quantity;
			$dimensions['maxheight'] = max ($dimensions['maxheight'], $h);
			$dimensions['minheight'] = min ($dimensions['minheight'], $h);
			$dimensions['totalpackaging'] += $product->product_packaging * $product->quantity;
			$dimensions['maxpackaging'] = max ($dimensions['maxpackaging'], $product->product_packaging);
			$dimensions['minpackaging'] = min ($dimensions['minpackaging'], $product->product_packaging);
638
		}
639

640
641
		return $dimensions;
	}
642
	
643
644
	protected function getOrderWeights (VirtueMartCart $cart, $products, $weight_unit) {
		$dimensions=array(
645
646
647
			'weight' => 0,
			'maxweight' => 0, 'minweight' => 9999999999,
		);
648
649
650
651
652
		foreach ($products as $product) {
			$w = ShopFunctions::convertWeigthUnit ($product->product_weight, $product->product_weight_uom, $weight_unit);
			$dimensions['maxweight'] = max ($dimensions['maxweight'], $w);
			$dimensions['minweight'] = min ($dimensions['minweight'], $w);
			$dimensions['weight'] += $w * $product->quantity;
653
		}
654
		return $dimensions;
655
656
	}
	
657
	protected function getOrderListProperties (VirtueMartCart $cart, $products) {
658
659
		$categories = array();
		$vendors = array();
660
		$skus = array();
661
		$manufacturers = array();
662
		foreach ($products as $product) {
663
			$skus[] = $product->product_sku;
664
665
			$categories = array_merge ($categories, $product->categories);
			$vendors[] = $product->virtuemart_vendor_id;
666
667
668
			if ($product->virtuemart_manufacturer_id) {
				$manufacturers[] = $product->virtuemart_manufacturer_id;
			}
669
		}
670
		$skus = array_unique($skus);
671
		$vendors = array_unique($vendors);
672
673
		$categories = array_unique($categories);
		$manufacturers = array_unique($manufacturers);
674
675
676
677
678
		return array ('skus'=>$skus, 
			      'categories'=>$categories,
			      'vendors'=>$vendors,
			      'manufacturers'=>$manufacturers,
		);
679
680
	}
	
681
	protected function getOrderCountryState (VirtueMartCart $cart, $address) {
682
683
684
685
		$data = array (
			'countryid' => 0, 'country' => '', 'country2' => '', 'country3' => '',
			'stateid'   => 0, 'state'   => '', 'state2'   => '', 'state3'   => '',
		);
686
687
688
		
		$countriesModel = VmModel::getModel('country');
		if (isset($address['virtuemart_country_id'])) {
689
			$data['countryid'] = $address['virtuemart_country_id'];
690
691
692
693
694
			// The following is a workaround to make sure the cache is invalidated
			// because if some other extension meanwhile called $countriesModel->getCountries,
			// the cache will be modified, but the model's id will not be changes, so the
			// getData call will return the wrong cache.
			$countriesModel->setId(0); 
695
			$countriesModel->setId($address['virtuemart_country_id']);
696
			$country = $countriesModel->getData($address['virtuemart_country_id']);
697
			if (!empty($country)) {
698
699
700
701
				$data['country'] = $country->country_name;
				$data['country2'] = $country->country_2_code;
				$data['country3'] = $country->country_3_code;
			}
702
703
704
		}
		
		$statesModel = VmModel::getModel('state');
705
		if (isset($address['virtuemart_state_id'])) {
706
			$data['stateid'] = $address['virtuemart_state_id'];
707
708
709
710
711
			// The following is a workaround to make sure the cache is invalidated
			// because if some other extension meanwhile called $countriesModel->getCountries,
			// the cache will be modified, but the model's id will not be changes, so the
			// getData call will return the wrong cache.
			$statesModel->setId(0); 
712
			$statesModel->setId($address['virtuemart_state_id']);
713
			$state = $statesModel->getData($address['virtuemart_state_id']);
714
			if (!empty($state)) {
715
716
717
718
				$data['state'] = $state->state_name;
				$data['state2'] = $state->state_2_code;
				$data['state3'] = $state->state_3_code;
			}
719
720
721
722
723
724
		}
		
		return $data;

	}
	
725
726
727
728
729
730
731
732
733
734
735
	protected function getOrderAddress (VirtueMartCart $cart, $address) {
		$zip = isset($address['zip'])?trim($address['zip']):'';
		$data = array('zip'=>$zip,
			'zip1'=>substr($zip,0,1),
			'zip2'=>substr($zip,0,2),
			'zip3'=>substr($zip,0,3),
			'zip4'=>substr($zip,0,4),
			'zip5'=>substr($zip,0,5),
			'zip6'=>substr($zip,0,6),
			'city'=>isset($address['city'])?trim($address['city']):'',
		);
736
737
738
739
740
741
742
743
744
745
746
747
		$data['company'] = $address['company'];
		$data['title'] = $address['title'];
		$data['first_name'] = $address['first_name'];
		$data['middle_name'] = $address['middle_name'];
		$data['last_name'] = $address['last_name'];
		$data['address1'] = $address['address_1'];
		$data['address2'] = $address['address_2'];
		$data['city'] = $address['city'];
		$data['phone1'] = $address['phone_1'];
		$data['phone2'] = $address['phone_2'];
		$data['fax'] = $address['fax'];
		$data['email'] = $address['email'];
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
		return $data;
	}
	
	protected function getOrderPrices (VirtueMartCart $cart, $products, $cart_prices) {
		$data = array(
			'amount' => 0, 
			'amountwithtax' => 0, 
			'amountwithouttax' => 0, 
			'baseprice' => 0, 
			'basepricewithtax' => 0, 
			'discountedpricewithouttax' => 0, 
			'salesprice' => 0, 
			'taxamount' => 0, 
			'salespricewithdiscount' => 0, 
			'discountamount' => 0, 
			'pricewithouttax' => 0,
		);
		if (!empty($cart_prices)) {
			// get prices for the whole cart -> simply user the cart_prices
			$data['amount']                 = $cart_prices['salesPrice'];
			$data['amountwithtax']          = $cart_prices['salesPrice'];
			$data['amountwithouttax']       = $cart_prices['priceWithoutTax'];
			$data['baseprice']              = $cart_prices['basePrice'];
			$data['basepricewithtax']       = $cart_prices['basePriceWithTax'];
			$data['discountedpricewithouttax'] = $cart_prices['discountedPriceWithoutTax'];
			$data['salesprice']             = $cart_prices['salesPrice'];
			$data['taxamount']              = $cart_prices['taxAmount'];
			$data['salespricewithdiscount'] = $cart_prices['salesPriceWithDiscount'];
			$data['discountamount']         = $cart_prices['discountAmount'];
			$data['pricewithouttax']        = $cart_prices['priceWithoutTax'];
		} else {
			// TODO: Calculate the prices from the individual products!
			// Possible problems are discounts on the order total
			foreach ($products as $product) {
				$data['amount']                 = $product->allPrices[$product->selectedPrice]['salesPrice'];
				$data['amountwithtax']          = $product->allPrices[$product->selectedPrice]['salesPrice'];
				$data['amountwithouttax']       = $product->allPrices[$product->selectedPrice]['priceWithoutTax'];
				$data['baseprice']              = $product->allPrices[$product->selectedPrice]['basePrice'];
				$data['basepricewithtax']       = $product->allPrices[$product->selectedPrice]['basePriceWithTax'];
				$data['discountedpricewithouttax'] = $product->allPrices[$product->selectedPrice]['discountedPriceWithoutTax'];
				$data['salesprice']             = $product->allPrices[$product->selectedPrice]['salesPrice'];
				$data['taxamount']              = $product->allPrices[$product->selectedPrice]['taxAmount'];
				$data['salespricewithdiscount'] = $product->allPrices[$product->selectedPrice]['salesPriceWithDiscount'];
				$data['discountamount']         = $product->allPrices[$product->selectedPrice]['discountAmount'];
				$data['pricewithouttax']        = $product->allPrices[$product->selectedPrice]['priceWithoutTax'];
			}
		}
		return $data;
	}

	/** Allow child classes to add additional variables for the rules or modify existing one
799
	 */
800
	protected function addCustomCartValues (VirtueMartCart $cart, $products, $cart_prices, &$values) {
801
	}
802
803

	protected function getCartValues (VirtueMartCart $cart, $products, $method, $cart_prices) {
804
		$address = (($cart->ST == 0 || $cart->STSameAsBT == 1) ? $cart->BT : $cart->ST);
805
806
807
808
809
810
811
812
813
814
		$cartvals = array_merge (
			array(
				'articles'=>$this->getOrderArticles($cart, $products),
				'products'=>$this->getOrderProducts($cart, $products),
			),
			// Add the prices, optionally calculated from the products subset of the cart
			$this->getOrderPrices ($cart, $products, $cart_prices),
			// Add 'skus', 'categories', 'vendors' variables:
			$this->getOrderListProperties ($cart, $products),
			// Add country / state variables:
815
			$this->getOrderAddress ($cart, $address),
816
817
818
819
820
			$this->getOrderCountryState ($cart, $address),
			// Add Total/Min/Max weight and dimension variables:
			$this->getOrderWeights ($cart, $products, $method->weight_unit),
			$this->getOrderDimensions ($cart, $products, $method->length_unit)
		);
821
		// Let child classes update the $cartvals array, or add new variables
822
		$this->addCustomCartValues($cart, $products, $cart_prices, $cartvals);
823

824
825
826
827
		// Finally, call the triger of vmshipmentrules plugins to let them add/modify variables
		JPluginHelper::importPlugin('vmshipmentrules');
		$dispatcher = JDispatcher::getInstance();
		$dispatcher->trigger('onVmShippingRulesGetCartValues',array(&$cartvals, $cart, $products, $method, $cart_prices));
828

829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
		return $cartvals;
	}

	/**
	 * Create the table for this plugin if it does not yet exist.
	 * This functions checks if the called plugin is active one.
	 * When yes it is calling the standard method to create the tables
	 *
	 * @author Valérie Isaksen
	 *
	 */
	function plgVmOnStoreInstallShipmentPluginTable ($jplugin_id) {
		return $this->onStoreInstallPluginTable ($jplugin_id);
	}

	/**
	 * @param VirtueMartCart $cart
	 * @return null
	 */
	public function plgVmOnSelectCheckShipment (VirtueMartCart &$cart) {
		return $this->OnSelectCheck ($cart);
	}

	/**
	 * plgVmDisplayListFE
	 * This event is fired to display the pluginmethods in the cart (edit shipment/payment) for example
	 *
	 * @param object  $cart Cart object
	 * @param integer $selected ID of the method selected
	 * @return boolean True on success, false on failures, null when this plugin was not selected.
	 * On errors, JError::raiseWarning (or JError::raiseError) must be used to set a message.
	 *
	 * @author Valerie Isaksen
	 * @author Max Milbers
	 */
	public function plgVmDisplayListFEShipment (VirtueMartCart $cart, $selected = 0, &$htmlIn) {
		return $this->displayListFE ($cart, $selected, $htmlIn);
	}

	/**
	 * @param VirtueMartCart $cart
	 * @param array          $cart_prices
	 * @param                $cart_prices_name
	 * @return bool|null
	 */
	public function plgVmOnSelectedCalculatePriceShipment (VirtueMartCart $cart, array &$cart_prices, &$cart_prices_name) {
		return $this->onSelectedCalculatePrice ($cart, $cart_prices, $cart_prices_name);
	}

	/**
	 * plgVmOnCheckAutomaticSelected
	 * Checks how many plugins are available. If only one, the user will not have the choice. Enter edit_xxx page
	 * The plugin must check first if it is the correct type
	 *
	 * @author Valerie Isaksen
	 * @param VirtueMartCart cart: the cart object
	 * @return null if no plugin was found, 0 if more then one plugin was found,  virtuemart_xxx_id if only one plugin is found
	 *
	 */
	function plgVmOnCheckAutomaticSelectedShipment (VirtueMartCart $cart, array $cart_prices = array(), &$shipCounter) {
		if ($shipCounter > 1) {
			return 0;
		}
		return $this->onCheckAutomaticSelected ($cart, $cart_prices, $shipCounter);
	}

	/**
	 * This method is fired when showing when priting an Order
	 * It displays the the payment method-specific data.
	 *
	 * @param integer $_virtuemart_order_id The order ID
	 * @param integer $method_id  method used for this order
	 * @return mixed Null when for payment methods that were not selected, text (HTML) otherwise
	 * @author Valerie Isaksen
	 */
	function plgVmonShowOrderPrint ($order_number, $method_id) {
		return $this->onShowOrderPrint ($order_number, $method_id);
	}

	function plgVmDeclarePluginParamsShipment ($name, $id, &$data) {
		return $this->declarePluginParams ('shipment', $name, $id, $data);
	}

912
913
914
915
916
	/* This function is needed in VM 2.0.14 etc. because otherwise the params are not saved */
	function plgVmSetOnTablePluginParamsShipment ($name, $id, &$table) {

		return $this->setOnTablePluginParams ($name, $id, $table);
	}
917

918
919
920
921
	function plgVmDeclarePluginParamsShipmentVM3 (&$data) {
		return $this->declarePluginParams ('shipment', $data);
	}

922
923
924
925
926
927
928
	function plgVmSetOnTablePluginShipment(&$data,&$table){

		$name = $data['shipment_element'];
		$id = $data['shipment_jplugin_id'];

		if (!empty($this->_psType) and !$this->selectedThis ($this->_psType, $name, $id)) {
			return FALSE;
929
930
		}
		if (isset($data['rules1'])) {
931
932
			// Try to parse all rules (and spit out error) to inform the user. There is no other 
			// reason to parse the rules here, it's really only to trigger warnings/errors in case of a syntax error.
933
			$method = new StdClass ();
934
935
936
937
938
939
940
941
			$this->parseMethodRule ($data['rules1'], isset($data['countries1'])?$data['countries1']:array(), $data['tax_id1'], $method);
			$this->parseMethodRule ($data['rules2'], isset($data['countries2'])?$data['countries2']:array(), $data['tax_id2'], $method);
			$this->parseMethodRule ($data['rules3'], isset($data['countries3'])?$data['countries3']:array(), $data['tax_id3'], $method);
			$this->parseMethodRule ($data['rules4'], isset($data['countries4'])?$data['countries4']:array(), $data['tax_id4'], $method);
			$this->parseMethodRule ($data['rules5'], isset($data['countries5'])?$data['countries5']:array(), $data['tax_id5'], $method);
			$this->parseMethodRule ($data['rules6'], isset($data['countries6'])?$data['countries6']:array(), $data['tax_id6'], $method);
			$this->parseMethodRule ($data['rules7'], isset($data['countries7'])?$data['countries7']:array(), $data['tax_id7'], $method);
			$this->parseMethodRule ($data['rules8'], isset($data['countries8'])?$data['countries8']:array(), $data['tax_id8'], $method);
942
		}
943
944
		$ret=$this->setOnTablePluginParams ($name, $id, $table);
		return $ret;
945
946
947
948
	}

}

Reinhold Kainhofer's avatar
Reinhold Kainhofer committed
949
if (class_exists ('ShippingRule')) {
950
951
	return;
}
952

953
954
955
956
957
958
959
960
961
962
963
/** Filter the given array of products and return only those that belong to the categories, manufacturers, 
 *  vendors or products given in the $filter_conditions. The $filter_conditions is an array of the form:
 *     array( 'skus'=>array(....), 'categories'=>array(1,2,3,42), 'manufacturers'=>array(77,78,83), 'vendors'=>array(1,2))
 *  Notice that giving an empty array for any of the keys means "no restriction" and is exactly the same 
 *  as leaving out the enty altogether
 */
function filterProducts($products, $filter_conditions) {
	$result = array();
	foreach ($products as $p) {
		if (!empty($filter_conditions['skus']) && !in_array($p->product_sku, $filter_conditions['skus']))
			continue;
964
		if (!empty($filter_conditions['categories']) && count(array_intersect($filter_conditions['categories'], $p->categories))==0)
965
966
967
968
969
970
971
972
973
974
975
			continue;
		if (!empty($filter_conditions['manufacturers']) && count(array_intersect($filter_conditions['manufacturers'], $p->product_manufacturers))==0)
			continue;
		if (!empty($filter_conditions['vendors']) && count(array_intersect($filter_conditions['vendors'], $p->product_vendors))==0)
			continue;
		$result[] = $p;
	}
	return $result;
}
	

976
class ShippingRule {
977
	var $plugin = Null;
978
	var $rulestring = '';
979
980
981
982
983
984
985
986
	var $name = '';
	var $ruletype = '';
	var $evaluated = False;
	var $match = False;
	var $value = Null;
	
	var $shipping = 0;
	var $conditions = array();
987
988
989
990
	var $countries = array();
	var $tax_id = 0;
	var $includes_tax = 0;
	
991
	function __construct ($plugin, $rule, $countries, $tax_id) {
992
993
994
995
996
997
998
999
		if (is_array($countries)) {
			$this->countries = $countries;
		} elseif (!empty($countries)) {
			$this->countries[0] = $countries;
		}
		$this->tax_id = $tax_id;
		$this->rulestring = $rule;
		$this->parseRule($rule);
1000
		$this->plugin=$plugin;
For faster browsing, not all history is shown. View entire blame