2011-08-09 15:16:18 +00:00
< ? php
/**
2011-08-10 17:11:11 +00:00
* WooCommerce cart
2011-08-09 15:16:18 +00:00
*
2011-08-10 17:11:11 +00:00
* The WooCommerce cart class stores cart data and active coupons as well as handling customer sessions and some cart related urls .
2011-08-09 15:16:18 +00:00
* The cart class also has a price calculation function which calls upon other classes to calcualte totals .
*
2011-08-10 17:11:11 +00:00
* @ class woocommerce_cart
* @ package WooCommerce
* @ category Class
* @ author WooThemes
2011-08-09 15:16:18 +00:00
*/
2011-08-10 17:11:11 +00:00
class woocommerce_cart {
2011-08-09 15:16:18 +00:00
2011-11-06 13:45:18 +00:00
/* Public Variables */
var $cart_contents ;
var $applied_coupons ;
2011-09-06 11:11:22 +00:00
var $cart_contents_total ;
var $cart_contents_weight ;
var $cart_contents_count ;
var $cart_contents_tax ;
2011-11-06 13:45:18 +00:00
2011-09-06 11:11:22 +00:00
var $total ;
var $subtotal ;
var $subtotal_ex_tax ;
var $tax_total ;
2011-12-28 23:59:33 +00:00
var $taxes ;
2011-11-25 19:31:06 +00:00
var $discount_cart ;
2011-09-06 11:11:22 +00:00
var $discount_total ;
var $shipping_total ;
var $shipping_tax_total ;
2011-08-09 15:16:18 +00:00
2011-11-19 20:59:16 +00:00
/* Private variables */
var $tax ;
2011-11-06 13:45:18 +00:00
/**
* Constructor
*/
2011-08-09 15:16:18 +00:00
function __construct () {
2011-11-19 20:59:16 +00:00
$this -> tax = & new woocommerce_tax ();
2011-11-22 13:18:33 +00:00
$this -> prices_include_tax = ( get_option ( 'woocommerce_prices_include_tax' ) == 'yes' ) ? true : false ;
2011-11-22 17:00:47 +00:00
$this -> display_totals_ex_tax = ( get_option ( 'woocommerce_display_totals_excluding_tax' ) == 'yes' ) ? true : false ;
2011-11-27 00:03:46 +00:00
$this -> display_cart_ex_tax = ( get_option ( 'woocommerce_display_cart_prices_excluding_tax' ) == 'yes' ) ? true : false ;
2011-11-19 20:59:16 +00:00
2011-11-02 20:32:35 +00:00
add_action ( 'init' , array ( & $this , 'init' ), 1 ); // Get cart on init
add_action ( 'wp' , array ( & $this , 'calculate_totals' ), 1 ); // Defer calculate totals so we can detect page
2011-08-09 15:16:18 +00:00
}
2011-11-06 13:45:18 +00:00
/**
* Loads the cart data from the session during WordPress init
*/
function init () {
2011-09-06 11:11:22 +00:00
$this -> applied_coupons = array ();
$this -> get_cart_from_session ();
if ( isset ( $_SESSION [ 'coupons' ]) ) $this -> applied_coupons = $_SESSION [ 'coupons' ];
2011-11-09 17:26:45 +00:00
add_action ( 'woocommerce_check_cart_items' , array ( & $this , 'check_cart_items' ), 1 );
2011-08-09 15:16:18 +00:00
}
2011-12-08 12:50:50 +00:00
/*-----------------------------------------------------------------------------------*/
/* Cart Session Handling */
/*-----------------------------------------------------------------------------------*/
2011-08-09 15:16:18 +00:00
2011-12-08 12:50:50 +00:00
/**
* Get the cart data from the PHP session
*/
function get_cart_from_session () {
if ( isset ( $_SESSION [ 'cart' ]) && is_array ( $_SESSION [ 'cart' ])) :
$cart = $_SESSION [ 'cart' ];
foreach ( $cart as $key => $values ) :
if ( $values [ 'variation_id' ] > 0 ) :
$_product = & new woocommerce_product_variation ( $values [ 'variation_id' ]);
else :
$_product = & new woocommerce_product ( $values [ 'product_id' ]);
endif ;
if ( $_product -> exists && $values [ 'quantity' ] > 0 ) :
// Put session data into array. Run through filter so other plugins can load their own session data
$this -> cart_contents [ $key ] = apply_filters ( 'woocommerce_get_cart_item_from_session' , array (
'product_id' => $values [ 'product_id' ],
'variation_id' => $values [ 'variation_id' ],
'variation' => $values [ 'variation' ],
'quantity' => $values [ 'quantity' ],
'data' => $_product
), $values );
endif ;
endforeach ;
else :
$this -> cart_contents = array ();
endif ;
if ( ! is_array ( $this -> cart_contents )) $this -> cart_contents = array ();
}
/**
* Sets the php session data for the cart and coupons
*/
function set_session () {
// Set cart and coupon session data
$_SESSION [ 'cart' ] = $this -> cart_contents ;
$_SESSION [ 'coupons' ] = $this -> applied_coupons ;
// Cart contents change so reset shipping
unset ( $_SESSION [ '_chosen_shipping_method' ]);
// Calculate totals
$this -> calculate_totals ();
}
/**
* Empty the cart data and destroy the session
*/
function empty_cart () {
$this -> cart_contents = array ();
2012-01-04 23:01:47 +00:00
$this -> reset ();
2011-12-08 12:50:50 +00:00
unset ( $_SESSION [ 'cart' ]);
unset ( $_SESSION [ 'coupons' ]);
}
/*-----------------------------------------------------------------------------------*/
/* Cart Data Functions */
/*-----------------------------------------------------------------------------------*/
2011-08-09 15:16:18 +00:00
2011-12-08 12:50:50 +00:00
/**
* Check cart items for errors
*/
function check_cart_items () {
global $woocommerce ;
$result = $this -> check_cart_item_stock ();
if ( is_wp_error ( $result )) $woocommerce -> add_error ( $result -> get_error_message () );
}
/**
* looks through the cart to check each item is in stock
*/
function check_cart_item_stock () {
$error = new WP_Error ();
foreach ( $this -> cart_contents as $cart_item_key => $values ) :
$_product = $values [ 'data' ];
if ( $_product -> managing_stock ()) :
if ( $_product -> is_in_stock () && $_product -> has_enough_stock ( $values [ 'quantity' ] )) :
// :)
else :
2012-01-05 11:31:22 +00:00
$error -> add ( 'out-of-stock' , sprintf ( __ ( 'Sorry, we do not have enough "%s" in stock to fulfill your order (%s in stock). Please edit your cart and try again. We apologise for any inconvenience caused.' , 'woocommerce' ), $_product -> get_title (), $_product -> stock ) );
2011-12-08 12:50:50 +00:00
return $error ;
endif ;
else :
if ( ! $_product -> is_in_stock ()) :
2012-01-05 11:31:22 +00:00
$error -> add ( 'out-of-stock' , sprintf ( __ ( 'Sorry, we do not have enough "%s" in stock to fulfill your order. Please edit your cart and try again. We apologise for any inconvenience caused.' , 'woocommerce' ), $_product -> get_title () ) );
2011-12-08 12:50:50 +00:00
return $error ;
endif ;
endif ;
endforeach ;
return true ;
}
/**
* Gets and formats a list of cart item data + variations for display on the frontend
*/
function get_item_data ( $cart_item , $flat = false ) {
global $woocommerce ;
2012-01-03 17:23:42 +00:00
$has_data = false ;
2011-12-08 12:50:50 +00:00
if ( ! $flat ) $return = '<dl class="variation">' ;
2011-08-09 15:16:18 +00:00
2011-12-08 12:50:50 +00:00
// Variation data
if ( $cart_item [ 'data' ] instanceof woocommerce_product_variation && is_array ( $cart_item [ 'variation' ])) :
2011-08-09 15:16:18 +00:00
2011-12-08 12:50:50 +00:00
$variation_list = array ();
foreach ( $cart_item [ 'variation' ] as $name => $value ) :
if ( ! $value ) continue ;
// If this is a term slug, get the term's nice name
if ( taxonomy_exists ( esc_attr ( str_replace ( 'attribute_' , '' , $name )))) :
$term = get_term_by ( 'slug' , $value , esc_attr ( str_replace ( 'attribute_' , '' , $name )));
if ( ! is_wp_error ( $term ) && $term -> name ) :
$value = $term -> name ;
endif ;
else :
$value = ucfirst ( $value );
endif ;
if ( $flat ) :
$variation_list [] = $woocommerce -> attribute_label ( str_replace ( 'attribute_' , '' , $name )) . ': ' . $value ;
else :
$variation_list [] = '<dt>' . $woocommerce -> attribute_label ( str_replace ( 'attribute_' , '' , $name )) . ':</dt><dd>' . $value . '</dd>' ;
endif ;
endforeach ;
if ( $flat ) :
$return .= implode ( ', ' , $variation_list );
2011-08-09 15:16:18 +00:00
else :
2011-12-08 12:50:50 +00:00
$return .= implode ( '' , $variation_list );
2011-08-09 15:16:18 +00:00
endif ;
2012-01-03 17:23:42 +00:00
$has_data = true ;
2011-12-08 12:50:50 +00:00
endif ;
// Other data - returned as array with name/value values
$other_data = apply_filters ( 'woocommerce_get_item_data' , array (), $cart_item );
if ( $other_data && is_array ( $other_data ) && sizeof ( $other_data ) > 0 ) :
$data_list = array ();
2011-08-09 15:16:18 +00:00
2011-12-08 12:50:50 +00:00
foreach ( $other_data as $data ) :
2011-11-06 13:45:18 +00:00
2011-12-08 12:50:50 +00:00
if ( $flat ) :
$data_list [] = $data [ 'name' ] . ': ' . $data [ 'value' ];
else :
$data_list [] = '<dt>' . $data [ 'name' ] . ':</dt><dd>' . $data [ 'value' ] . '</dd>' ;
endif ;
endforeach ;
if ( $flat ) :
$return .= implode ( ', ' , $data_list );
else :
$return .= implode ( '' , $data_list );
2011-08-09 15:16:18 +00:00
endif ;
2011-12-08 12:50:50 +00:00
2012-01-03 17:23:42 +00:00
$has_data = true ;
2011-12-08 12:50:50 +00:00
endif ;
2011-08-09 15:16:18 +00:00
2011-12-08 12:50:50 +00:00
if ( ! $flat ) $return .= '</dl>' ;
2012-01-03 17:23:42 +00:00
if ( $has_data ) return $return ;
2011-12-08 12:50:50 +00:00
}
2011-08-09 15:16:18 +00:00
2011-12-08 12:50:50 +00:00
/**
* Gets cross sells based on the items in the cart
*
* @ return array cross_sells item ids of cross sells
*/
function get_cross_sells () {
$cross_sells = array ();
$in_cart = array ();
if ( sizeof ( $this -> cart_contents ) > 0 ) : foreach ( $this -> cart_contents as $cart_item_key => $values ) :
if ( $values [ 'quantity' ] > 0 ) :
$cross_sells = array_merge ( $values [ 'data' ] -> get_cross_sells (), $cross_sells );
$in_cart [] = $values [ 'product_id' ];
endif ;
endforeach ; endif ;
$cross_sells = array_diff ( $cross_sells , $in_cart );
return $cross_sells ;
}
2011-11-06 13:45:18 +00:00
2011-12-08 12:50:50 +00:00
/** gets the url to the cart page */
function get_cart_url () {
2012-01-06 17:14:31 +00:00
$cart_page_id = woocommerce_get_page_id ( 'cart' );
if ( $cart_page_id ) return apply_filters ( 'woocommerce_get_cart_url' , get_permalink ( $cart_page_id ));
2011-12-08 12:50:50 +00:00
}
2011-11-06 13:45:18 +00:00
2011-12-08 12:50:50 +00:00
/** gets the url to the checkout page */
function get_checkout_url () {
2012-01-06 17:14:31 +00:00
$checkout_page_id = woocommerce_get_page_id ( 'checkout' );
2011-12-08 12:50:50 +00:00
if ( $checkout_page_id ) :
if ( is_ssl ()) return str_replace ( 'http:' , 'https:' , get_permalink ( $checkout_page_id ));
2012-01-06 17:14:31 +00:00
return apply_filters ( 'woocommerce_get_checkout_url' , get_permalink ( $checkout_page_id ));
2011-12-08 12:50:50 +00:00
endif ;
}
2011-08-09 15:16:18 +00:00
2011-12-08 12:50:50 +00:00
/** gets the url to remove an item from the cart */
function get_remove_url ( $cart_item_key ) {
global $woocommerce ;
2012-01-06 17:14:31 +00:00
$cart_page_id = woocommerce_get_page_id ( 'cart' );
if ( $cart_page_id ) return apply_filters ( 'woocommerce_get_remove_url' , $woocommerce -> nonce_url ( 'cart' , add_query_arg ( 'remove_item' , $cart_item_key , get_permalink ( $cart_page_id ))));
2011-12-08 12:50:50 +00:00
}
2011-08-27 20:07:16 +00:00
2011-12-08 12:50:50 +00:00
/**
* Returns the contents of the cart
*/
function get_cart () {
return $this -> cart_contents ;
}
/*-----------------------------------------------------------------------------------*/
/* Add to cart handling */
/*-----------------------------------------------------------------------------------*/
/**
* Check if product is in the cart and return cart item key
*
* Cart item key will be unique based on the item and its properties , such as variations
*/
function find_product_in_cart ( $cart_id = false ) {
if ( $cart_id !== false ) foreach ( $this -> cart_contents as $cart_item_key => $cart_item ) if ( $cart_item_key == $cart_id ) return $cart_item_key ;
}
2011-11-09 12:17:05 +00:00
2011-12-08 12:50:50 +00:00
/**
* Generate a unique ID for the cart item being added
*/
function generate_cart_id ( $product_id , $variation_id = '' , $variation = '' , $cart_item_data = '' ) {
$id_parts = array ( $product_id );
if ( $variation_id ) $id_parts [] = $variation_id ;
if ( is_array ( $variation )) :
$variation_key = '' ;
foreach ( $variation as $key => $value ) :
$variation_key .= trim ( $key ) . trim ( $value );
endforeach ;
$id_parts [] = $variation_key ;
endif ;
if ( is_array ( $cart_item_data )) :
$cart_item_data_key = '' ;
foreach ( $cart_item_data as $key => $value ) :
if ( is_array ( $value )) $value = http_build_query ( $value );
$cart_item_data_key .= trim ( $key ) . trim ( $value );
endforeach ;
$id_parts [] = $cart_item_data_key ;
endif ;
return md5 ( implode ( '_' , $id_parts ) );
}
2011-11-06 13:45:18 +00:00
2011-12-08 12:50:50 +00:00
/**
* Add a product to the cart
*
* @ param string product_id contains the id of the product to add to the cart
* @ param string quantity contains the quantity of the item to add
* @ param int variation_id
* @ param array variation attribute values
*/
function add_to_cart ( $product_id , $quantity = 1 , $variation_id = '' , $variation = '' ) {
global $woocommerce ;
2011-08-09 15:16:18 +00:00
2011-12-08 12:50:50 +00:00
if ( $quantity < 1 ) return false ;
2011-08-09 15:16:18 +00:00
2011-12-08 12:50:50 +00:00
// Load cart item data - may be added by other plugins
$cart_item_data = ( array ) apply_filters ( 'woocommerce_add_cart_item_data' , array (), $product_id );
2011-11-06 13:45:18 +00:00
2011-12-08 12:50:50 +00:00
// Generate a ID based on product ID, variation ID, variation data, and other cart item data
$cart_id = $this -> generate_cart_id ( $product_id , $variation_id , $variation , $cart_item_data );
2011-11-06 13:45:18 +00:00
2011-12-08 12:50:50 +00:00
// See if this product and its options is already in the cart
$cart_item_key = $this -> find_product_in_cart ( $cart_id );
if ( $variation_id > 0 ) :
$product_data = & new woocommerce_product_variation ( $variation_id );
else :
$product_data = & new woocommerce_product ( $product_id );
2011-11-06 13:45:18 +00:00
endif ;
2011-12-08 12:50:50 +00:00
// Type/Exists check
if ( $product_data -> is_type ( 'external' ) || ! $product_data -> exists () ) :
2012-01-05 11:31:22 +00:00
$woocommerce -> add_error ( __ ( 'This product cannot be purchased.' , 'woocommerce' ) );
2011-12-08 12:50:50 +00:00
return false ;
2011-11-06 13:45:18 +00:00
endif ;
2011-12-08 12:50:50 +00:00
// Price set check
if ( $product_data -> get_price () === '' ) :
2012-01-05 11:31:22 +00:00
$woocommerce -> add_error ( __ ( 'This product cannot be purchased - the price is not yet set.' , 'woocommerce' ) );
2011-12-08 12:50:50 +00:00
return false ;
endif ;
// Stock check - only check if we're managing stock and backorders are not allowed
if ( ! $product_data -> has_enough_stock ( $quantity ) ) :
2012-01-05 11:31:22 +00:00
$woocommerce -> add_error ( sprintf ( __ ( 'You cannot add that amount to the cart since there is not enough stock. We have %s in stock.' , 'woocommerce' ), $product_data -> get_stock_quantity () ));
2011-12-08 12:50:50 +00:00
return false ;
elseif ( ! $product_data -> is_in_stock () ) :
2012-01-05 11:31:22 +00:00
$woocommerce -> add_error ( __ ( 'You cannot add that product to the cart since the product is out of stock.' , 'woocommerce' ) );
2011-12-08 12:50:50 +00:00
return false ;
endif ;
if ( $cart_item_key ) :
$quantity = $quantity + $this -> cart_contents [ $cart_item_key ][ 'quantity' ];
// Stock check - this time accounting for whats already in-cart
if ( ! $product_data -> has_enough_stock ( $quantity ) ) :
2012-01-05 11:31:22 +00:00
$woocommerce -> add_error ( sprintf ( __ ( 'You cannot add that amount to the cart since there is not enough stock. We have %s in stock and you already have %s in your cart.' , 'woocommerce' ), $product_data -> get_stock_quantity (), $this -> cart_contents [ $cart_item_key ][ 'quantity' ] ));
2011-12-08 12:50:50 +00:00
return false ;
elseif ( ! $product_data -> is_in_stock () ) :
2012-01-05 11:31:22 +00:00
$woocommerce -> add_error ( __ ( 'You cannot add that product to the cart since the product is out of stock.' , 'woocommerce' ) );
2011-12-08 12:50:50 +00:00
return false ;
2011-11-06 13:45:18 +00:00
endif ;
2011-12-08 12:50:50 +00:00
2011-12-15 00:06:01 +00:00
$this -> set_quantity ( $cart_item_key , $quantity );
2011-12-08 12:50:50 +00:00
else :
// Add item after merging with $cart_item_data - hook to allow plugins to modify cart item
$this -> cart_contents [ $cart_id ] = apply_filters ( 'woocommerce_add_cart_item' , array_merge ( $cart_item_data , array (
'product_id' => $product_id ,
'variation_id' => $variation_id ,
'variation' => $variation ,
'quantity' => $quantity ,
'data' => $product_data
)));
2011-11-06 13:45:18 +00:00
2011-12-08 12:50:50 +00:00
endif ;
2011-11-06 13:45:18 +00:00
$this -> set_session ();
2011-12-08 12:50:50 +00:00
2011-11-06 13:45:18 +00:00
return true ;
2011-12-08 12:50:50 +00:00
}
2011-08-09 15:16:18 +00:00
2011-12-08 12:50:50 +00:00
/**
* Set the quantity for an item in the cart
*
* @ param string cart_item_key contains the id of the cart item
* @ param string quantity contains the quantity of the item
*/
function set_quantity ( $cart_item_key , $quantity = 1 ) {
2012-01-02 00:49:00 +00:00
2011-12-08 12:50:50 +00:00
if ( $quantity == 0 || $quantity < 0 ) :
unset ( $this -> cart_contents [ $cart_item_key ]);
else :
$this -> cart_contents [ $cart_item_key ][ 'quantity' ] = $quantity ;
2012-01-02 00:49:00 +00:00
do_action ( 'woocommerce_after_cart_item_quantity_update' , $this -> cart_contents [ $cart_item_key ], $quantity );
2011-12-08 12:50:50 +00:00
endif ;
2012-01-02 00:49:00 +00:00
2011-12-08 12:50:50 +00:00
$this -> set_session ();
}
2011-11-23 23:19:23 +00:00
2011-12-08 12:50:50 +00:00
/*-----------------------------------------------------------------------------------*/
/* Cart Calculation Functions */
/*-----------------------------------------------------------------------------------*/
/**
* Reset totals
*/
2012-01-04 23:01:47 +00:00
private function reset () {
2011-12-08 12:50:50 +00:00
$this -> total = 0 ;
$this -> cart_contents_total = 0 ;
$this -> cart_contents_weight = 0 ;
$this -> cart_contents_count = 0 ;
$this -> cart_contents_tax = 0 ;
$this -> tax_total = 0 ;
$this -> shipping_tax_total = 0 ;
$this -> subtotal = 0 ;
$this -> subtotal_ex_tax = 0 ;
$this -> discount_total = 0 ;
$this -> discount_cart = 0 ;
$this -> shipping_total = 0 ;
2011-12-30 21:11:18 +00:00
$this -> taxes = array ();
2011-12-08 12:50:50 +00:00
}
/**
* Function to apply discounts to a product and get the discounted price ( before tax is applied )
*/
function get_discounted_price ( $values , $price , $add_totals = false ) {
if ( $this -> applied_coupons ) foreach ( $this -> applied_coupons as $code ) :
$coupon = & new woocommerce_coupon ( $code );
2011-08-09 15:16:18 +00:00
2011-12-08 12:50:50 +00:00
if ( $coupon -> apply_before_tax () && $coupon -> is_valid () ) :
switch ( $coupon -> type ) :
case " fixed_product " :
case " percent_product " :
$this_item_is_discounted = false ;
2011-08-09 15:16:18 +00:00
2011-12-08 12:50:50 +00:00
// Specific product ID's get the discount
if ( sizeof ( $coupon -> product_ids ) > 0 ) :
if (( in_array ( $values [ 'product_id' ], $coupon -> product_ids ) || in_array ( $values [ 'variation_id' ], $coupon -> product_ids ))) :
$this_item_is_discounted = true ;
endif ;
2011-08-09 15:16:18 +00:00
2011-12-08 12:50:50 +00:00
else :
// No product ids - all items discounted
2011-11-19 20:59:16 +00:00
$this_item_is_discounted = true ;
2011-10-08 10:39:26 +00:00
2011-11-19 20:59:16 +00:00
endif ;
2011-12-08 12:50:50 +00:00
// Specific product ID's excluded from the discount
if ( sizeof ( $coupon -> exclude_product_ids ) > 0 ) :
2011-11-23 23:19:23 +00:00
2011-12-08 12:50:50 +00:00
if (( in_array ( $values [ 'product_id' ], $coupon -> exclude_product_ids ) || in_array ( $values [ 'variation_id' ], $coupon -> exclude_product_ids ))) :
$this_item_is_discounted = false ;
2011-11-25 19:31:06 +00:00
endif ;
2011-11-23 23:19:23 +00:00
2011-12-08 12:50:50 +00:00
endif ;
2011-10-08 10:39:26 +00:00
2011-12-08 12:50:50 +00:00
// Apply filter
$this_item_is_discounted = apply_filters ( 'woocommerce_item_is_discounted' , $this_item_is_discounted , $values , $before_tax = true );
// Apply the discount
if ( $this_item_is_discounted ) :
if ( $coupon -> type == 'fixed_product' ) :
if ( $price < $coupon -> amount ) :
$discount_amount = $price ;
else :
$discount_amount = $coupon -> amount ;
endif ;
$price = $price - $coupon -> amount ;
if ( $price < 0 ) $price = 0 ;
if ( $add_totals ) :
$this -> discount_cart = $this -> discount_cart + ( $discount_amount * $values [ 'quantity' ] );
endif ;
elseif ( $coupon -> type == 'percent_product' ) :
2011-11-19 20:59:16 +00:00
2011-12-08 12:50:50 +00:00
$percent_discount = ( $values [ 'data' ] -> get_price_excluding_tax ( false ) / 100 ) * $coupon -> amount ;
if ( $add_totals ) $this -> discount_cart = $this -> discount_cart + ( $percent_discount * $values [ 'quantity' ] );
$price = $price - $percent_discount ;
endif ;
2011-11-19 20:59:16 +00:00
endif ;
2011-12-08 12:50:50 +00:00
break ;
2011-11-23 23:19:23 +00:00
2011-12-08 12:50:50 +00:00
case " fixed_cart " :
/**
* This is the most complex discount - we need to divide the discount between rows based on their price in
* proportion to the subtotal . This is so rows with different tax rates get a fair discount , and so rows
* with no price ( free ) don ' t get discount too .
*/
// Get item discount by dividing item cost by subtotal to get a %
$discount_percent = ( $values [ 'data' ] -> get_price_excluding_tax ( false ) * $values [ 'quantity' ]) / $this -> subtotal_ex_tax ;
// Use pence to help prevent rounding errors
$coupon_amount_pence = $coupon -> amount * 100 ;
// Work out the discount for the row
$item_discount = $coupon_amount_pence * $discount_percent ;
// Work out discount per item
$item_discount = $item_discount / $values [ 'quantity' ];
// Pence
$price = ( $price * 100 );
// Check if discount is more than price
if ( $price < $item_discount ) :
$discount_amount = $price ;
else :
$discount_amount = $item_discount ;
endif ;
// Take discount off of price (in pence)
$price = $price - $discount_amount ;
// Back to pounds
$price = $price / 100 ;
// Cannot be below 0
if ( $price < 0 ) $price = 0 ;
// Add coupon to discount total (once, since this is a fixed cart discount and we don't want rounding issues)
if ( $add_totals ) $this -> discount_cart = $this -> discount_cart + (( $discount_amount * $values [ 'quantity' ]) / 100 );
break ;
2011-11-19 20:59:16 +00:00
2011-12-08 12:50:50 +00:00
case " percent " :
2011-11-23 23:19:23 +00:00
2011-12-08 12:50:50 +00:00
$percent_discount = ( $values [ 'data' ] -> get_price ( ) / 100 ) * $coupon -> amount ;
if ( $add_totals ) $this -> discount_cart = $this -> discount_cart + ( $percent_discount * $values [ 'quantity' ] );
$price = $price - $percent_discount ;
break ;
2011-11-23 23:19:23 +00:00
2011-12-08 12:50:50 +00:00
endswitch ;
endif ;
endforeach ;
return apply_filters ( 'woocommerce_get_discounted_price_' , $price , $values , $this );
}
/**
* Function to apply product discounts after tax
*/
function apply_product_discounts_after_tax ( $values , $price ) {
if ( $this -> applied_coupons ) foreach ( $this -> applied_coupons as $code ) :
$coupon = & new woocommerce_coupon ( $code );
do_action ( 'woocommerce_product_discount_after_tax_' . $coupon -> type , $coupon );
if ( $coupon -> type != 'fixed_product' && $coupon -> type != 'percent_product' ) continue ;
if ( ! $coupon -> apply_before_tax () && $coupon -> is_valid () ) :
$this_item_is_discounted = false ;
// Specific product ID's get the discount
if ( sizeof ( $coupon -> product_ids ) > 0 ) :
2011-11-23 23:19:23 +00:00
2011-12-08 12:50:50 +00:00
if (( in_array ( $values [ 'product_id' ], $coupon -> product_ids ) || in_array ( $values [ 'variation_id' ], $coupon -> product_ids ))) :
$this_item_is_discounted = true ;
2011-11-23 23:19:23 +00:00
endif ;
2011-12-08 12:50:50 +00:00
else :
2011-11-19 20:59:16 +00:00
2011-12-08 12:50:50 +00:00
// No product ids - all items discounted
$this_item_is_discounted = true ;
endif ;
// Specific product ID's excluded from the discount
if ( sizeof ( $coupon -> exclude_product_ids ) > 0 ) :
2011-11-19 20:59:16 +00:00
2011-12-08 12:50:50 +00:00
if (( in_array ( $values [ 'product_id' ], $coupon -> exclude_product_ids ) || in_array ( $values [ 'variation_id' ], $coupon -> exclude_product_ids ))) :
$this_item_is_discounted = false ;
endif ;
2011-11-23 23:19:23 +00:00
2011-12-08 12:50:50 +00:00
endif ;
2011-11-01 16:25:54 +00:00
2011-12-08 12:50:50 +00:00
// Apply filter
$this_item_is_discounted = apply_filters ( 'woocommerce_item_is_discounted' , $this_item_is_discounted , $values , $before_tax = false );
2011-11-15 22:20:59 +00:00
2011-12-08 12:50:50 +00:00
// Apply the discount
if ( $this_item_is_discounted ) :
if ( $coupon -> type == 'fixed_product' ) :
2011-12-05 15:41:13 +00:00
2011-12-08 12:50:50 +00:00
if ( $price < $coupon -> amount ) :
$discount_amount = $price ;
else :
$discount_amount = $coupon -> amount ;
endif ;
$this -> discount_total = $this -> discount_total + ( $discount_amount * $values [ 'quantity' ] );
elseif ( $coupon -> type == 'percent_product' ) :
$this -> discount_total = $this -> discount_total + ( $price / 100 ) * $coupon -> amount ;
endif ;
endif ;
2011-11-01 16:25:54 +00:00
2011-12-08 12:50:50 +00:00
endif ;
endforeach ;
}
2011-11-19 20:59:16 +00:00
2011-12-08 12:50:50 +00:00
/**
* Function to apply cart discounts after tax
*/
function apply_cart_discounts_after_tax () {
2011-11-19 20:59:16 +00:00
2011-12-08 12:50:50 +00:00
if ( $this -> applied_coupons ) foreach ( $this -> applied_coupons as $code ) :
$coupon = & new woocommerce_coupon ( $code );
2011-11-20 00:55:23 +00:00
2011-12-08 12:50:50 +00:00
do_action ( 'woocommerce_cart_discount_after_tax_' . $coupon -> type , $coupon );
2011-11-20 00:55:23 +00:00
2011-12-08 12:50:50 +00:00
if ( ! $coupon -> apply_before_tax () && $coupon -> is_valid () ) :
2011-11-20 00:55:23 +00:00
2011-12-08 12:50:50 +00:00
switch ( $coupon -> type ) :
2011-11-23 23:19:23 +00:00
2011-12-08 12:50:50 +00:00
case " fixed_cart " :
$this -> discount_total = $this -> discount_total + $coupon -> amount ;
break ;
2011-11-23 23:19:23 +00:00
2011-12-08 12:50:50 +00:00
case " percent " :
$percent_discount = ( round ( $this -> cart_contents_total + $this -> tax_total , 2 ) / 100 ) * $coupon -> amount ;
$this -> discount_total = $this -> discount_total + $percent_discount ;
break ;
endswitch ;
2011-11-19 20:59:16 +00:00
2011-12-08 12:50:50 +00:00
endif ;
endforeach ;
}
2011-11-02 20:32:35 +00:00
2011-12-08 12:50:50 +00:00
/**
* calculate totals for the items in the cart
*/
function calculate_totals () {
global $woocommerce ;
2011-11-19 20:59:16 +00:00
2012-01-04 23:01:47 +00:00
$this -> reset ();
2011-12-14 19:02:41 +00:00
do_action ( 'woocommerce_before_calculate_totals' , $this );
2011-12-08 12:50:50 +00:00
// Get count of all items + weights + subtotal (we may need this for discounts)
if ( sizeof ( $this -> cart_contents ) > 0 ) foreach ( $this -> cart_contents as $cart_item_key => $values ) :
2011-10-28 15:04:39 +00:00
2011-12-08 12:50:50 +00:00
$_product = $values [ 'data' ];
2011-11-19 20:59:16 +00:00
2011-12-08 12:50:50 +00:00
$this -> cart_contents_weight = $this -> cart_contents_weight + ( $_product -> get_weight () * $values [ 'quantity' ]);
$this -> cart_contents_count = $this -> cart_contents_count + $values [ 'quantity' ];
// Base Price (inlusive of tax for now)
2012-01-04 23:01:47 +00:00
$row_base_price = $_product -> get_price () * $values [ 'quantity' ];
2011-12-28 23:59:33 +00:00
$base_tax_rates = $this -> tax -> get_shop_base_rate ( $_product -> tax_class );
2011-12-08 12:50:50 +00:00
$tax_amount = 0 ;
if ( $this -> prices_include_tax ) :
2011-10-28 15:04:39 +00:00
2011-12-28 23:59:33 +00:00
if ( $_product -> is_taxable () ) :
2011-12-08 12:50:50 +00:00
2011-12-28 23:59:33 +00:00
$tax_rates = $this -> tax -> get_rates ( $_product -> get_tax_class () );
2011-11-19 20:59:16 +00:00
2011-12-08 12:50:50 +00:00
// ADJUST BASE if tax rate is different (different region or modified tax class)
2011-12-28 23:59:33 +00:00
if ( $tax_rates !== $base_tax_rates ) :
2012-01-04 23:01:47 +00:00
$base_taxes = $this -> tax -> calc_tax ( $row_base_price , $base_tax_rates , true );
$modded_taxes = $this -> tax -> calc_tax ( $row_base_price - array_sum ( $base_taxes ), $tax_rates , false );
$row_base_price = ( $row_base_price - array_sum ( $base_taxes )) + array_sum ( $modded_taxes );
2011-12-08 12:50:50 +00:00
endif ;
2011-11-19 20:59:16 +00:00
2012-01-04 23:01:47 +00:00
$taxes = $this -> tax -> calc_tax ( $row_base_price , $tax_rates , true );
2012-01-04 16:24:26 +00:00
$tax_amount = $this -> tax -> get_tax_total ( $taxes );
2011-12-08 12:50:50 +00:00
endif ;
2011-11-19 20:59:16 +00:00
2011-12-08 12:50:50 +00:00
// Sub total is based on base prices (without discounts)
2012-01-04 23:01:47 +00:00
$this -> subtotal = $this -> subtotal + $row_base_price ;
2012-01-02 15:25:07 +00:00
2012-01-04 23:01:47 +00:00
$this -> subtotal_ex_tax = $this -> subtotal_ex_tax + ( $row_base_price - $tax_amount );
2011-12-08 12:50:50 +00:00
else :
2011-11-23 23:19:23 +00:00
2011-12-28 23:59:33 +00:00
if ( $_product -> is_taxable () ) :
2011-11-26 16:15:25 +00:00
2011-12-28 23:59:33 +00:00
$tax_rates = $this -> tax -> get_rates ( $_product -> get_tax_class () );
2012-01-04 23:01:47 +00:00
$taxes = $this -> tax -> calc_tax ( $row_base_price , $tax_rates , false );
2012-01-04 16:24:26 +00:00
$tax_amount = $this -> tax -> get_tax_total ( $taxes );
2011-11-26 16:15:25 +00:00
endif ;
2011-12-08 12:50:50 +00:00
// Sub total is based on base prices (without discounts)
2012-01-04 23:01:47 +00:00
$this -> subtotal = $this -> subtotal + $row_base_price + $tax_amount ;
$this -> subtotal_ex_tax = $this -> subtotal_ex_tax + $row_base_price ;
2011-11-23 23:19:23 +00:00
endif ;
2011-12-08 12:50:50 +00:00
endforeach ;
2011-11-23 23:19:23 +00:00
2011-12-08 12:50:50 +00:00
// Now calc the main totals, including discounts
if ( $this -> prices_include_tax ) :
2011-11-23 23:19:23 +00:00
2011-11-21 11:33:46 +00:00
/**
2011-12-08 12:50:50 +00:00
* Calculate totals for items
2011-11-21 11:33:46 +00:00
*/
2011-12-08 12:50:50 +00:00
if ( sizeof ( $this -> cart_contents ) > 0 ) : foreach ( $this -> cart_contents as $cart_item_key => $values ) :
2011-11-21 16:26:06 +00:00
2011-12-08 12:50:50 +00:00
/**
* Prices include tax
*
* To prevent rounding issues we need to work with the inclusive price where possible
* otherwise we ' ll see errors such as when working with a 9.99 inc price , 20 % VAT which would
* be 8.325 leading to totals being 1 p off
*
* Pre tax coupons come off the price the customer thinks they are paying - tax is calculated
* afterwards .
*
* e . g . $ 100 bike with $ 10 coupon = customer pays $ 90 and tax worked backwards from that
*
* Used this excellent article for reference :
* http :// developer . practicalecommerce . com / articles / 1473 - Coding - for - Tax - Calculations - Everything - You - Never - Wanted - to - Know - Part - 2
2011-11-21 11:33:46 +00:00
*/
2011-12-08 12:50:50 +00:00
$_product = $values [ 'data' ];
2011-11-21 11:33:46 +00:00
2011-12-08 12:50:50 +00:00
// Base Price (inlusive of tax for now)
$base_price = $_product -> get_price ();
// Base Price Adjustment
2011-12-28 23:59:33 +00:00
if ( $_product -> is_taxable () ) :
2011-11-21 11:33:46 +00:00
2011-12-28 23:59:33 +00:00
// Get rates
$tax_rates = $this -> tax -> get_rates ( $_product -> get_tax_class () );
2012-01-04 23:01:47 +00:00
2011-12-08 12:50:50 +00:00
/**
* ADJUST TAX - Checkout calculations when customer is OUTSIDE the shop base country and prices INCLUDE tax
* OR
* ADJUST TAX - Checkout calculations when a tax class is modified
*/
if ( ( $woocommerce -> customer -> is_customer_outside_base () && defined ( 'WOOCOMMERCE_CHECKOUT' ) && WOOCOMMERCE_CHECKOUT ) || ( $_product -> get_tax_class () !== $_product -> tax_class ) ) :
2012-01-04 23:01:47 +00:00
// Get tax rate for the store base, ensuring we use the unmodified tax_class for the product
$base_tax_rates = $this -> tax -> get_shop_base_rate ( $_product -> tax_class );
2011-12-08 12:50:50 +00:00
// Work out new price based on region
2012-01-04 23:01:47 +00:00
$row_base_price = $base_price * $values [ 'quantity' ];
$base_taxes = $this -> tax -> calc_tax ( $row_base_price , $base_tax_rates , true );
$modded_taxes = $this -> tax -> calc_tax ( $row_base_price - array_sum ( $base_taxes ), $tax_rates , false );
$adjusted_price = ( $row_base_price - array_sum ( $base_taxes ) + array_sum ( $modded_taxes )) / $values [ 'quantity' ];
// Calc base tax (for a single unit) - we will store this in the order data
$base_tax = array_sum ( $modded_taxes ) / $values [ 'quantity' ];
2011-12-08 12:50:50 +00:00
// Apply discounts
$discounted_price = $this -> get_discounted_price ( $values , $adjusted_price , true );
2011-12-28 23:59:33 +00:00
$discounted_taxes = $this -> tax -> calc_tax ( $discounted_price * $values [ 'quantity' ], $tax_rates , true );
2012-01-04 16:24:26 +00:00
$discounted_tax_amount = $this -> tax -> get_tax_total ( $discounted_taxes ); // Sum taxes - round also to prevent rounding errors
2011-12-28 23:59:33 +00:00
2011-12-08 12:50:50 +00:00
/**
* Regular tax calculation ( customer inside base and the tax class is unmodified
*/
else :
2012-01-04 23:01:47 +00:00
// Calc base tax (for a single unit) - we will store this in the order data
$base_tax = array_sum ( $this -> tax -> calc_tax ( $base_price , $tax_rates , true ));
// Calc prices and tax (discounted)
2011-12-08 12:50:50 +00:00
$discounted_price = $this -> get_discounted_price ( $values , $base_price , true );
2011-12-28 23:59:33 +00:00
$discounted_taxes = $this -> tax -> calc_tax ( $discounted_price * $values [ 'quantity' ], $tax_rates , true );
2012-01-04 16:24:26 +00:00
$discounted_tax_amount = $this -> tax -> get_tax_total ( $discounted_taxes ); // Sum taxes - round also to prevent rounding errors
2011-12-08 12:50:50 +00:00
endif ;
2011-12-30 21:11:18 +00:00
// Tax rows - merge the totals we just got
foreach ( array_keys ( $this -> taxes + $discounted_taxes ) as $key ) {
$this -> taxes [ $key ] = ( isset ( $discounted_taxes [ $key ]) ? $discounted_taxes [ $key ] : 0 ) + ( isset ( $this -> taxes [ $key ]) ? $this -> taxes [ $key ] : 0 );
}
2011-12-28 23:59:33 +00:00
2011-11-25 22:13:01 +00:00
else :
2011-12-08 12:50:50 +00:00
// Discounted Price (price with any pre-tax discounts applied)
2011-11-25 22:13:01 +00:00
$discounted_price = $this -> get_discounted_price ( $values , $base_price , true );
2011-12-08 12:50:50 +00:00
$discounted_tax_amount = 0 ;
2012-01-04 23:01:47 +00:00
$base_tax = 0 ;
2011-11-21 11:33:46 +00:00
2011-12-08 12:50:50 +00:00
endif ;
2012-01-02 00:49:00 +00:00
2012-01-04 23:01:47 +00:00
// Lines prices - round tax so price is correctly calculated
$line_tax = round ( $discounted_tax_amount , 2 );
$line_cost = ( $discounted_price * $values [ 'quantity' ]) - $line_tax ;
2011-12-08 12:50:50 +00:00
// Add any product discounts (after tax)
2012-01-04 23:01:47 +00:00
$this -> apply_product_discounts_after_tax ( $values , $line_cost + $discounted_tax_amount );
2011-12-08 12:50:50 +00:00
// Cart contents total is based on discounted prices and is used for the final total calculation
2012-01-04 23:01:47 +00:00
$this -> cart_contents_total = $this -> cart_contents_total + $line_cost ;
// Store unit/line cost + tax
$this -> cart_contents [ $cart_item_key ][ 'line_cost' ] = $line_cost ;
$this -> cart_contents [ $cart_item_key ][ 'line_tax' ] = $line_tax ;
$this -> cart_contents [ $cart_item_key ][ 'base_cost' ] = $_product -> get_price_excluding_tax ( false );
$this -> cart_contents [ $cart_item_key ][ 'base_tax' ] = $base_tax ;
2011-12-08 12:50:50 +00:00
endforeach ; endif ;
2011-11-19 20:59:16 +00:00
2011-12-08 12:50:50 +00:00
else :
if ( sizeof ( $this -> cart_contents ) > 0 ) : foreach ( $this -> cart_contents as $cart_item_key => $values ) :
/**
* Prices exclude tax
*
* This calculation is simpler - work with the base , untaxed price .
*/
$_product = $values [ 'data' ];
2011-11-21 11:33:46 +00:00
2011-12-08 12:50:50 +00:00
// Base Price (i.e. no tax, regardless of region)
2011-12-28 23:59:33 +00:00
$base_price = $_product -> get_price ();
2011-12-29 01:18:59 +00:00
2011-12-08 12:50:50 +00:00
// Discounted Price (base price with any pre-tax discounts applied
$discounted_price = $this -> get_discounted_price ( $values , $base_price , true );
// Tax Amount (For the line, based on discounted, ex.tax price)
2011-12-28 23:59:33 +00:00
if ( $_product -> is_taxable () ) :
2011-12-08 12:50:50 +00:00
2012-01-04 23:01:47 +00:00
// Get tax rates
$tax_rates = $this -> tax -> get_rates ( $_product -> get_tax_class () );
// Calc base tax (for a single unit) - we will store this in the order data
$base_tax = array_sum ( $this -> tax -> calc_tax ( $base_price , $tax_rates , false ));
// Now calc product rates
2011-12-28 23:59:33 +00:00
$discounted_taxes = $this -> tax -> calc_tax ( $discounted_price * $values [ 'quantity' ], $tax_rates , false );
2011-12-30 19:36:44 +00:00
$discounted_tax_amount = array_sum ( $discounted_taxes );
2011-12-30 21:11:18 +00:00
// Tax rows - merge the totals we just got
foreach ( array_keys ( $this -> taxes + $discounted_taxes ) as $key ) {
$this -> taxes [ $key ] = ( isset ( $discounted_taxes [ $key ]) ? $discounted_taxes [ $key ] : 0 ) + ( isset ( $this -> taxes [ $key ]) ? $this -> taxes [ $key ] : 0 );
}
2011-12-08 12:50:50 +00:00
else :
2012-01-04 23:01:47 +00:00
$discounted_tax_amount = 0 ;
$base_tax = 0 ;
2011-11-21 11:33:46 +00:00
endif ;
2012-01-04 23:01:47 +00:00
// Lines prices
$line_tax = $discounted_tax_amount ;
$line_cost = $discounted_price * $values [ 'quantity' ];
2011-12-08 12:50:50 +00:00
// Add any product discounts (after tax)
2012-01-04 23:01:47 +00:00
$this -> apply_product_discounts_after_tax ( $values , $line_cost + $line_tax );
2011-12-08 12:50:50 +00:00
// Cart contents total is based on discounted prices and is used for the final total calculation
2012-01-04 23:01:47 +00:00
$this -> cart_contents_total = $this -> cart_contents_total + $line_cost ;
// Store unit, line cost + tax
$this -> cart_contents [ $cart_item_key ][ 'line_cost' ] = $line_cost ;
$this -> cart_contents [ $cart_item_key ][ 'line_tax' ] = $line_tax ;
$this -> cart_contents [ $cart_item_key ][ 'base_cost' ] = $_product -> get_price ();
$this -> cart_contents [ $cart_item_key ][ 'base_tax' ] = $base_tax ;
2011-12-08 12:50:50 +00:00
endforeach ; endif ;
2011-11-19 20:59:16 +00:00
2011-12-08 12:50:50 +00:00
endif ;
2011-11-19 20:59:16 +00:00
2012-01-02 00:49:00 +00:00
// Set tax total to sum of all tax rows
if ( get_option ( 'woocommerce_tax_round_at_subtotal' ) == 'yes' ) :
2012-01-04 16:24:26 +00:00
$this -> tax_total = $this -> tax -> get_tax_total ( $this -> taxes );
2012-01-02 00:49:00 +00:00
else :
$this -> tax_total = array_sum ( $this -> taxes );
endif ;
2011-09-14 14:55:03 +00:00
2011-12-08 12:50:50 +00:00
// Cart Discounts (after tax)
$this -> apply_cart_discounts_after_tax ();
// Only go beyond this point if on the cart/checkout
if ( ! is_checkout () && ! is_cart () && ! defined ( 'WOOCOMMERCE_CHECKOUT' ) && ! is_ajax ()) return ;
// Cart Shipping
$this -> calculate_shipping ();
2012-01-02 00:49:00 +00:00
// Taxes Rounding - taxes now include shipping taxes
2012-01-04 16:24:26 +00:00
$this -> taxes = $this -> tax -> get_taxes_rounded ( $this -> taxes );
2011-12-08 12:50:50 +00:00
// VAT exemption done at this point - so all totals are correct before exemption
if ( $woocommerce -> customer -> is_vat_exempt ()) :
$this -> shipping_tax_total = $this -> tax_total = 0 ;
2011-12-30 21:11:18 +00:00
$this -> taxes = array ();
2011-12-08 12:50:50 +00:00
endif ;
// Allow plugins to hook and alter totals before final total is calculated
do_action ( 'woocommerce_calculate_totals' , $this );
/**
* Grand Total
*
* Based on discounted product prices , discounted tax , shipping cost + tax , and any discounts to be added after tax ( e . g . store credit )
*/
2011-12-23 16:30:46 +00:00
$this -> total = number_format ( $this -> cart_contents_total + $this -> tax_total + $this -> shipping_tax_total + $this -> shipping_total - $this -> discount_total , 2 , '.' , '' );
2011-12-08 12:50:50 +00:00
if ( $this -> total < 0 ) $this -> total = 0 ;
}
2011-11-19 20:59:16 +00:00
/**
2011-12-08 12:50:50 +00:00
* looks at the totals to see if payment is actually required
2011-11-19 20:59:16 +00:00
*/
2011-12-08 12:50:50 +00:00
function needs_payment () {
if ( $this -> total > 0 ) return true ; else return false ;
}
2011-11-06 13:45:18 +00:00
2011-12-08 12:50:50 +00:00
/*-----------------------------------------------------------------------------------*/
/* Shipping related functions */
/*-----------------------------------------------------------------------------------*/
/**
* Use the shipping class to calculate shipping
*/
function calculate_shipping () {
global $woocommerce ;
if ( $this -> needs_shipping ()) :
$woocommerce -> shipping -> calculate_shipping ();
else :
$woocommerce -> shipping -> reset_shipping ();
endif ;
$this -> shipping_total = $woocommerce -> shipping -> shipping_total ; // Shipping Total
$this -> shipping_label = $woocommerce -> shipping -> shipping_label ; // Shipping Label
2012-01-03 19:07:32 +00:00
$this -> shipping_tax_total = array_sum ( $woocommerce -> shipping -> shipping_taxes ); // Shipping tax amount
2011-12-30 19:36:44 +00:00
2012-01-03 19:07:32 +00:00
// Merge Shipping tax rows with cart tax rows
2012-01-02 00:49:00 +00:00
if ( is_array ( $woocommerce -> shipping -> shipping_taxes ) && sizeof ( $woocommerce -> shipping -> shipping_taxes ) > 0 ) :
2011-12-30 21:11:18 +00:00
// Tax rows - merge the totals we just got
2012-01-02 00:49:00 +00:00
foreach ( array_keys ( $this -> taxes + $woocommerce -> shipping -> shipping_taxes ) as $key ) {
$this -> taxes [ $key ] = ( isset ( $woocommerce -> shipping -> shipping_taxes [ $key ]) ? $woocommerce -> shipping -> shipping_taxes [ $key ] : 0 ) + ( isset ( $this -> taxes [ $key ]) ? $this -> taxes [ $key ] : 0 );
2011-12-30 21:11:18 +00:00
}
endif ;
2011-12-08 12:50:50 +00:00
}
2011-11-06 13:45:18 +00:00
2011-12-08 12:50:50 +00:00
/**
* looks through the cart to see if shipping is actually required
*/
function needs_shipping () {
if ( get_option ( 'woocommerce_calc_shipping' ) == 'no' ) return false ;
if ( ! is_array ( $this -> cart_contents )) return false ;
2011-11-06 13:45:18 +00:00
2011-12-08 12:50:50 +00:00
$needs_shipping = false ;
foreach ( $this -> cart_contents as $cart_item_key => $values ) :
$_product = $values [ 'data' ];
if ( $_product -> needs_shipping () ) :
$needs_shipping = true ;
endif ;
endforeach ;
return $needs_shipping ;
}
2011-11-06 13:45:18 +00:00
2011-12-08 12:50:50 +00:00
/**
* Sees if we need a shipping address
*/
function ship_to_billing_address_only () {
if ( get_option ( 'woocommerce_ship_to_billing_address_only' ) == 'yes' ) return true ; else return false ;
}
2011-11-19 20:59:16 +00:00
2011-12-08 12:50:50 +00:00
/**
* gets the shipping total ( after calculation )
*/
function get_cart_shipping_total () {
global $woocommerce ;
if ( isset ( $this -> shipping_label )) :
if ( $this -> shipping_total > 0 ) :
// Display ex tax if the option is set, or prices exclude tax
if ( $this -> display_totals_ex_tax || ! $this -> prices_include_tax ) :
$return = woocommerce_price ( $this -> shipping_total );
if ( $this -> shipping_tax_total > 0 && $this -> prices_include_tax ) :
$return .= ' <small>' . $woocommerce -> countries -> ex_tax_or_vat () . '</small>' ;
endif ;
return $return ;
else :
$return = woocommerce_price ( $this -> shipping_total + $this -> shipping_tax_total );
if ( $this -> shipping_tax_total > 0 && ! $this -> prices_include_tax ) :
$return .= ' <small>' . $woocommerce -> countries -> inc_tax_or_vat () . '</small>' ;
endif ;
return $return ;
endif ;
2011-11-06 13:45:18 +00:00
else :
2012-01-05 11:31:22 +00:00
return __ ( 'Free!' , 'woocommerce' );
2011-11-06 13:45:18 +00:00
endif ;
endif ;
2011-12-08 12:50:50 +00:00
}
2011-11-06 13:45:18 +00:00
2011-12-08 12:50:50 +00:00
/**
* gets title of the chosen shipping method
*/
function get_cart_shipping_title () {
if ( isset ( $this -> shipping_label )) :
2012-01-05 11:31:22 +00:00
return __ ( 'via' , 'woocommerce' ) . ' ' . $this -> shipping_label ;
2011-12-08 12:50:50 +00:00
endif ;
return false ;
}
/*-----------------------------------------------------------------------------------*/
/* Coupons/Discount related functions */
/*-----------------------------------------------------------------------------------*/
/**
* returns whether or not a discount has been applied
*/
function has_discount ( $code ) {
if ( in_array ( $code , $this -> applied_coupons )) return true ;
return false ;
}
/**
* Applies a coupon code
*
* @ param string code The code to apply
* @ return bool True if the coupon is applied , false if it does not exist or cannot be applied
*/
function add_discount ( $coupon_code ) {
global $woocommerce ;
2011-11-06 13:45:18 +00:00
2011-12-08 12:50:50 +00:00
$the_coupon = & new woocommerce_coupon ( $coupon_code );
if ( $the_coupon -> id ) :
2011-11-06 13:45:18 +00:00
2011-12-08 12:50:50 +00:00
// Check if applied
if ( $woocommerce -> cart -> has_discount ( $coupon_code )) :
2012-01-05 11:31:22 +00:00
$woocommerce -> add_error ( __ ( 'Discount code already applied!' , 'woocommerce' ) );
2011-12-08 12:50:50 +00:00
return false ;
endif ;
2011-11-06 13:45:18 +00:00
2011-12-08 12:50:50 +00:00
// Check it can be used with cart
if ( ! $the_coupon -> is_valid ()) :
2012-01-05 11:31:22 +00:00
$woocommerce -> add_error ( __ ( 'Invalid coupon.' , 'woocommerce' ) );
2011-12-08 12:50:50 +00:00
return false ;
endif ;
2011-11-06 13:45:18 +00:00
2011-12-08 12:50:50 +00:00
// If its individual use then remove other coupons
if ( $the_coupon -> individual_use == 'yes' ) :
$this -> applied_coupons = array ();
2011-11-06 13:45:18 +00:00
endif ;
2011-12-08 12:50:50 +00:00
foreach ( $this -> applied_coupons as $code ) :
$coupon = & new woocommerce_coupon ( $code );
if ( $coupon -> individual_use == 'yes' ) :
$this -> applied_coupons = array ();
endif ;
endforeach ;
$this -> applied_coupons [] = $coupon_code ;
$this -> set_session ();
2012-01-05 11:31:22 +00:00
$woocommerce -> add_message ( __ ( 'Discount code applied successfully.' , 'woocommerce' ) );
2011-12-08 12:50:50 +00:00
return true ;
2011-11-06 13:45:18 +00:00
else :
2012-01-05 11:31:22 +00:00
$woocommerce -> add_error ( __ ( 'Coupon does not exist!' , 'woocommerce' ) );
2011-12-08 12:50:50 +00:00
return false ;
2011-11-06 13:45:18 +00:00
endif ;
2011-12-08 12:50:50 +00:00
return false ;
}
/**
* gets the array of applied coupon codes
*/
function get_applied_coupons () {
return ( array ) $this -> applied_coupons ;
}
2011-11-06 13:45:18 +00:00
2011-12-08 12:50:50 +00:00
/**
* gets the array of applied coupon codes
*/
function remove_coupons ( $type = 0 ) {
2011-11-06 13:45:18 +00:00
2011-12-08 12:50:50 +00:00
if ( $type == 1 ) :
if ( $this -> applied_coupons ) foreach ( $this -> applied_coupons as $index => $code ) :
$coupon = & new woocommerce_coupon ( $code );
if ( $coupon -> apply_before_tax () ) unset ( $this -> applied_coupons [ $index ]);
endforeach ;
$_SESSION [ 'coupons' ] = $this -> applied_coupons ;
elseif ( $type == 2 ) :
if ( $this -> applied_coupons ) foreach ( $this -> applied_coupons as $index => $code ) :
$coupon = & new woocommerce_coupon ( $code );
if ( ! $coupon -> apply_before_tax () ) unset ( $this -> applied_coupons [ $index ]);
endforeach ;
$_SESSION [ 'coupons' ] = $this -> applied_coupons ;
else :
unset ( $_SESSION [ 'coupons' ]);
$this -> applied_coupons = array ();
endif ;
}
/*-----------------------------------------------------------------------------------*/
/* Get Formatted Totals */
/*-----------------------------------------------------------------------------------*/
/**
* Get the total of all order discounts ( after tax discounts )
*/
function get_order_discount_total () {
return $this -> discount_total ;
}
2011-11-06 13:45:18 +00:00
2011-12-08 12:50:50 +00:00
/**
* Get the total of all cart discounts ( before tax discounts )
*/
function get_cart_discount_total () {
return $this -> discount_cart ;
}
/**
* gets the total ( after calculation )
*/
function get_total () {
return woocommerce_price ( $this -> total );
}
/**
* gets the cart contents total ( after calculation )
*/
function get_cart_total () {
if ( ! $this -> prices_include_tax ) :
return woocommerce_price ( $this -> cart_contents_total );
else :
return woocommerce_price ( $this -> cart_contents_total + $this -> tax_total );
endif ;
}
/**
* gets the sub total ( after calculation )
*/
2011-12-30 19:36:44 +00:00
function get_cart_subtotal ( $compound = false ) {
2011-12-08 12:50:50 +00:00
global $woocommerce ;
2011-11-06 13:45:18 +00:00
2011-12-29 01:18:59 +00:00
// If the cart has compound tax, we want to show the subtotal as
// cart + shipping + non-compound taxes (after discount)
2011-12-30 19:36:44 +00:00
if ( $compound ) :
2011-11-06 13:45:18 +00:00
2011-12-30 21:11:18 +00:00
return woocommerce_price ( $this -> cart_contents_total + $this -> shipping_total + $this -> get_taxes_total ( false ) );
2011-12-29 01:18:59 +00:00
// Otherwise we show cart items totals only (before discount)
2011-11-06 13:45:18 +00:00
else :
2011-12-29 01:18:59 +00:00
// Display ex tax if the option is set, or prices exclude tax
if ( $this -> display_totals_ex_tax || ! $this -> prices_include_tax ) :
$return = woocommerce_price ( $this -> subtotal_ex_tax );
if ( $this -> tax_total > 0 && $this -> prices_include_tax ) :
$return .= ' <small>' . $woocommerce -> countries -> ex_tax_or_vat () . '</small>' ;
endif ;
return $return ;
else :
$return = woocommerce_price ( $this -> subtotal );
if ( $this -> tax_total > 0 && ! $this -> prices_include_tax ) :
$return .= ' <small>' . $woocommerce -> countries -> inc_tax_or_vat () . '</small>' ;
endif ;
return $return ;
2011-12-08 12:50:50 +00:00
endif ;
2011-11-06 13:45:18 +00:00
endif ;
2011-12-08 12:50:50 +00:00
}
2011-08-09 15:16:18 +00:00
2011-12-08 12:50:50 +00:00
/**
* Get the product row subtotal
*
* Gets the tax etc to avoid rounding issues .
*
* When on the checkout ( review order ), this will get the subtotal based on the customer ' s tax rate rather than the base rate
*/
function get_product_subtotal ( $_product , $quantity ) {
global $woocommerce ;
2011-12-29 01:18:59 +00:00
2011-12-08 12:50:50 +00:00
$price = $_product -> get_price ();
$taxable = $_product -> is_taxable ();
2011-12-29 01:18:59 +00:00
$base_tax_rates = $this -> tax -> get_shop_base_rate ( $_product -> tax_class );
$tax_rates = $this -> tax -> get_rates ( $_product -> get_tax_class () ); // This will get the base rate unless we're on the checkout page
2011-08-09 15:16:18 +00:00
2011-12-08 12:50:50 +00:00
// Taxable
2011-12-28 23:59:33 +00:00
if ( $taxable ) :
2011-08-09 15:16:18 +00:00
2011-12-08 12:50:50 +00:00
if ( $this -> display_cart_ex_tax && $this -> prices_include_tax ) :
2011-12-29 01:18:59 +00:00
$base_taxes = $this -> tax -> calc_tax ( $price * $quantity , $base_tax_rates , true );
2011-12-30 19:36:44 +00:00
$base_tax_amount = array_sum ( $base_taxes );
2012-01-02 15:25:07 +00:00
2011-12-08 12:50:50 +00:00
$row_price = ( $price * $quantity ) - $base_tax_amount ;
$return = woocommerce_price ( $row_price );
$return .= ' <small class="tax_label">' . $woocommerce -> countries -> ex_tax_or_vat () . '</small>' ;
2011-11-22 14:22:35 +00:00
2011-12-29 01:18:59 +00:00
elseif ( ! $this -> display_cart_ex_tax && $tax_rates !== $base_tax_rates && $this -> prices_include_tax ) :
2011-12-30 19:36:44 +00:00
$base_taxes = $this -> tax -> calc_tax ( $price * $quantity , $base_tax_rates , true );
$modded_taxes = $this -> tax -> calc_tax ( ( $price * $quantity ) - array_sum ( $base_taxes ), $tax_rates , false );
$row_price = (( $price * $quantity ) - array_sum ( $base_taxes )) + array_sum ( $modded_taxes );
2011-12-08 12:50:50 +00:00
$return = woocommerce_price ( $row_price );
2012-01-04 23:01:47 +00:00
if ( ! $this -> prices_include_tax ) :
$return .= ' <small class="tax_label">' . $woocommerce -> countries -> inc_tax_or_vat () . '</small>' ;
endif ;
2011-12-08 12:50:50 +00:00
else :
$row_price = $price * $quantity ;
$return = woocommerce_price ( $row_price );
endif ;
2011-11-26 16:15:25 +00:00
2011-12-08 12:50:50 +00:00
// Non taxable
2011-11-26 16:15:25 +00:00
else :
$row_price = $price * $quantity ;
$return = woocommerce_price ( $row_price );
endif ;
2011-11-23 23:19:23 +00:00
2011-12-08 12:50:50 +00:00
return $return ;
}
2011-11-22 13:18:33 +00:00
2011-12-08 12:50:50 +00:00
/**
* gets the cart tax ( after calculation )
*/
function get_cart_tax () {
2011-12-23 18:15:46 +00:00
$return = false ;
2011-12-08 12:50:50 +00:00
$cart_total_tax = $this -> tax_total + $this -> shipping_tax_total ;
2011-12-23 18:15:46 +00:00
if ( $cart_total_tax > 0 ) $return = woocommerce_price ( $cart_total_tax );
return apply_filters ( 'woocommerce_get_cart_tax' , $return );
2011-12-30 21:11:18 +00:00
}
/**
* Get tax row amounts with or without compound taxes includes
*/
function get_taxes_total ( $compound = true ) {
$total = 0 ;
foreach ( $this -> taxes as $key => $tax ) :
if ( ! $compound && $this -> tax -> is_compound ( $key )) continue ;
$total += $tax ;
endforeach ;
return $total ;
}
2011-11-22 13:18:33 +00:00
2011-12-08 12:50:50 +00:00
/**
* gets the total ( product ) discount amount - these are applied before tax
*/
function get_discounts_before_tax () {
if ( $this -> discount_cart ) :
return woocommerce_price ( $this -> discount_cart );
endif ;
return false ;
}
2011-11-22 13:18:33 +00:00
2011-12-08 12:50:50 +00:00
/**
* gets the order discount amount - these are applied after tax
*/
function get_discounts_after_tax () {
if ( $this -> discount_total ) :
return woocommerce_price ( $this -> discount_total );
endif ;
return false ;
}
2011-09-06 11:11:22 +00:00
2011-12-08 12:50:50 +00:00
/**
* gets the total discount amount - both kinds
*/
function get_total_discount () {
if ( $this -> discount_total || $this -> discount_cart ) :
return woocommerce_price ( $this -> discount_total + $this -> discount_cart );
2011-08-09 15:16:18 +00:00
endif ;
2011-12-08 12:50:50 +00:00
return false ;
}
2011-08-09 15:16:18 +00:00
}