This commit is contained in:
Julian Jöris 2011-11-21 11:38:14 +01:00
parent e469a838bb
commit fb5df55da5
23 changed files with 452 additions and 240 deletions

View File

@ -89,7 +89,7 @@ function woocommerce_admin_scripts() {
$woocommerce_witepanel_params = array(
'remove_item_notice' => __("Remove this item? If you have previously reduced this item's stock, or this order was submitted by a customer, will need to manually restore the item's stock.", 'woothemes'),
'cart_total' => __("Calc totals based on order items, discount amount, and shipping?", 'woothemes'),
'cart_total' => __("Calculate totals based on order items, discount amount, and shipping? Note, you will need to calculate discounts before tax manually.", 'woothemes'),
'copy_billing' => __("Copy billing information to shipping information? This will remove any currently entered shipping information.", 'woothemes'),
'prices_include_tax' => get_option('woocommerce_prices_include_tax'),
'ID' => __('ID', 'woothemes'),

View File

@ -35,6 +35,9 @@ function woocommerce_coupon_data_meta_box($post) {
// Individual use
woocommerce_wp_checkbox( array( 'id' => 'individual_use', 'label' => __('Individual use', 'woothemes'), 'description' => __('Check this box if the coupon cannot be used in conjunction with other coupons', 'woothemes') ) );
// Apply before tax
woocommerce_wp_checkbox( array( 'id' => 'apply_before_tax', 'label' => __('Apply coupon before tax?', 'woothemes'), 'description' => __('Check this box if the coupon should be applied before calculating a product\'s tax', 'woothemes') ) );
// Product ids
woocommerce_wp_text_input( array( 'id' => 'product_ids', 'label' => __('Product IDs', 'woothemes'), 'placeholder' => __('N/A', 'woothemes'), 'description' => __('(optional) Comma separate IDs which need to be in the cart to use this coupon or, for "Product Discounts", which products are discounted.', 'woothemes') ) );
@ -54,18 +57,6 @@ function woocommerce_coupon_data_meta_box($post) {
<?php
}
/**
* Coupon data meta box
*
* Displays the meta box
*/
add_filter('enter_title_here', 'woocommerce_coupon_enter_title_here', 1, 2);
function woocommerce_coupon_enter_title_here( $text, $post ) {
if ($post->post_type=='shop_coupon') return __('Coupon code', 'woothemes');
return $text;
}
/**
* Coupon Data Save
*
@ -79,7 +70,6 @@ function woocommerce_process_shop_coupon_meta( $post_id, $post ) {
$woocommerce_errors = array();
if (!$_POST['coupon_amount']) $woocommerce_errors[] = __('Coupon amount is required', 'woothemes');
if ($_POST['discount_type']=='fixed_product' && !$_POST['product_ids']) $woocommerce_errors[] = __('Product discount coupons require you to set "Product IDs" to work.', 'woothemes');
// Add/Replace data to array
$type = strip_tags(stripslashes( $_POST['discount_type'] ));
@ -89,6 +79,7 @@ function woocommerce_process_shop_coupon_meta( $post_id, $post ) {
$usage_limit = (isset($_POST['usage_limit']) && $_POST['usage_limit']>0) ? (int) $_POST['usage_limit'] : '';
$individual_use = isset($_POST['individual_use']) ? 'yes' : 'no';
$expiry_date = strip_tags(stripslashes( $_POST['expiry_date'] ));
$apply_before_tax = isset($_POST['apply_before_tax']) ? 'yes' : 'no';
// Save
update_post_meta( $post_id, 'discount_type', $type );
@ -98,6 +89,7 @@ function woocommerce_process_shop_coupon_meta( $post_id, $post ) {
update_post_meta( $post_id, 'exclude_product_ids', $exclude_product_ids );
update_post_meta( $post_id, 'usage_limit', $usage_limit );
update_post_meta( $post_id, 'expiry_date', $expiry_date );
update_post_meta( $post_id, 'apply_before_tax', $apply_before_tax );
do_action('woocommerce_coupon_options');

View File

@ -254,7 +254,7 @@ function variable_product_write_panel_js() {
if ($attribute['is_taxonomy']) :
$post_terms = wp_get_post_terms( $post->ID, $attribute['name'] );
foreach ($post_terms as $term) :
echo '<option value="'.$term->slug.'">'.$term->name.'</option>';
echo '<option value="'.$term->slug.'">'.esc_html($term->name).'</option>';
endforeach;
else :
$options = explode('|', $attribute['value']);

View File

@ -504,7 +504,7 @@ function woocommerce_process_product_meta( $post_id, $post ) {
endif;
else :
// Format values
$values = htmlspecialchars(stripslashes($attribute_values[$i]));
$values = esc_html(stripslashes($attribute_values[$i]));
// Text based, separate by pipe
$values = explode('|', $values);
$values = array_map('trim', $values);

View File

@ -44,6 +44,17 @@ function woocommerce_meta_boxes() {
add_meta_box('product_variation-parent', __('Product', 'woothemes'), 'variations_product_meta_box', 'product_variation', 'side', 'default');
}
/**
* Title boxes
*/
add_filter('enter_title_here', 'woocommerce_enter_title_here', 1, 2);
function woocommerce_enter_title_here( $text, $post ) {
if ($post->post_type=='shop_coupon') return __('Coupon code', 'woothemes');
if ($post->post_type=='product') return __('Product name', 'woothemes');
return $text;
}
/**
* Let variations have a product as the parent
*/

View File

@ -275,6 +275,9 @@ jQuery(document).ready(function($) {
var variation = product_variations[i];
var variation_id = variation.variation_id;
//console.debug(variation.attributes);
//console.debug(settings);
if(variations_match(variation.attributes, settings)) {
matching.push(variation);
}
@ -305,7 +308,17 @@ jQuery(document).ready(function($) {
if(attr_name == current_attr_name) {
if (attr_val) {
// Decode entities
attr_val = $("<div/>").html( attr_val ).text();
// Add slashes
attr_val = attr_val.replace(/'/g, "\\'");
attr_val = attr_val.replace(/"/g, "\\\"");
// Compare the meercat
current_attr_select.find('option[value="'+attr_val+'"]').removeAttr('disabled');
} else {
current_attr_select.find('option').removeAttr('disabled');
}
@ -364,10 +377,14 @@ jQuery(document).ready(function($) {
} else {
if ($(this).val().length == 0) all_set = false;
// Get value
value = $(this).val();
value = value.replace('"', '&quot;');
// Encode entities
value = $(this).val()
.replace(/&/g, '&amp;')
.replace(/"/g, '&quot;')
.replace(/'/g, '&#039;')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;');
// Add to settings array
current_settings[$(this).attr('name')] = value;
}

File diff suppressed because one or more lines are too long

View File

@ -17,7 +17,6 @@ class woocommerce_cart {
var $applied_coupons;
var $cart_contents_total;
var $cart_contents_total_ex_tax;
var $cart_contents_weight;
var $cart_contents_count;
var $cart_contents_tax;
@ -26,14 +25,20 @@ class woocommerce_cart {
var $subtotal;
var $subtotal_ex_tax;
var $tax_total;
var $discount_product;
var $discount_total;
var $shipping_total;
var $shipping_tax_total;
/* Private variables */
var $tax;
/**
* Constructor
*/
function __construct() {
$this->tax = &new woocommerce_tax();
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
}
@ -106,18 +111,7 @@ class woocommerce_cart {
*/
function empty_cart() {
$this->cart_contents = array();
$this->total = 0;
$this->cart_contents_total = 0;
$this->cart_contents_total_ex_tax = 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->shipping_total = 0;
$this->reset_totals();
unset($_SESSION['cart']);
unset($_SESSION['coupons']);
}
@ -188,8 +182,8 @@ class woocommerce_cart {
$product_data = &new woocommerce_product( $product_id );
endif;
// Type check
if ( $product_data->is_type('external') ) :
// Type/Exists check
if ( $product_data->is_type('external') || !$product_data->exists() ) :
$woocommerce->add_error( __('This product cannot be purchased.', 'woothemes') );
return false;
endif;
@ -308,16 +302,11 @@ class woocommerce_cart {
}
/**
* calculate totals for the items in the cart
* Reset totals
*/
function calculate_totals() {
global $woocommerce;
$_tax = &new woocommerce_tax();
private function reset_totals() {
$this->total = 0;
$this->cart_contents_total = 0;
$this->cart_contents_total_ex_tax = 0;
$this->cart_contents_weight = 0;
$this->cart_contents_count = 0;
$this->cart_contents_tax = 0;
@ -326,179 +315,295 @@ class woocommerce_cart {
$this->subtotal = 0;
$this->subtotal_ex_tax = 0;
$this->discount_total = 0;
$this->discount_product = 0;
$this->shipping_total = 0;
}
/**
* Function to apply discounts to a product and get the discounted price (before tax is applied)
*/
function get_discounted_price( $values, $price ) {
if (sizeof($this->cart_contents)>0) : foreach ($this->cart_contents as $cart_item_key => $values) :
if ($this->applied_coupons) foreach ($this->applied_coupons as $code) :
$coupon = &new woocommerce_coupon( $code );
// Get product from cart data
$_product = $values['data'];
if ( $coupon->apply_before_tax() && $coupon->is_valid() ) :
switch ($coupon->type) :
case "fixed_product" :
case "percent_product" :
$this_item_is_discounted = false;
if ($_product->exists() && $values['quantity']>0) :
$this->cart_contents_count = $this->cart_contents_count + $values['quantity'];
$this->cart_contents_weight = $this->cart_contents_weight + ($_product->get_weight() * $values['quantity']);
$total_item_price = $_product->get_price() * $values['quantity'];
if ( get_option('woocommerce_calc_taxes')=='yes') :
if ( $_product->is_taxable() ) :
$rate = $_tax->get_rate( $_product->get_tax_class() );
// 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;
if (get_option('woocommerce_prices_include_tax')=='yes') :
// Price incldues tax
$tax_amount = $_tax->calc_tax( $_product->get_price(), $rate, true ) * $values['quantity'];
else :
// Price excludes tax
$tax_amount = $_tax->calc_tax( $_product->get_price(), $rate, false ) * $values['quantity'];
// 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) :
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;
endif;
/**
* Checkout calculations when customer is OUTSIDE the shop base country and price INCLUDE tax
*/
if (get_option('woocommerce_prices_include_tax')=='yes' && $woocommerce->customer->is_customer_outside_base() && defined('WOOCOMMERCE_CHECKOUT') && WOOCOMMERCE_CHECKOUT ) :
// Get the base rate first
$base_rate = $_tax->get_shop_base_rate( $_product->tax_class );
// 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') :
// Calc tax for base country
$base_tax_amount = $_tax->calc_tax( $_product->get_price(), $base_rate, true);
// Now calc tax for user county (which now excludes tax)
$tax_amount = $_tax->calc_tax( ( $_product->get_price() - $base_tax_amount ), $rate, false );
$tax_amount = $tax_amount * $values['quantity'];
// Finally, update $total_item_price to reflect tax amounts
$total_item_price = ($total_item_price - ($base_tax_amount * $values['quantity']) + $tax_amount);
/**
* Checkout calculations when customer is INSIDE the shop base country and price INCLUDE tax
*/
elseif (get_option('woocommerce_prices_include_tax')=='yes' && $_product->get_tax_class() !== $_product->tax_class) :
// Calc tax for original rate
$original_tax_amount = $_tax->calc_tax( $_product->get_price(), $_tax->get_rate( $_product->tax_class ), true);
// Now calc tax for new rate (which now excludes tax)
$tax_amount = $_tax->calc_tax( ( $_product->get_price() - $original_tax_amount ), $rate, false );
$tax_amount = $tax_amount * $values['quantity'];
$total_item_price = ($total_item_price - ($original_tax_amount * $values['quantity']) + $tax_amount);
$this->discount_product = $this->discount_product + ( $coupon->amount * $values['quantity'] );
$price = $price - $coupon->amount;
elseif ($coupon->type=='percent_product') :
$percent_discount = ( $values['data']->get_price_excluding_tax() / 100 ) * $coupon->amount;
$this->discount_product = $this->discount_product + ( $percent_discount * $values['quantity'] );
$price = $price - $percent_discount;
endif;
endif;
break;
case "fixed_cart" :
// Use pence to help prevent rounding errors
$coupon_amount_pence = $coupon->amount * 100;
// Get item discount by dividing by total number of products in the cart
$item_discount = $coupon_amount_pence / $this->cart_contents_count;
// Take discount off of price (in pence)
$price = ( $price * 100 ) - $item_discount;
// Back to pounds
$price = $price / 100;
// Add coupon to discount total (once, since this is a fixed cart discount and we don't want rounding issues)
$this->discount_product = $this->discount_product + (($item_discount*$values['quantity']) / 100);
break;
case "percent" :
// Get % off each item - this works out the same as doing the whole cart
$percent_discount = ( $values['data']->get_price_excluding_tax() / 100 ) * $coupon->amount;
$this->discount_product = $this->discount_product + ( $percent_discount * $values['quantity'] );
$price = $price - $percent_discount;
break;
endswitch;
endif;
endforeach;
return $price;
}
/**
* 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 );
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) :
if ((in_array($values['product_id'], $coupon->product_ids) || in_array($values['variation_id'], $coupon->product_ids))) :
$this_item_is_discounted = true;
endif;
else :
// 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) :
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;
endif;
$tax_amount = ( isset($tax_amount) ? $tax_amount : 0 );
$this->cart_contents_tax = $this->cart_contents_tax + $tax_amount;
$this->cart_contents_total = $this->cart_contents_total + $total_item_price;
$this->cart_contents_total_ex_tax = $this->cart_contents_total_ex_tax + ($_product->get_price_excluding_tax()*$values['quantity']);
// Apply filter
$this_item_is_discounted = apply_filters( 'woocommerce_item_is_discounted', $this_item_is_discounted, $values, $before_tax = false );
// Product Discounts
if ($this->applied_coupons) foreach ($this->applied_coupons as $code) :
$coupon = &new woocommerce_coupon( $code );
if ($coupon->type!='fixed_product' && $coupon->type!='percent_product') continue;
$this_item_is_discounted = false;
// 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;
else :
// No product ids - all items discounted
$this_item_is_discounted = true;
// Apply the discount
if ($this_item_is_discounted) :
if ($coupon->type=='fixed_product') :
$this->discount_total = $this->discount_total + ( $coupon->amount * $values['quantity'] );
elseif ($coupon->type=='percent_product') :
$this->discount_total = $this->discount_total + ( $price / 100 ) * $coupon->amount;
endif;
// Specific product ID's excluded from the discount
if (sizeof($coupon->exclude_product_ids)>0) :
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;
endif;
// Apply filter
$this_item_is_discounted = apply_filters( 'woocommerce_item_is_discounted', $this_item_is_discounted, $values );
// Apply the discount
if ($this_item_is_discounted) :
if ($coupon->type=='fixed_product') :
$this->discount_total = $this->discount_total + ( $coupon->amount * $values['quantity'] );
elseif ($coupon->type=='percent_product') :
$this->discount_total = $this->discount_total + ( $total_item_price / 100 ) * $coupon->amount;
endif;
endif;
endforeach;
endif;
endif;
endforeach; endif;
endforeach;
}
/**
* Function to apply cart discounts after tax
*/
function apply_cart_discounts_after_tax() {
// Calculate final totals
$this->tax_total = $this->cart_contents_tax; // Tax Total
$this->subtotal_ex_tax = $this->cart_contents_total_ex_tax; // Subtotal without tax
$this->subtotal = $this->cart_contents_total; // Subtotal
if ($this->applied_coupons) foreach ($this->applied_coupons as $code) :
$coupon = &new woocommerce_coupon( $code );
if ( !$coupon->apply_before_tax() && $coupon->is_valid() ) :
switch ($coupon->type) :
case "fixed_cart" :
$this->discount_total = $this->discount_total + $coupon->amount;
break;
case "percent" :
$percent_discount = round( ( ($this->cart_contents_total + $this->tax_total) / 100) * $coupon->amount , 2);
$this->discount_total = $this->discount_total + $percent_discount;
break;
endswitch;
endif;
endforeach;
}
/**
* calculate totals for the items in the cart
*/
function calculate_totals() {
global $woocommerce;
$this->reset_totals();
// Get count of all items
if (sizeof($this->cart_contents)>0) foreach ($this->cart_contents as $cart_item_key => $values) $this->cart_contents_count = $this->cart_contents_count + $values['quantity'];
// Calc totals for items
if (sizeof($this->cart_contents)>0) foreach ($this->cart_contents as $cart_item_key => $values) :
$_product = $values['data'];
$this->cart_contents_weight = $this->cart_contents_weight + ($_product->get_weight() * $values['quantity']);
// Base Price (i.e. no tax, regardless of region)
$base_price = $_product->get_price_excluding_tax();
// Discounted Price (base price with any pre-tax discounts applied
$discounted_price = $this->get_discounted_price( $values, $base_price );
// Tax Amount (For the line, based on discounted, ex.tax price)
if ( get_option('woocommerce_calc_taxes')=='yes' && $_product->is_taxable() ) :
$tax_rate = $this->tax->get_rate( $_product->get_tax_class() );
$tax_amount = $this->tax->calc_tax( $base_price, $tax_rate, false ) * $values['quantity'];
$discounted_tax_amount = $this->tax->calc_tax( $discounted_price, $tax_rate, false ) * $values['quantity'];
else :
$tax_amount = 0;
$discounted_tax_amount = 0;
endif;
// Total item price (discounted price + tax * quantity)
$total_item_price = ($discounted_price*$values['quantity']) + $discounted_tax_amount;
// Add any product discounts (after tax)
$this->apply_product_discounts_after_tax( $values, $total_item_price );
// Sub total is based on base prices (without discounts)
$this->subtotal = $this->subtotal + ($base_price*$values['quantity']) + $tax_amount;
$this->subtotal_ex_tax = $this->subtotal_ex_tax + ($base_price*$values['quantity']);
// Cart contents total is based on discounted prices and is used for the final total calculation
$this->cart_contents_total = $this->cart_contents_total + ($discounted_price*$values['quantity']);
// Cart tax is based on discounted amounts
$this->tax_total = $this->tax_total + $discounted_tax_amount;
endforeach;
// 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 Discounts
if ($this->applied_coupons) foreach ($this->applied_coupons as $code) :
$coupon = &new woocommerce_coupon( $code );
if ($coupon->is_valid()) :
if ($coupon->type=='fixed_cart') :
$this->discount_total = $this->discount_total + $coupon->amount;
elseif ($coupon->type=='percent') :
if (get_option('woocommerce_prices_include_tax')=='yes') :
$this->discount_total = $this->discount_total + ( $this->subtotal / 100 ) * $coupon->amount;
else :
$this->discount_total = $this->discount_total + ( ($this->subtotal + $this->cart_contents_tax) / 100 ) * $coupon->amount;
endif;
endif;
endif;
endforeach;
// Cart Shipping
if ($this->needs_shipping()) $woocommerce->shipping->calculate_shipping(); else $woocommerce->shipping->reset_shipping();
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_tax_total = $woocommerce->shipping->shipping_tax; // Shipping Tax
// VAT excemption done at this point - so all totals are correct before exemption
if ($woocommerce->customer->is_vat_exempt()) :
$this->shipping_tax_total = 0;
$this->tax_total = 0;
$this->shipping_tax_total = $this->tax_total = 0;
endif;
// Allow plugins to hook and alter totals before final total is calculated
do_action('woocommerce_calculate_totals', $this);
// Grand Total
if (get_option('woocommerce_prices_include_tax')=='yes') :
$this->total = $this->subtotal + $this->shipping_tax_total - $this->discount_total + $woocommerce->shipping->shipping_total;
else :
$this->total = $this->subtotal + $this->tax_total + $this->shipping_tax_total - $this->discount_total + $woocommerce->shipping->shipping_total;
endif;
/**
* Grand Total
*
* Based on discounted product prices, discounted tax, shipping cost + tax, and any discounts to be added after tax (e.g. store credit)
*/
$this->total = $this->cart_contents_total + $this->tax_total + $this->shipping_tax_total + $woocommerce->shipping->shipping_total - $this->discount_total;
if ($this->total < 0) $this->total = 0;
}
/**
* Get the total of all discounts
*/
function get_discount_total() {
return $this->discount_total + $this->discount_product;
}
/**
*returns whether or not a discount has been applied
*/
@ -547,10 +652,10 @@ class woocommerce_cart {
* 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() );
}
/**
@ -720,11 +825,7 @@ class woocommerce_cart {
if (get_option('woocommerce_display_totals_tax')=='excluding' || ( defined('WOOCOMMERCE_CHECKOUT') && WOOCOMMERCE_CHECKOUT )) :
if (get_option('woocommerce_prices_include_tax')=='yes') :
$return = woocommerce_price($this->subtotal - $this->tax_total);
else :
$return = woocommerce_price($this->subtotal);
endif;
$return = woocommerce_price( $this->subtotal_ex_tax );
if ($this->tax_total>0) :
$return .= ' <small>'.$woocommerce->countries->ex_tax_or_vat().'</small>';
@ -733,11 +834,7 @@ class woocommerce_cart {
else :
if (get_option('woocommerce_prices_include_tax')=='yes') :
$return = woocommerce_price($this->subtotal);
else :
$return = woocommerce_price($this->subtotal + $this->tax_total);
endif;
$return = woocommerce_price( $this->subtotal );
if ($this->tax_total>0) :
$return .= ' <small>'.$woocommerce->countries->inc_tax_or_vat().'</small>';
@ -802,10 +899,34 @@ class woocommerce_cart {
}
/**
* gets the total discount amount
* gets the total (product) discount amount - these are applied before tax
*/
function get_discounts_before_tax() {
if ($this->discount_product) :
return woocommerce_price($this->discount_product);
endif;
return false;
}
/**
* gets the total (product) discount amount - these are applied before tax
*/
function get_discounts_after_tax() {
if ($this->discount_total) :
return woocommerce_price($this->discount_total);
endif;
return false;
}
/**
* gets the total discount amount - both kinds
*/
function get_total_discount() {
if ($this->discount_total) return woocommerce_price($this->discount_total); else return false;
if ($this->discount_total || $this->discount_product) :
return woocommerce_price($this->discount_total + $this->discount_product);
endif;
return false;
}
/**

View File

@ -530,8 +530,7 @@ class woocommerce_checkout {
endif;
endif;
// hook, to be able to use the validation, but to be able to do something different afterwards
do_action( 'woocommerce_after_checkout_validation', $this->posted, $_POST, $woocommerce->error_count() );
do_action( 'woocommerce_after_checkout_validation', $this->posted );
if (!isset($_POST['update_totals']) && $woocommerce->error_count()==0) :
@ -746,7 +745,7 @@ class woocommerce_checkout {
update_post_meta( $order_id, '_payment_method', $this->posted['payment_method']);
update_post_meta( $order_id, '_order_subtotal', number_format($woocommerce->cart->subtotal_ex_tax, 2, '.', ''));
update_post_meta( $order_id, '_order_shipping', number_format($woocommerce->cart->shipping_total, 2, '.', ''));
update_post_meta( $order_id, '_order_discount', number_format($woocommerce->cart->discount_total, 2, '.', ''));
update_post_meta( $order_id, '_order_discount', number_format($woocommerce->cart->get_discount_total(), 2, '.', ''));
update_post_meta( $order_id, '_order_tax', number_format($woocommerce->cart->tax_total, 2, '.', ''));
update_post_meta( $order_id, '_order_shipping_tax', number_format($woocommerce->cart->shipping_tax_total, 2, '.', ''));
update_post_meta( $order_id, '_order_total', number_format($woocommerce->cart->total, 2, '.', ''));
@ -859,4 +858,4 @@ class woocommerce_checkout {
endif;
}
}
}

View File

@ -20,6 +20,7 @@ class woocommerce_coupon {
var $usage_limit;
var $usage_count;
var $expiry_date;
var $apply_before_tax;
/** get coupon with $code */
function woocommerce_coupon( $code ) {
@ -39,6 +40,7 @@ class woocommerce_coupon {
$this->usage_limit = get_post_meta($coupon->ID, 'usage_limit', true);
$this->usage_count = (int) get_post_meta($coupon->ID, 'usage_count', true);
$this->expiry_date = ($expires = get_post_meta($coupon->ID, 'expiry_date', true)) ? strtotime($expires) : '';
$this->apply_before_tax = get_post_meta($coupon->ID, 'apply_before_tax', true);
if (!$this->amount) return false;
@ -49,6 +51,11 @@ class woocommerce_coupon {
return false;
}
/** Check if coupon needs applying before tax **/
function apply_before_tax() {
if ($this->apply_before_tax=='yes') return true; else return false;
}
/** Increase usage count */
function inc_usage_count() {
$this->usage_count++;

View File

@ -166,7 +166,6 @@ class woocommerce_paypal extends woocommerce_payment_gateway {
'upload' => 1,
'return' => $this->get_return_url( $order ),
'cancel_return' => $order->get_cancel_order_url(),
//'cancel_return' => home_url(),
// Order key
'custom' => $order_id,
@ -189,7 +188,7 @@ class woocommerce_paypal extends woocommerce_payment_gateway {
// Payment Info
'invoice' => $order->order_key,
'tax_cart' => $order->get_total_tax(),
'discount_amount_cart' => $order->order_discount
'discount_amount_cart' => $order->get_total_discount()
),
$phone_args
);

View File

@ -145,11 +145,19 @@ class woocommerce_order {
}
/** Gets shipping and product tax */
function get_total_tax() {
return $this->order_tax + $this->order_shipping_tax;
}
/** Gets total discount */
function get_total_discount() {
return $this->order_discount;
}
/** Gets subtotal */
function get_subtotal_to_display() {
global $woocommerce;

View File

@ -505,7 +505,7 @@ class woocommerce_product {
// Round
$price = round( $price * 100 ) / 100;
// Format
$price = number_format($price, 2, '.', '');
@ -763,7 +763,7 @@ class woocommerce_product {
if (sizeof($attributes)>0 || ($show_dimensions && $has_dimensions)) :
echo '<table cellspacing="0" class="shop_attributes">';
echo '<table class="shop_attributes">';
$alt = 1;
if (($show_dimensions && $has_dimensions)) :

View File

@ -235,21 +235,24 @@ class woocommerce_tax {
*/
function calc_tax( $price, $rate, $price_includes_tax = true ) {
$price = round($price * 100, 0); // To avoid float rounding errors, work with integers (pence)
$price = round($price * 10000, 0); // To avoid float rounding errors, work with integers (pence + 2 dp = 4 decimals)
$rate = $rate * 100;
if ($price_includes_tax) :
$rate = ($rate / 100) + 1;
$rate = ($rate / 10000) + 1;
$tax_amount = $price - ( $price / $rate);
else :
$tax_amount = $price * ($rate/100);
$tax_amount = $price * ($rate/10000);
endif;
$tax_amount = round($tax_amount); // Round to the nearest pence
$tax_amount = $tax_amount / 100; // Back to pounds
$tax_amount = round($tax_amount, 0); // Round to the nearest pence
$tax_amount = $tax_amount / 10000; // Back to pounds
return number_format($tax_amount, 2, '.', '');
return $tax_amount;
//return number_format($tax_amount, 2, '.', '');
}
/**

View File

@ -4,7 +4,7 @@ Tags: ecommerce, e-commerce, commerce, woothemes, wordpress ecommerce, store, sh
Donate link: https://www.paypal.com/cgi-bin/webscr?cmd=_xclick&business=paypal@woothemes.com&item_name=Donation+for+WooCommerce
Requires at least: 3.1
Tested up to: 3.3
Stable tag: 1.2.3
Stable tag: 1.2.4
An e-commerce toolkit that helps you sell anything. Beautifully.
@ -82,6 +82,12 @@ Yes you can! Join in on our GitHub repository :) https://github.com/woothemes/wo
== Changelog ==
= 1.3 - 18/11/2011 =
* Schema.org markup for products and reviews
* Option to apply coupons before tax
* Rewritten cart calculations to support coupons before tax and after tax (optional)
* 2 lines of discounts on total tables - 1 for product discounts, 1 for after tax discounts (e.g. store credit)
= 1.2.4 - 18/11/2011 =
* More sale price logic fixes for variations. Now correctly compares variation's prices.
* Clear cache on upgrade/install
@ -94,6 +100,7 @@ Yes you can! Join in on our GitHub repository :) https://github.com/woothemes/wo
* Feature to prevent admin access to customers (optional)
* Fixed quick edit
* text/html email headers
* Fixed variation issue with quote symbols using esc_html
= 1.2.3 - 17/11/2011 =
* Fix for sale price logic

View File

@ -15,6 +15,11 @@
<td><?php echo $woocommerce->cart->get_cart_subtotal(); ?></td>
</tr>
<?php if ($woocommerce->cart->get_discounts_before_tax()) : ?><tr class="discount">
<td colspan="2"><?php _e('Product Discounts', 'woothemes'); ?></td>
<td>-<?php echo $woocommerce->cart->get_discounts_before_tax(); ?></td>
</tr><?php endif; ?>
<?php if ($woocommerce->cart->needs_shipping()) : ?>
<td colspan="2"><?php _e('Shipping', 'woothemes'); ?></td>
<td>
@ -66,10 +71,11 @@
<td><?php echo $woocommerce->cart->get_cart_tax(); ?></td>
</tr><?php endif; ?>
<?php if ($woocommerce->cart->get_total_discount()) : ?><tr class="discount">
<?php if ($woocommerce->cart->get_discounts_after_tax()) : ?><tr class="discount">
<td colspan="2"><?php _e('Discount', 'woothemes'); ?></td>
<td>-<?php echo $woocommerce->cart->get_total_discount(); ?></td>
<td>-<?php echo $woocommerce->cart->get_discounts_after_tax(); ?></td>
</tr><?php endif; ?>
<tr>
<td colspan="2"><strong><?php _e('Grand Total', 'woothemes'); ?></strong></td>
<td><strong><?php echo $woocommerce->cart->get_total(); ?></strong></td>
@ -142,7 +148,7 @@
<?php do_action( 'woocommerce_review_order_before_submit' ); ?>
<input type="submit" class="button alt" name="place_order" id="place_order" value="<?php _e('Place order', 'woothemes'); ?>" />
<input type="submit" class="button alt" name="place_order" id="place_order" value="<?php echo apply_filters('woocommerce_order_button_text', __('Place order', 'woothemes')); ?>" />
<?php if (get_option('woocommerce_terms_page_id')>0) : ?>
<p class="form-row terms">

View File

@ -24,16 +24,18 @@
$average = number_format($rating / $count, 2);
echo '<div class="hreview-aggregate">';
echo '<div itemprop="aggregateRating" itemscope itemtype="http://schema.org/AggregateRating">';
echo '<div class="star-rating" title="'.sprintf(__('Rated %s out of 5', 'woothemes'),$average).'"><span style="width:'.($average*16).'px"><span class="rating">'.$average.'</span> '.__('out of 5', 'woothemes').'</span></div>';
echo '<div class="star-rating" title="'.sprintf(__('Rated %s out of 5', 'woothemes'), $average).'"><span style="width:'.($average*16).'px"><span itemprop="ratingValue" class="rating">'.$average.'</span> '.__('out of 5', 'woothemes').'</span></div>';
echo '<h2>'.sprintf( _n('%s review for %s', '%s reviews for %s', $count, 'woothemes'), '<span class="count">'.$count.'</span>', '<span class="item fn">'.wptexturize($post->post_title).'</span>' ).'</h2>';
echo '<h2>'.sprintf( _n('%s review for %s', '%s reviews for %s', $count, 'woothemes'), '<span itemprop="ratingCount" class="count">'.$count.'</span>', wptexturize($post->post_title) ).'</h2>';
echo '</div>';
else :
echo '<h2>'.__('Reviews', 'woothemes').'</h2>';
endif;
$title_reply = '';

View File

@ -6,13 +6,13 @@
<?php do_action('woocommerce_before_single_product', $post, $_product); ?>
<div id="post-<?php the_ID(); ?>" <?php post_class(); ?>>
<div itemscope itemtype="http://schema.org/Product" id="product-<?php the_ID(); ?>" <?php post_class(); ?>>
<?php do_action('woocommerce_before_single_product_summary', $post, $_product); ?>
<div class="summary">
<h1 class="product_title page-title"><?php the_title(); ?></h1>
<h1 itemprop="name" class="product_title page-title"><?php the_title(); ?></h1>
<?php do_action( 'woocommerce_single_product_summary', $post, $_product ); ?>

View File

@ -85,7 +85,7 @@ class WooCommerce_Widget_Login extends WP_Widget {
// Get redirect URL
$redirect_to = apply_filters( 'woocommerce_login_widget_redirect', get_permalink(get_option('woocommerce_myaccount_page_id')) );
?>
<form method="post" action="">
<form method="post">
<p><label for="user_login"><?php _e('Username', 'woothemes'); ?></label> <input name="log" value="<?php if (isset($_POST['log'])) echo esc_attr(stripslashes($_POST['log'])); ?>" class="input-text" id="user_login" type="text" /></p>

View File

@ -155,7 +155,7 @@ class WooCommerce_Widget_Price_Filter extends WP_Widget {
endif;
echo '<form method="get" action="">
echo '<form method="get">
<div class="price_slider_wrapper">
<div class="price_slider"></div>
<div class="price_slider_amount">

View File

@ -3,7 +3,7 @@
Plugin Name: WooCommerce
Plugin URI: http://www.woothemes.com/woocommerce/
Description: An eCommerce plugin for wordpress.
Version: 1.2.3
Version: 1.2.4
Author: WooThemes
Author URI: http://woothemes.com
Requires at least: 3.1
@ -28,7 +28,7 @@ endif;
* Constants
**/
if (!defined('WOOCOMMERCE_TEMPLATE_URL')) define('WOOCOMMERCE_TEMPLATE_URL', 'woocommerce/');
if (!defined("WOOCOMMERCE_VERSION")) define("WOOCOMMERCE_VERSION", "1.2.3");
if (!defined("WOOCOMMERCE_VERSION")) define("WOOCOMMERCE_VERSION", "1.2.4");
if (!defined("PHP_EOL")) define("PHP_EOL", "\r\n");
/**
@ -517,23 +517,26 @@ add_filter('preprocess_comment', 'woocommerce_check_comment_rating', 0);
function woocommerce_comments($comment, $args, $depth) {
$GLOBALS['comment'] = $comment; global $post; ?>
<li <?php comment_class(); ?> id="li-comment-<?php comment_ID() ?>">
<li itemprop="reviews" itemscope itemtype="http://schema.org/Review" <?php comment_class(); ?> id="li-comment-<?php comment_ID() ?>">
<div id="comment-<?php comment_ID(); ?>" class="comment_container">
<?php echo get_avatar( $comment, $size='60' ); ?>
<div class="comment-text">
<div class="star-rating" title="<?php echo esc_attr( get_comment_meta( $comment->comment_ID, 'rating', true ) ); ?>">
<span style="width:<?php echo get_comment_meta( $comment->comment_ID, 'rating', true )*16; ?>px"><?php echo get_comment_meta( $comment->comment_ID, 'rating', true ); ?> <?php _e('out of 5', 'woothemes'); ?></span>
<div itemprop="reviewRating" itemscope itemtype="http://schema.org/Rating" class="star-rating" title="<?php echo esc_attr( get_comment_meta( $comment->comment_ID, 'rating', true ) ); ?>">
<span style="width:<?php echo get_comment_meta( $comment->comment_ID, 'rating', true )*16; ?>px"><span itemprop="ratingValue"><?php echo get_comment_meta( $comment->comment_ID, 'rating', true ); ?></span> <?php _e('out of 5', 'woothemes'); ?></span>
</div>
<?php if ($comment->comment_approved == '0') : ?>
<p class="meta"><em><?php _e('Your comment is awaiting approval', 'woothemes'); ?></em></p>
<?php else : ?>
<p class="meta">
<?php _e('Rating by', 'woothemes'); ?> <strong class="reviewer vcard"><span class="fn"><?php comment_author(); ?></span></strong> <?php _e('on', 'woothemes'); ?> <?php echo get_comment_date('M jS Y'); ?>:
<?php _e('Rating by', 'woothemes'); ?> <strong itemprop="author"><?php comment_author(); ?></strong> <?php _e('on', 'woothemes'); ?> <time itemprop="datePublished" time datetime="<?php echo get_comment_date('c'); ?>"><?php echo get_comment_date('M jS Y'); ?></time>:
</p>
<?php endif; ?>
<div class="description"><?php comment_text(); ?></div>
<div itemprop="description" class="description"><?php comment_text(); ?></div>
<div class="clear"></div>
</div>
<div class="clear"></div>

View File

@ -238,6 +238,17 @@ function woocommerce_post_type() {
'public' => true,
'show_ui' => true,
'capability_type' => 'post',
'capabilities' => array(
'publish_posts' => 'manage_woocommerce',
'edit_posts' => 'manage_woocommerce',
'edit_others_posts' => 'manage_woocommerce',
'delete_posts' => 'manage_woocommerce',
'delete_others_posts'=> 'manage_woocommerce',
'read_private_posts'=> 'manage_woocommerce',
'edit_post' => 'manage_woocommerce',
'delete_post' => 'manage_woocommerce',
'read_post' => 'manage_woocommerce',
),
'publicly_queryable' => false,
'exclude_from_search' => true,
'show_in_menu' => $show_in_menu,
@ -271,6 +282,17 @@ function woocommerce_post_type() {
'public' => true,
'show_ui' => true,
'capability_type' => 'post',
'capabilities' => array(
'publish_posts' => 'manage_woocommerce',
'edit_posts' => 'manage_woocommerce',
'edit_others_posts' => 'manage_woocommerce',
'delete_posts' => 'manage_woocommerce',
'delete_others_posts'=> 'manage_woocommerce',
'read_private_posts'=> 'manage_woocommerce',
'edit_post' => 'manage_woocommerce',
'delete_post' => 'manage_woocommerce',
'read_post' => 'manage_woocommerce',
),
'publicly_queryable' => true,
'exclude_from_search' => true,
'show_in_menu' => $show_in_menu,

View File

@ -59,7 +59,7 @@ if (!function_exists('woocommerce_template_loop_add_to_cart')) {
if( $_product->get_price() === '' && $_product->product_type!=='external') return;
if (!$_product->is_in_stock()) :
echo '<a href="'.get_permalink($post->ID).'" class="button">'.__('Read More', 'woothemes').'</a>';
echo '<a href="'.get_permalink($post->ID).'" class="button">'. apply_filters('out_of_stock_add_to_cart_text', __('Read More', 'woothemes')).'</a>';
return;
endif;
@ -119,13 +119,13 @@ if (!function_exists('woocommerce_show_product_images')) {
echo '<div class="images">';
$thumb_id = 0;
if (has_post_thumbnail()) :
$thumb_id = get_post_thumbnail_id();
$large_thumbnail_size = apply_filters('single_product_large_thumbnail_size', 'shop_single');
echo '<a href="'.wp_get_attachment_url($thumb_id).'" class="zoom" rel="thumbnails" title="'.get_the_title().'">';
the_post_thumbnail($large_thumbnail_size);
echo '</a>';
echo '<a itemprop="image" href="'.wp_get_attachment_url($thumb_id).'" class="zoom" rel="thumbnails">' . get_the_post_thumbnail($post->ID, $large_thumbnail_size) . '</a>';
else :
echo '<img src="'.$woocommerce->plugin_url().'/assets/images/placeholder.png" alt="Placeholder" />';
endif;
@ -210,13 +210,13 @@ if (!function_exists('woocommerce_output_product_data_tabs')) {
**/
if (!function_exists('woocommerce_template_single_price')) {
function woocommerce_template_single_price( $post, $_product ) {
?><p class="price"><?php echo $_product->get_price_html(); ?></p><?php
?><p itemprop="price" class="price"><?php echo $_product->get_price_html(); ?></p><?php
}
}
if (!function_exists('woocommerce_template_single_excerpt')) {
function woocommerce_template_single_excerpt( $post, $_product ) {
if ($post->post_excerpt) echo wpautop(wptexturize($post->post_excerpt));
if ($post->post_excerpt) echo '<div itemprop="description">' . wpautop(wptexturize($post->post_excerpt)) . '</div>';
}
}
@ -224,7 +224,7 @@ if (!function_exists('woocommerce_template_single_meta')) {
function woocommerce_template_single_meta( $post, $_product ) {
?>
<div class="product_meta"><?php if ($_product->is_type('simple') && get_option('woocommerce_enable_sku')=='yes') : ?><span class="sku"><?php _e('SKU:', 'woothemes'); ?> <?php echo $_product->sku; ?>.</span><?php endif; ?><?php echo $_product->get_categories( ', ', ' <span class="posted_in">'.__('Posted in', 'woothemes').' ', '.</span>'); ?><?php echo $_product->get_tags( ', ', ' <span class="tagged_as">'.__('Tagged as', 'woothemes').' ', '.</span>'); ?></div>
<div class="product_meta"><?php if ($_product->is_type('simple') && get_option('woocommerce_enable_sku')=='yes') : ?><span itemprop="productID" class="sku"><?php _e('SKU:', 'woothemes'); ?> <?php echo $_product->sku; ?>.</span><?php endif; ?><?php echo $_product->get_categories( ', ', ' <span class="posted_in">'.__('Posted in', 'woothemes').' ', '.</span>'); ?><?php echo $_product->get_tags( ', ', ' <span class="tagged_as">'.__('Tagged as', 'woothemes').' ', '.</span>'); ?></div>
<?php
}
@ -284,13 +284,21 @@ if (!function_exists('woocommerce_simple_add_to_cart')) {
// No price set - so no button
if( $_product->get_price() === '') return;
if ($availability['availability']) : ?><p class="stock <?php echo $availability['class'] ?>"><?php echo $availability['availability']; ?></p><?php endif;
if ($availability['availability']) : ?>
<p class="stock <?php echo $availability['class'] ?>"><?php echo $availability['availability']; ?></p>
<?php endif;
// Don't show cart if out of stock
if (!$_product->is_in_stock()) return;
if (!$_product->is_in_stock()) :
echo '<link itemprop="availability" href="http://schema.org/OutOfStock">';
return;
endif;
echo '<link itemprop="availability" href="http://schema.org/InStock">';
do_action('woocommerce_before_add_to_cart_form');
?>
<?php do_action('woocommerce_before_add_to_cart_form'); ?>
<form action="<?php echo esc_url( $_product->add_to_cart_url() ); ?>" class="cart" method="post">
<?php do_action('woocommerce_before_to_cart_button'); ?>
@ -304,9 +312,10 @@ if (!function_exists('woocommerce_simple_add_to_cart')) {
<?php do_action('woocommerce_after_add_to_cart_button'); ?>
</form>
<?php
do_action('woocommerce_after_add_to_cart_form');
<?php do_action('woocommerce_after_add_to_cart_form'); ?>
<?php
}
}
if (!function_exists('woocommerce_grouped_add_to_cart')) {
@ -721,6 +730,11 @@ if (!function_exists('woocommerce_cart_totals')) {
<td><?php echo $woocommerce->cart->get_cart_subtotal(); ?></td>
</tr>
<?php if ($woocommerce->cart->get_discounts_before_tax()) : ?><tr class="discount">
<th><?php _e('Product Discounts', 'woothemes'); ?></th>
<td>-<?php echo $woocommerce->cart->get_discounts_before_tax(); ?></td>
</tr><?php endif; ?>
<?php if ($woocommerce->cart->get_cart_shipping_total()) : ?><tr>
<th><?php _e('Shipping', 'woothemes'); ?> <small><?php echo $woocommerce->countries->shipping_to_prefix().' '.__($woocommerce->countries->countries[ $woocommerce->customer->get_shipping_country() ], 'woothemes'); ?></small></th>
<td>
@ -763,7 +777,7 @@ if (!function_exists('woocommerce_cart_totals')) {
?>
</td>
</tr><?php endif; ?>
<?php if ($woocommerce->cart->get_cart_tax()) : ?><tr>
<th><?php _e('Tax', 'woothemes'); ?> <?php if ($woocommerce->customer->is_customer_outside_base()) : ?><small><?php echo sprintf(__('estimated for %s', 'woothemes'), $woocommerce->countries->estimated_for_prefix() . __($woocommerce->countries->countries[ $woocommerce->countries->get_base_country() ], 'woothemes') ); ?></small><?php endif; ?></th>
<td><?php
@ -771,10 +785,11 @@ if (!function_exists('woocommerce_cart_totals')) {
?></td>
</tr><?php endif; ?>
<?php if ($woocommerce->cart->get_total_discount()) : ?><tr class="discount">
<?php if ($woocommerce->cart->get_discounts_after_tax()) : ?><tr class="discount">
<th><?php _e('Discount', 'woothemes'); ?></th>
<td>-<?php echo $woocommerce->cart->get_total_discount(); ?></td>
<td>-<?php echo $woocommerce->cart->get_discounts_after_tax(); ?></td>
</tr><?php endif; ?>
<tr>
<th><strong><?php _e('Total', 'woothemes'); ?></strong></th>
<td><strong><?php echo $woocommerce->cart->get_total(); ?></strong></td>
@ -1063,7 +1078,7 @@ function woocommerce_upsell_display() {
global $_product;
$upsells = $_product->get_upsells();
if (sizeof($upsells)>0) :
echo '<div class="upsells products"><h2>'.__('You may also like&hellip;', 'woothemes').'</h2><ul>';
echo '<div class="upsells products"><h2>'.__('You may also like&hellip;', 'woothemes').'</h2>';
$args = array(
'post_type' => 'product',
'ignore_sticky_posts' => 1,