woocommerce/includes/class-wc-discounts.php

207 lines
4.7 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.
*/
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 coupons which have been applied.
*
* @var array
*/
protected $coupons = array();
/**
* An array of discounts which have been applied.
*
* @var array
*/
protected $discounts = array();
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 ) {
2017-07-18 17:47:05 +00:00
$this->items = array();
if ( ! empty( $raw_items ) && is_array( $raw_items ) ) {
foreach ( $raw_items as $raw_item ) {
$item = (object) array(
2017-07-18 17:07:46 +00:00
'price' => 0, // Unit price without discounts.
'discounted_price' => 0, // Unit price with discounts.
'quantity' => 0, // Line qty.
);
2017-07-18 04:43:31 +00:00
if ( is_a( $raw_item, 'WC_Cart_Item' ) ) {
$item->quantity = $raw_item->get_quantity();
$item->price = $raw_item->get_price();
} elseif ( is_a( $raw_item, 'WC_Order_Item_Product' ) ) {
$item->quantity = $raw_item->get_quantity();
$item->price = $raw_item->get_subtotal();
} else {
// @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();
}
2017-07-18 04:43:31 +00:00
2017-07-18 17:07:46 +00:00
$item->discounted_price = $item->price;
$this->items[] = $item;
2017-07-18 13:04:56 +00:00
}
}
2017-07-18 04:43:31 +00:00
}
2017-07-18 17:07:46 +00:00
public function get_discounted_totals() {}
public function get_applied_discounts() {}
public function get_applied_coupons() {}
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 array(
'items',
'discount_totals' => array(
// 'code' => 'amount'
)
);
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 17:07:46 +00:00
$items = $this->get_items();
$type = $coupon->get_discount_type();
$amount = $coupon->get_amount();
switch ( $type ) {
case 'percent' :
$this->apply_percentage_discount( $amount );
break;
2017-07-18 17:47:05 +00:00
case 'fixed_product' :
$this->apply_fixed_product_discount( $amount );
break;
case 'fixed_cart' :
$this->apply_fixed_cart_discount( $amount );
2017-07-18 17:07:46 +00:00
break;
}
}
/**
* Apply percent discount to items.
*
* @param float $amount
*/
private function apply_percentage_discount( $amount ) {
foreach ( $this->items as $item ) {
$discount = (float) $amount * ( $item->discounted_price / 100 );
$item->discounted_price -= $discount;
$item->discounted_price = max( 0, $item->discounted_price );
}
}
/**
2017-07-18 17:47:05 +00:00
* Apply fixed product discount to items.
*
* @param float $amount
*/
private function apply_fixed_product_discount( $discount ) {
foreach ( $this->items as $item ) {
$item->discounted_price -= $discount;
$item->discounted_price = max( 0, $item->discounted_price );
}
}
private function apply_discount_to_item( &$item, $discount ) {
if ( $discount > $item->discounted_price ) {
$discount = $item->discounted_price;
}
$item->discounted_price = $item->discounted_price - $discount;
return $discount;
}
/**
* Apply fixed cart discount to items.
2017-07-18 17:07:46 +00:00
*
* @param float $amount
*/
2017-07-18 17:47:05 +00:00
private function apply_fixed_cart_discount( $total_amount ) {
2017-07-18 17:07:46 +00:00
// Fixed amount needs to be divided equally between items.
$item_count = array_sum( wp_list_pluck( $this->items, 'quantity' ) );
$discount = floor( $total_amount / $item_count );
$discounted = 0; // Keep track of what actually gets discounted, since some products may be cheaper than the discount.
2017-07-18 17:47:05 +00:00
if ( 0 < $discount ) {
2017-07-18 17:07:46 +00:00
foreach ( $this->items as $item ) {
2017-07-18 17:47:05 +00:00
$discounted += $this->apply_discount_to_item( $item, $discount );
2017-07-18 17:07:46 +00:00
}
// Anything left?
2017-07-18 17:47:05 +00:00
if ( $discounted && ( $remaining_discount = $total_amount - $discounted ) ) {
$this->apply_fixed_cart_discount( $remaining_discount );
2017-07-18 17:07:46 +00:00
}
// Amount is too small to divide equally.
} elseif ( $total_amount ) {
$discount = $total_amount;
while ( $discount > 0 ) {
$did_discount = false;
foreach ( $this->items as $item ) {
if ( $item->discounted_price ) {
$item->discounted_price --;
$discount --;
$did_discount = true;
}
}
if ( ! $did_discount ) {
break;
}
}
}
2017-07-18 04:43:31 +00:00
}
}