woocommerce/includes/class-wc-discounts.php

243 lines
6.3 KiB
PHP
Raw Normal View History

2017-07-18 04:43:31 +00:00
<?php
/**
* Discount calculation
*
* @author Automattic
* @package WooCommerce/Classes
* @version 3.2.0
* @since 3.2.0
*/
/**
* Discounts class.
2017-07-18 19:48:19 +00:00
*
* @todo this class will need to be called instead get_discounted_price, in the cart?
2017-07-18 04:43:31 +00:00
*/
class WC_Discounts {
/**
2017-07-18 13:04:56 +00:00
* An array of items to discount.
2017-07-18 04:43:31 +00:00
*
2017-07-18 13:04:56 +00:00
* @var array
2017-07-18 04:43:31 +00:00
*/
2017-07-18 13:04:56 +00:00
protected $items = array();
2017-07-18 04:43:31 +00:00
2017-07-18 17:07:46 +00:00
/**
* An array of discounts which have been applied.
2017-07-18 17:07:46 +00:00
*
* @var array
*/
protected $discounts = array();
2017-07-18 17:07:46 +00:00
/**
* Reset items and discounts to 0.
2017-07-18 17:07:46 +00:00
*/
protected function reset() {
$this->items = array();
$this->discounts = array( 'cart' => 0 );
}
2017-07-18 17:07:46 +00:00
2017-07-18 04:43:31 +00:00
/**
2017-07-18 13:04:56 +00:00
* Get items.
2017-07-18 04:43:31 +00:00
*
2017-07-18 13:04:56 +00:00
* @since 3.2.0
* @return object[]
2017-07-18 04:43:31 +00:00
*/
2017-07-18 13:04:56 +00:00
public function get_items() {
return $this->items;
2017-07-18 04:43:31 +00:00
}
/**
2017-07-18 13:04:56 +00:00
* Set cart/order items which will be discounted.
2017-07-18 04:43:31 +00:00
*
2017-07-18 13:04:56 +00:00
* @since 3.2.0
2017-07-18 17:07:46 +00:00
* @param array $raw_items List of raw cart or order items.
2017-07-18 04:43:31 +00:00
*/
2017-07-18 13:04:56 +00:00
public function set_items( $raw_items ) {
$this->reset();
2017-07-18 17:47:05 +00:00
if ( ! empty( $raw_items ) && is_array( $raw_items ) ) {
foreach ( $raw_items as $raw_item ) {
$item = (object) array(
'price' => 0, // Line price without discounts.
'quantity' => 0, // Line qty.
'product' => false,
);
if ( is_a( $raw_item, 'WC_Cart_Item' ) ) {
//$item->quantity = $raw_item->get_quantity();
//$item->price = $raw_item->get_price() * $raw_item->get_quantity();
//$item->is_taxable = $raw_item->is_taxable();
//$item->tax_class = $raw_item->get_tax_class();
// @todo
} elseif ( is_a( $raw_item, 'WC_Order_Item_Product' ) ) {
$item->key = $raw_item->get_id();
$item->quantity = $raw_item->get_quantity();
$item->product = $raw_item->get_product();
} else {
$item->key = $raw_item['key'];
// @todo remove when we implement WC_Cart_Item. This is the old cart item schema.
$item->quantity = $raw_item['quantity'];
$item->price = $raw_item['data']->get_price() * $raw_item['quantity'];
$item->product = $raw_item['data'];
}
$this->items[ $item->key ] = $item;
$this->discounts[ $item->key ] = 0;
2017-07-18 13:04:56 +00:00
}
}
2017-07-18 04:43:31 +00:00
}
/**
2017-07-18 13:04:56 +00:00
* Get all discount totals.
2017-07-18 04:43:31 +00:00
*
2017-07-18 13:04:56 +00:00
* @since 3.2.0
* @return array
2017-07-18 04:43:31 +00:00
*/
2017-07-18 13:04:56 +00:00
public function get_discounts() {
return $this->discounts;
}
/**
* Get discount by key.
*
* @since 3.2.0
* @return array
*/
public function get_discount( $key ) {
return isset( $this->discounts[ $key ] ) ? $this->discounts[ $key ] : 0;
2017-07-18 04:43:31 +00:00
}
/**
2017-07-18 13:04:56 +00:00
* Apply a discount to all items using a coupon.
2017-07-18 04:43:31 +00:00
*
2017-07-18 13:04:56 +00:00
* @since 3.2.0
* @param WC_Coupon $coupon
* @return bool True if applied.
2017-07-18 04:43:31 +00:00
*/
2017-07-18 17:07:46 +00:00
public function apply_coupon( $coupon ) {
2017-07-18 13:04:56 +00:00
if ( ! is_a( $coupon, 'WC_Coupon' ) ) {
return false;
}
2017-07-18 19:48:19 +00:00
/* @todo add this logic here somewhere
if ( null === $this->get_limit_usage_to_x_items() ) {
$limit_usage_qty = $cart_item_qty;
} else {
$limit_usage_qty = min( $this->get_limit_usage_to_x_items(), $cart_item_qty );
$this->set_limit_usage_to_x_items( max( 0, ( $this->get_limit_usage_to_x_items() - $limit_usage_qty ) ) );
}
if ( $single ) {
$discount = ( $discount * $limit_usage_qty ) / $cart_item_qty;
} else {
$discount = ( $discount / $cart_item_qty ) * $limit_usage_qty;
}*/
// @todo how can we support the old woocommerce_coupon_get_discount_amount filter?
switch ( $coupon->get_discount_type() ) {
2017-07-18 17:07:46 +00:00
case 'percent' :
$this->apply_percentage_discount( $coupon->get_amount() );
2017-07-18 17:07:46 +00:00
break;
2017-07-18 17:47:05 +00:00
case 'fixed_product' :
$this->apply_fixed_product_discount( $coupon->get_amount() );
2017-07-18 17:47:05 +00:00
break;
case 'fixed_cart' :
$this->apply_fixed_cart_discount( $coupon->get_amount() );
2017-07-18 17:07:46 +00:00
break;
}
}
/**
* Get discounted price of an item.
2017-07-18 17:07:46 +00:00
*
* @since 3.2.0
* @param object $item
* @return float
2017-07-18 17:07:46 +00:00
*/
public function get_discounted_price( $item ) {
return $item->price - $this->discounts[ $item->key ];
2017-07-18 17:07:46 +00:00
}
/**
* Apply a discount amount to an item and ensure it does not go negative.
2017-07-18 17:47:05 +00:00
*
* @since 3.2.0
* @param object $item
* @param float $discount
* @return float
*/
protected function apply_discount_to_item( &$item, $discount ) {
$discounted_price = $this->get_discounted_price( $item );
$discount = $discount > $discounted_price ? $discounted_price : $discount;
$this->discounts[ $item->key ] = $this->discounts[ $item->key ] + $discount;
return $discount;
}
/**
* Apply a discount amount to the cart.
*
* @since 3.2.0
* @param object $item
* @param float $discount
*/
protected function apply_discount_to_cart( $discount ) {
$this->discounts['cart'] += $discount;
}
/**
* Apply percent discount to items.
*
* @since 3.2.0
2017-07-18 17:47:05 +00:00
* @param float $amount
*/
protected function apply_percentage_discount( $amount ) {
2017-07-18 17:47:05 +00:00
foreach ( $this->items as $item ) {
$this->apply_discount_to_item( $item, (float) $amount * ( $this->get_discounted_price( $item ) / 100 ) );
2017-07-18 17:47:05 +00:00
}
}
/**
* Apply fixed product discount to items.
2017-07-18 17:07:46 +00:00
*
* @since 3.2.0
2017-07-18 17:07:46 +00:00
* @param float $amount
*/
protected function apply_fixed_product_discount( $discount ) {
foreach ( $this->items as $item ) {
$this->apply_discount_to_item( $item, $discount * $item->quantity );
2017-07-18 17:07:46 +00:00
}
2017-07-18 04:43:31 +00:00
}
2017-07-18 17:52:50 +00:00
/*protected function filter_taxable_items( $item ) {
return $item->is_taxable;
}*/
2017-07-18 17:52:50 +00:00
/**
* Apply fixed cart discount to items. Cart discounts will be stored and
* displayed separately to items, and taxes will be apportioned.
2017-07-18 17:52:50 +00:00
*
* @since 3.2.0
* @param float $cart_discount
2017-07-18 17:52:50 +00:00
*/
protected function apply_fixed_cart_discount( $cart_discount ) {
// @todo Fixed cart discounts will be apportioned based on tax class.
/*$tax_class_counts = array_count_values( wp_list_pluck( array_filter( $this->items, array( $this, 'filter_taxable_items' ) ), 'tax_class' ) );
$item_count = array_sum( wp_list_pluck( $this->items, 'quantity' ) );
$cart_discount_taxes = array();
foreach ( $tax_class_counts as $tax_class => $tax_class_count ) {
$proportion = $tax_class_count / $item_count;
$cart_discount_proportion = $cart_discount * $proportion;
$tax_rates = WC_Tax::get_rates( $tax_class );
$cart_discount_taxes[ $tax_class ] = WC_Tax::calc_tax( $cart_discount_proportion, $tax_rates );
2017-07-18 17:52:50 +00:00
}
var_dump($cart_discount_taxes);*/
$this->apply_discount_to_cart( $cart_discount );
2017-07-18 17:52:50 +00:00
}
2017-07-18 04:43:31 +00:00
}