Chapter 8 [ 203 ] To store these rules, we need to record: A name for the rule The shipping method the rule is associated with The order of the rule, so if more than one rule were applicable, they would be applied in order The type of match to perform, either against total product cost, or the shipping cost (product cost would allow us to offer free shipping for orders over $X, and against shipping costs allow us to cap the costs at $Y) The amount to match against The operator to compare the match amount against the product or basket cost (this would be an operator such as greater than, less than, less than or equal to, greater than or equal to, not equal to, or equal to) The rule amount; this would be a value that would be applied to the shipping cost by a rule operator The rule operator, to determine how the rule amount would be applied to the shipping cost (this would be an operator such as plus, minus, divide by, multiply by, or set value to) The following SQL represents this in our database: CREATE TABLE ` shipping_rules` ( `ID` int(11) NOT NULL auto_increment, `shipping_id` int(11) NOT NULL, `match_amount` float NOT NULL, `match_type` enum('shipping','products') NOT NULL, `match_operator` enum('<','>','<=','>=','<>','==') NOT NULL, `rule` varchar(255) NOT NULL, `rule_amount` float NOT NULL, `rule_operator` enum('+','-','=','*','/') NOT NULL, `order` int(11) NOT NULL, PRIMARY KEY (`ID`), KEY `shipping_id` (`shipping_id`,`order`) ) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ; Let's look at some example shipping rules, and potential values for these. • • • • • • • • This material is copyright and is licensed for the sole use by jackie tracey on 23rd February 2010 953 Quincy Drive, , Brick, , 08724 Shipping and Tax [ 204 ] Free shipping If we wished to offer free shipping to all customers whose orders were greater than or equal to $50, we would use the following values: Name: Free Shipping Order: 2 (assuming we use both this and the following rule)2 (assuming we use both this and the following rule)(assuming we use both this and the following rule) Type of match: Product Match amount: 50 Match comparison operator: Greater than or equal to Rule amount: 0 Rule operator: Set equal to Capped shipping If we wished to cap shipping costs to $20, to ensure no customer paid more than that, we would use the following values: Name: Max shipping cost Order: 1 Type of match: Shipping Match amount: 20 Match comparison operator: Greater than Rule amount: 20 Rule operator: Set equal to Of course we can also use these rules to do all sorts of calculations, such as discounted shipping for bulk orders, and so on. We could also extend these rules to take into account delivery locations. Tracking When products are shipped to customers, they may wish to be informed about tracking information. It may be possible for us to integrate with shipping provider APIs to do this. However, the simplest method (which could also eventually be integrated with such an API) is to allow store administrators to supply a message to the customer when they update an order's status to "dispatched"; this is something we will discuss in the Chapter 13, Administration. • • • • • • • • • • • • • • This material is copyright and is licensed for the sole use by jackie tracey on 23rd February 2010 953 Quincy Drive, , Brick, , 08724 Chapter 8 [ 205 ] Integrating shipping costs into the basket We should integrate these shipping cost systems into our framework in the following stages: 1. List of shipping methods and a default method. 2. Calculate product-based shipping costs. 3. Calculate weight-based shipping costs. 4. Consider shipping rules and adjust shipping costs accordingly. Shipping methods and a default We can store a default shipping method in the framework's settings. When a customer selects an alternative shipping method, we should store that in an appropriate session variable. At this stage, all we need to do is check if the session variable is set. If the session variable is set, then that is the shipping method we must use; if it is not, then we must use the default shipping method. // get the shipping method if( isset( $_SESSION['shipping_method'] ) ) { // user-selected $this->shippingMethodID = intval( $_SESSION['shipping_method'] ); } else { // system default $this->shippingMethodID = $this->registry-> getSetting('default_shipping_method'); } Calculating shipping costs based on products To calculate shipping costs based on products, we need to lookup the shipping cost for each product in the basket associated with the current shipping method. // shipping costs: product based $shippingCosts = $this->getShippingProductCosts( $this->productIDs ); This material is copyright and is licensed for the sole use by jackie tracey on 23rd February 2010 953 Quincy Drive, , Brick, , 08724 Download at Wow! eBook Shipping and Tax [ 206 ] Once we have these shipping costs, it is a case of looking up the product ID in the $shippingCosts array to get the shipping cost, and multiplying this by the quantity of the product in the basket. $this->shippingCost = $this->shippingCost + ( $shippingCosts[ $contents['product_id'] ] * $contents['product_quantity'] ); Calculating shipping costs based on product weights To calculate shipping costs based on product weight, we must build an array of shipping costs based on weight ranges. // shipping costs: weight based $weightCosts = $this->getShippingWeightCosts(); Once we have our array of shipping weight costs, while iterating through products in the basket, we then iterate through the ordered weights until we nd an upper limit to the product in question. Once found, we get our shipping cost. This cost is then multiplied by the quantity of the product in the basket, and added to the rolling shipping cost. // shipping costs: weight based $currentWeight = 0; while( $weightFound == false ) { if( $contents['product_weight'] >= $weightCosts[$currentWeight]['weight'] ) { $weightFound = true; $this->shippingCost = $this->shippingCost + ( $weightCosts[$currentWeight]['cost'] * $contents['product_quantity'] ); } else { if( count( $weightCosts ) == $currentWeight ) { // we don't want to do this forever! $weightFound = true; } else { $currentWeight++; } } } This material is copyright and is licensed for the sole use by jackie tracey on 23rd February 2010 953 Quincy Drive, , Brick, , 08724 Chapter 8 [ 207 ] Considering shipping rules, and adjusting prices accordingly The nal shipping feature is shipping rules; this requires us looking up the shipping rules from the database, and iterating through them. For each rule, we need to check the type of rule, then check if the shipping cost or the basket cost is at least that of the rule amount; if it is, then we perform our rule calculation. /** * Takes any shipping rules into account with regards to the shipping costs * @return void */ private function considerShippingRules() { // get the rules $rules_sql = "SELECT * FROM shipping_rules WHERE shipping_id={$this->shippingMethodUD} ORDER BY `order`"; $this->registry->getObject('db')->executeQuery( $rules_sql ); // go through them while( $rule = $this->registry->getObject('db')->getRows() ) { // rule depends on the shipping cost Here we have established that the current rule is based on shipping cost, which means we then check to see if the shipping cost meets the rule. if( $rule['match_type'] == 'shipping' ) { $match = false; $match_operator = $rule['match_operator']; // check to see our shipping cost meets the rule if( $match_operator == '==' ) { if( $this->shippingCost == $rule['match_amount'] ) { $match = true; } } elseif( $match_operator == '<>' ) { if( $this->shippingCost <> $rule['match_amount'] ) { $match = true; } } elseif( $match_operator == '>=' ) { if( $this->shippingCost >= $rule['match_amount'] ) { $match = true; } } elseif( $match_operator == '<=' ) { if( $this->shippingCost <= $rule['match_amount'] ) { $match = true; } } elseif( $match_operator == '>' ) This material is copyright and is licensed for the sole use by jackie tracey on 23rd February 2010 953 Quincy Drive, , Brick, , 08724 . enum('<','>','<=','>=','<>','==') NOT NULL, `rule` varchar( 255 ) NOT NULL, `rule_amount` float NOT NULL, `rule_operator` enum('+','-','=','*','/'). February 2010 953 Quincy Drive, , Brick, , 08724 Shipping and Tax [ 204 ] Free shipping If we wished to offer free shipping to all customers whose orders were greater than or equal to $50 , we would. and is licensed for the sole use by jackie tracey on 23rd February 2010 953 Quincy Drive, , Brick, , 08724 Chapter 8 [ 2 05 ] Integrating shipping costs into the basket We should integrate these