initial implementation of order items taxes

This commit is contained in:
claudiosmweb 2014-07-19 01:08:02 -03:00
parent 50113fa531
commit 93cf3c88bd
11 changed files with 137 additions and 136 deletions

File diff suppressed because one or more lines are too long

View File

@ -766,6 +766,9 @@ ul.wc_coupon_list_block {
font-size: 1em;
}
}
th.line_tax {
white-space: nowrap;
}
.quantity {
text-align: center;
input {

View File

@ -123,6 +123,17 @@ abstract class WC_Abstract_Order {
wc_add_order_item_meta( $item_id, '_line_subtotal_tax', wc_format_decimal( isset( $args['totals']['subtotal_tax'] ) ? $args['totals']['subtotal_tax'] : 0 ) );
wc_add_order_item_meta( $item_id, '_line_tax', wc_format_decimal( isset( $args['totals']['tax'] ) ? $args['totals']['tax'] : 0 ) );
// Save tax data - Since 2.2
if ( isset( $args['totals']['tax_data'] ) ) {
$tax_data = array();
$tax_data['total'] = array_map( 'wc_format_decimal', $args['totals']['tax_data']['total'] );
$tax_data['subtotal'] = array_map( 'wc_format_decimal', $args['totals']['tax_data']['subtotal'] );
wc_add_order_item_meta( $item_id, '_line_tax_data', $tax_data );
} else {
wc_add_order_item_meta( $item_id, '_line_tax_data', array( 'total' => array(), 'subtotal' => array() ) );
}
// Add variation meta
if ( ! empty( $args['variation'] ) ) {
foreach ( $args['variation'] as $key => $value ) {

View File

@ -18,41 +18,6 @@ if ( ! defined( 'ABSPATH' ) ) {
</div>
</td>
<?php if ( 'yes' == get_option( 'woocommerce_calc_taxes' ) ) :
$tax_classes = array_filter( array_map( 'trim', explode( "\n", get_option( 'woocommerce_tax_classes' ) ) ) );
$classes_options = array();
$classes_options[''] = __( 'Standard', 'woocommerce' );
$tax_class = isset( $item['tax_class'] ) ? sanitize_title( $item['tax_class'] ) : '';
if ( $tax_classes ) {
foreach ( $tax_classes as $class ) {
$classes_options[ sanitize_title( $class ) ] = $class;
}
}
?>
<td class="tax_class" width="1%">
<div class="view">
<?php
$item_value = isset( $classes_options[ $tax_class ] ) ? esc_attr( $classes_options[ $tax_class ] ) : '';
echo $item_value ? $item_value : __( 'Standard', 'woocommerce' );
?>
</div>
<div class="edit" style="display:none">
<select class="tax_class" name="order_item_tax_class[<?php echo absint( $item_id ); ?>]" title="<?php _e( 'Tax class', 'woocommerce' ); ?>">
<option value="0" <?php selected( 0, $tax_class ) ?>><?php _e( 'N/A', 'woocommerce' ); ?></option>
<optgroup label="<?php _e( 'Taxable', 'woocommerce' ); ?>">
<?php
foreach ( $classes_options as $value => $name ) {
echo '<option value="' . esc_attr( $value ) . '" ' . selected( $value, $tax_class, false ) . '>'. esc_html( $name ) . '</option>';
}
?>
</optgroup>
</select>
</div>
</td>
<?php endif; ?>
<td class="quantity" width="1%">1</td>
<td class="line_cost" width="1%">
@ -64,6 +29,8 @@ if ( ! defined( 'ABSPATH' ) ) {
</div>
</td>
<?php if ( 'yes' == get_option( 'woocommerce_calc_taxes' ) ) : ?>
<td class="line_tax" width="1%">

View File

@ -95,7 +95,7 @@ if ( ! defined( 'ABSPATH' ) ) {
}
?>
</div>
<div class="edit" style="display:none">
<div class="edit" style="display: none;">
<table class="meta" cellspacing="0">
<tfoot>
<tr>
@ -147,42 +147,11 @@ if ( ! defined( 'ABSPATH' ) ) {
<?php do_action( 'woocommerce_admin_order_item_values', $_product, $item, absint( $item_id ) ); ?>
<?php if ( 'yes' == get_option( 'woocommerce_calc_taxes' ) ) :
$tax_classes = array_filter( array_map( 'trim', explode( "\n", get_option('woocommerce_tax_classes' ) ) ) );
$classes_options = array();
$classes_options[''] = __( 'Standard', 'woocommerce' );
if ( $tax_classes ) {
foreach ( $tax_classes as $class ) {
$classes_options[ sanitize_title( $class ) ] = $class;
}
}
?>
<td class="tax_class" width="1%">
<div class="view">
<?php
$item_value = isset( $item['tax_class'] ) ? sanitize_title( $item['tax_class'] ) : '';
echo $classes_options[ $item_value ];
?>
</div>
<div class="edit" style="display:none">
<select class="tax_class" name="order_item_tax_class[<?php echo absint( $item_id ); ?>]" title="<?php _e( 'Tax class', 'woocommerce' ); ?>">
<?php
$item_value = isset( $item['tax_class'] ) ? sanitize_title( $item['tax_class'] ) : '';
foreach ( $classes_options as $value => $name )
echo '<option value="' . esc_attr( $value ) . '" ' . selected( $value, $item_value, false ) . '>' . esc_html( $name ) . '</option>';
?>
</select>
</div>
</td>
<?php endif; ?>
<td class="quantity" width="1%">
<div class="view">
<?php echo ( isset( $item['qty'] ) ) ? esc_html( $item['qty'] ) : ''; ?>
</div>
<div class="edit" style="display:none">
<div class="edit" style="display: none;">
<input type="number" step="<?php echo apply_filters( 'woocommerce_quantity_input_step', '1', $_product ); ?>" min="0" autocomplete="off" name="order_item_qty[<?php echo absint( $item_id ); ?>]" placeholder="0" value="<?php echo esc_attr( $item['qty'] ); ?>" size="4" class="quantity" />
</div>
</td>
@ -199,37 +168,47 @@ if ( ! defined( 'ABSPATH' ) ) {
}
?>
</div>
<div class="edit" style="display:none">
<div class="edit" style="display: none;">
<span class="subtotal"><label><?php _e( 'Subtotal', 'woocommerce' ); ?>: <a class="tips" data-tip="<?php _e( 'Before pre-tax discounts.', 'woocommerce' ); ?>" href="#">[?]</a> <input type="text" name="line_subtotal[<?php echo absint( $item_id ); ?>]" placeholder="<?php echo wc_format_localized_price( 0 ); ?>" value="<?php echo ( isset( $item['line_subtotal'] ) ) ? esc_attr( wc_format_localized_price( $item['line_subtotal'] ) ) : ''; ?>" class="line_subtotal wc_input_price" /></label></span>
<label><?php _e( 'Total', 'woocommerce' ); ?>: <a class="tips" data-tip="<?php _e( 'After pre-tax discounts.', 'woocommerce' ); ?>" href="#">[?]</a> <input type="text" name="line_total[<?php echo absint( $item_id ); ?>]" placeholder="<?php echo wc_format_localized_price( 0 ); ?>" value="<?php echo ( isset( $item['line_total'] ) ) ? esc_attr( wc_format_localized_price( $item['line_total'] ) ) : ''; ?>" class="line_total wc_input_price" /></label>
</div>
</td>
<?php if ( 'yes' == get_option( 'woocommerce_calc_taxes' ) ) : ?>
<?php
if ( 'yes' == get_option( 'woocommerce_calc_taxes' ) ) :
$tax_data = maybe_unserialize( $item['line_tax_data'] );
foreach ( $order_taxes as $tax_item ) :
$tax_item_id = $tax_item['rate_id'];
$tax_item_total = isset( $tax_data['total'][ $tax_item_id ] ) ? $tax_data['total'][ $tax_item_id ] : '';
$tax_item_subtotal = isset( $tax_data['subtotal'][ $tax_item_id ] ) ? $tax_data['subtotal'][ $tax_item_id ] : '';
?>
<td class="line_tax" width="1%">
<div class="view">
<?php
if ( isset( $item['line_tax'] ) ) {
if ( isset( $item['line_subtotal_tax'] ) && $item['line_subtotal_tax'] != $item['line_tax'] ) {
echo '<del>' . wc_price( wc_round_tax_total( $item['line_subtotal_tax'] ) ) . '</del> ';
}
<td class="line_tax" width="1%">
<div class="view">
<?php
if ( '' != $tax_item_total ) {
if ( isset( $tax_item_subtotal ) && $tax_item_subtotal != $tax_item_total ) {
echo '<del>' . wc_price( wc_round_tax_total( $tax_item_subtotal ) ) . '</del> ';
}
echo wc_price( wc_round_tax_total( $item['line_tax'] ) );
}
?>
</div>
<div class="edit" style="display:none">
<span class="subtotal"><input type="text" name="line_subtotal_tax[<?php echo absint( $item_id ); ?>]" placeholder="<?php echo wc_format_localized_price( 0 ); ?>" value="<?php echo ( isset( $item['line_subtotal_tax'] ) ) ? esc_attr( wc_format_localized_price( $item['line_subtotal_tax'] ) ) : ''; ?>" class="line_subtotal_tax wc_input_price" /></span>
echo wc_price( wc_round_tax_total( $tax_item_total ) );
}
?>
</div>
<div class="edit" style="display: none;">
<span class="subtotal"><input type="text" name="line_subtotal_tax[<?php echo absint( $item_id ); ?>][<?php echo absint( $tax_item_id ); ?>]" placeholder="<?php echo wc_format_localized_price( 0 ); ?>" value="<?php echo ( isset( $tax_item_subtotal ) ) ? esc_attr( wc_format_localized_price( $tax_item_subtotal ) ) : ''; ?>" class="line_subtotal_tax wc_input_price" /></span>
<input type="text" name="line_tax[<?php echo absint( $item_id ); ?>]" placeholder="<?php echo wc_format_localized_price( 0 ); ?>" value="<?php echo ( isset( $item['line_tax'] ) ) ? esc_attr( wc_format_localized_price( $item['line_tax'] ) ) : ''; ?>" class="line_tax wc_input_price" />
</div>
</td>
<input type="text" name="line_tax[<?php echo absint( $item_id ); ?>][<?php echo absint( $tax_item_id ); ?>]" placeholder="<?php echo wc_format_localized_price( 0 ); ?>" value="<?php echo ( isset( $tax_item_total ) ) ? esc_attr( wc_format_localized_price( $tax_item_total ) ) : ''; ?>" class="line_tax wc_input_price" />
</div>
</td>
<?php endif; ?>
<?php
endforeach;
endif;
?>
<td class="wc-order-item-refund-quantity" width="1%" style="display:none">
<td class="wc-order-item-refund-quantity" width="1%" style="display: none;">
<input type="number" step="<?php echo apply_filters( 'woocommerce_quantity_input_step', '1', $_product ); ?>" min="0" max="<?php echo esc_attr( $item['qty'] ); ?>" autocomplete="off" name="order_item_refund_qty[<?php echo absint( $item_id ); ?>]" placeholder="0" size="4" class="quantity" />
</td>

View File

@ -2,6 +2,20 @@
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly
}
if ( 'yes' == get_option( 'woocommerce_calc_taxes' ) ) {
$order_taxes = $order->get_taxes();
$tax_classes = array_filter( array_map( 'trim', explode( "\n", get_option( 'woocommerce_tax_classes' ) ) ) );
$classes_options = array();
$classes_options[''] = __( 'Standard', 'woocommerce' );
if ( $tax_classes ) {
foreach ( $tax_classes as $class ) {
$classes_options[ sanitize_title( $class ) ] = $class;
}
}
}
?>
<div class="woocommerce_order_items_wrapper wc-order-items-editable">
<table cellpadding="0" cellspacing="0" class="woocommerce_order_items">
@ -12,19 +26,27 @@ if ( ! defined( 'ABSPATH' ) ) {
<?php do_action( 'woocommerce_admin_order_item_headers' ); ?>
<?php if ( get_option( 'woocommerce_calc_taxes' ) == 'yes' ) : ?>
<th class="tax_class"><?php _e( 'Tax&nbsp;Class', 'woocommerce' ); ?></th>
<?php endif; ?>
<th class="quantity"><?php _e( 'Qty', 'woocommerce' ); ?></th>
<th class="line_cost"><?php _e( 'Total', 'woocommerce' ); ?></th>
<?php if ( get_option( 'woocommerce_calc_taxes' ) == 'yes' ) : ?>
<th class="line_tax"><?php _e( 'Tax', 'woocommerce' ); ?></th>
<?php endif; ?>
<?php
if ( 'yes' == get_option( 'woocommerce_calc_taxes' ) ) :
foreach ( $order_taxes as $tax_item ) :
$tax_class = wc_get_tax_class_by_tax_id( $tax_item['rate_id'] );
$tax_class_name = isset( $classes_options[ $tax_class ] ) ? $classes_options[ $tax_class ] : __( 'Tax', 'woocommerce' );
?>
<th class="wc-order-item-refund-quantity" style="display:none"><?php _e( 'Refund', 'woocommerce' ); ?></th>
<th class="line_tax"><?php echo esc_attr( $tax_class_name ); ?> <span class="tips" data-tip="<?php
echo esc_attr( $tax_item['label'] . ' (' . $tax_item['name'] . ')' );
?>">[?]</span></th>
<?php
endforeach;
endif;
?>
<th class="wc-order-item-refund-quantity" style="display: none;"><?php _e( 'Refund', 'woocommerce' ); ?></th>
<th class="wc-order-edit-line-item" width="1%">&nbsp;</th>
</tr>
@ -37,7 +59,6 @@ if ( ! defined( 'ABSPATH' ) ) {
$shipping_methods = WC()->shipping() ? WC()->shipping->load_shipping_methods() : array();
foreach ( $order_items as $item_id => $item ) {
switch ( $item['type'] ) {
case 'line_item' :
$_product = $order->get_product_from_item( $item );
@ -137,6 +158,9 @@ if ( ! defined( 'ABSPATH' ) ) {
<button type="button" class="button add-order-item"><?php _e( 'Add product(s)', 'woocommerce' ); ?></button>
<button type="button" class="button add-order-fee"><?php _e( 'Add fee', 'woocommerce' ); ?></button>
<button type="button" class="button add-order-shipping"><?php _e( 'Add shipping cost', 'woocommerce' ); ?></button>
<?php if ( 'yes' == get_option( 'woocommerce_calc_taxes' ) ) : ?>
<button type="button" class="button add-order-tax"><?php _e( 'Add Tax', 'woocommerce' ); ?></button>
<?php endif; ?>
<button type="button" class="button cancel-action"><?php _e( 'Cancel', 'woocommerce' ); ?></button>
<button type="button" class="button button-primary save-action"><?php _e( 'Save', 'woocommerce' ); ?></button>
</div>

View File

@ -31,12 +31,6 @@ if ( ! defined( 'ABSPATH' ) ) {
<input type="hidden" class="order_refund_id" name="order_refund_id[]" value="<?php echo esc_attr( $refund->id ); ?>" />
</td>
<?php if ( 'yes' == get_option( 'woocommerce_calc_taxes' ) ) : ?>
<td class="tax_class" width="1%"></td>
<?php endif; ?>
<td class="quantity" width="1%">1</td>
<td class="line_cost" width="1%">

View File

@ -43,12 +43,6 @@ if ( ! defined( 'ABSPATH' ) ) {
</div>
</td>
<?php if ( 'yes' == get_option( 'woocommerce_calc_taxes' ) ) : ?>
<td class="tax_class" width="1%"></td>
<?php endif; ?>
<td class="quantity" width="1%">1</td>
<td class="line_cost" width="1%">
@ -60,11 +54,17 @@ if ( ! defined( 'ABSPATH' ) ) {
</div>
</td>
<?php if ( 'yes' == get_option( 'woocommerce_calc_taxes' ) ) : ?>
<?php
if ( 'yes' == get_option( 'woocommerce_calc_taxes' ) ) :
for ( $i = 0; $i < count( $order_taxes ); $i++ ) :
?>
<td class="line_tax" width="1%"></td>
<td class="line_tax" width="1%"></td>
<?php endif; ?>
<?php
endfor;
endif;
?>
<td class="wc-order-item-refund-quantity" width="1%" style="display:none"></td>

View File

@ -93,7 +93,7 @@ class WC_Cart {
$this->dp = absint( get_option( 'woocommerce_price_num_decimals' ) );
$this->display_totals_ex_tax = $this->tax_display_cart == 'excl';
$this->display_cart_ex_tax = $this->tax_display_cart == 'excl';
// Array of data the cart calculates and stores in the session with defaults
$this->cart_session_data = array(
'cart_contents_total' => 0,
@ -334,7 +334,7 @@ class WC_Cart {
// Check item stock
$result = $this->check_cart_item_stock();
if ( is_wp_error( $result ) ) {
if ( is_wp_error( $result ) ) {
wc_add_notice( $result->get_error_message(), 'error' );
}
}
@ -804,10 +804,10 @@ class WC_Cart {
// Load cart item data - may be added by other plugins
$cart_item_data = (array) apply_filters( 'woocommerce_add_cart_item_data', $cart_item_data, $product_id, $variation_id );
// 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 );
// See if this product and its options is already in the cart
$cart_item_key = $this->find_product_in_cart( $cart_id );
@ -816,7 +816,7 @@ class WC_Cart {
$variation_id = $product_id;
$product_id = wp_get_post_parent_id( $variation_id );
}
// Get the product
$product_data = get_product( $variation_id ? $variation_id : $product_id );
@ -1001,7 +1001,7 @@ class WC_Cart {
// Prices
$base_price = $_product->get_price();
$line_price = $_product->get_price() * $values['quantity'];
$line_subtotal = 0;
$line_subtotal_tax = 0;
@ -1100,6 +1100,10 @@ class WC_Cart {
$base_price = $_product->get_price();
$line_price = $_product->get_price() * $values['quantity'];
// Tax data
$taxes = array();
$discounted_taxes = array();
/**
* No tax to calculate
*/
@ -1204,10 +1208,13 @@ class WC_Cart {
$this->cart_contents_total += $line_total;
// Store costs + taxes for lines
$this->cart_contents[ $cart_item_key ]['line_total'] = $line_total;
$this->cart_contents[ $cart_item_key ]['line_tax'] = $line_tax;
$this->cart_contents[ $cart_item_key ]['line_subtotal'] = $line_subtotal;
$this->cart_contents[ $cart_item_key ]['line_total'] = $line_total;
$this->cart_contents[ $cart_item_key ]['line_tax'] = $line_tax;
$this->cart_contents[ $cart_item_key ]['line_subtotal'] = $line_subtotal;
$this->cart_contents[ $cart_item_key ]['line_subtotal_tax'] = $line_subtotal_tax;
// Store rates ID and costs - Since 2.2
$this->cart_contents[ $cart_item_key ]['line_tax_data'] = array( 'total' => $taxes, 'subtotal' => $discounted_taxes );
}
// Only calculate the grand total + shipping if on the cart/checkout
@ -1376,7 +1383,7 @@ class WC_Cart {
/**
* Should the shipping address form be shown
*
*
* @return bool
*/
function needs_shipping_address() {
@ -1523,7 +1530,7 @@ class WC_Cart {
$usage_count = 0;
}
}
foreach ( $check_emails as $check_email ) {
$usage_count = $usage_count + sizeof( array_keys( $used_by, $check_email ) );
}
@ -1909,7 +1916,7 @@ class WC_Cart {
// Get tax rates
$tax_rates = $this->tax->get_rates( $fee->tax_class );
$fee_taxes = $this->tax->calc_tax( $fee->amount, $tax_rates, false );
if ( ! empty( $fee_taxes ) ) {
// Set the tax total for this fee
$this->fees[ $fee_key ]->tax = array_sum( $fee_taxes );

View File

@ -204,16 +204,17 @@ class WC_Checkout {
// Store the line items to the new/resumed order
foreach ( WC()->cart->get_cart() as $cart_item_key => $values ) {
$item_id = $order->add_product(
$values['data'],
$values['quantity'],
$item_id = $order->add_product(
$values['data'],
$values['quantity'],
array(
'variation' => $values['variation'],
'totals' => array(
'subtotal' => $values['line_subtotal'],
'subtotal_tax' => $values['line_subtotal_tax'],
'total' => $values['line_total'],
'tax' => $values['line_tax']
'tax' => $values['line_tax'],
'tax_data' => $values['line_tax_data'] // Since 2.2
)
)
);
@ -233,7 +234,7 @@ class WC_Checkout {
if ( ! $item_id ) {
throw new Exception( __( 'Error: Unable to create order. Please try again.', 'woocommerce' ) );
}
// Allow plugins to add order item meta to fees
do_action( 'woocommerce_add_order_fee_meta', $order_id, $item_id, $fee, $fee_key );
}
@ -246,7 +247,7 @@ class WC_Checkout {
if ( ! $item_id ) {
throw new Exception( __( 'Error: Unable to create order. Please try again.', 'woocommerce' ) );
}
// Allows plugins to add order item meta to shipping
do_action( 'woocommerce_add_shipping_order_item', $order_id, $item_id, $package_key );
}
@ -517,7 +518,7 @@ class WC_Checkout {
if ( WC()->cart->needs_shipping() ) {
if ( ! in_array( WC()->customer->get_shipping_country(), array_keys( WC()->countries->get_shipping_countries() ) ) )
if ( ! in_array( WC()->customer->get_shipping_country(), array_keys( WC()->countries->get_shipping_countries() ) ) )
wc_add_notice( sprintf( __( 'Unfortunately <strong>we do not ship %s</strong>. Please enter an alternative shipping address.', 'woocommerce' ), WC()->countries->shipping_to_prefix() . ' ' . WC()->customer->get_shipping_country() ), 'error' );
// Validate Shipping Methods
@ -571,15 +572,15 @@ class WC_Checkout {
// As we are now logged in, checkout will need to refresh to show logged in data
WC()->session->set( 'reload_checkout', true );
// Also, recalculate cart totals to reveal any role-based discounts that were unavailable before registering
WC()->cart->calculate_totals();
// Add customer info from other billing fields
if ( $this->posted['billing_first_name'] && apply_filters( 'woocommerce_checkout_update_customer_data', true, $this ) ) {
$userdata = array(
'ID' => $this->customer_id,
'first_name' => $this->posted['billing_first_name'] ? $this->posted['billing_first_name'] : '',
$userdata = array(
'ID' => $this->customer_id,
'first_name' => $this->posted['billing_first_name'] ? $this->posted['billing_first_name'] : '',
'last_name' => $this->posted['billing_last_name'] ? $this->posted['billing_last_name'] : '',
'display_name' => $this->posted['billing_first_name'] ? $this->posted['billing_first_name'] : ''
);

View File

@ -570,3 +570,18 @@ function wc_create_refund( $args = array() ) {
return new WC_Order_Refund( $refund_id );
}
/**
* Get tax class by tax id.
*
* @since 2.2
* @param int $tax_id
* @return string
*/
function wc_get_tax_class_by_tax_id( $tax_id ) {
global $wpdb;
$tax_class = $wpdb->get_var( $wpdb->prepare( "SELECT tax_rate_class FROM {$wpdb->prefix}woocommerce_tax_rates WHERE tax_rate_id = %d", $tax_id ) );
return wc_clean( $tax_class );
}