The best between the sale price and coupon discount
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 |
class ADP_WC_Coupon_Discount_Picker { private $cloned_cart; private $products_no_coupon_discount = array(); public function __construct() { add_filter( 'wdp_calculate_totals_hook_priority', array( $this, 'set_calculate_total_priority') ); add_action( 'woocommerce_after_calculate_totals', array( $this, 'set_cart_discount' ), PHP_INT_MAX, 1 ); add_filter( 'woocommerce_coupon_is_valid_for_product', array( $this, 'coupon_is_valid_for_product' ), 10, 4 ); } public function set_calculate_total_priority( $priority ) { return $priority - 1; } public function set_cart_discount( $cart ) { $this->cloned_cart = clone $cart; $context = new ADP\BaseVersion\Includes\Context(); $coupons = $this->cloned_cart->get_coupons(); $wc_coupons_discounts = array(); if ( empty( $coupons ) ) { return; } $this->sanitize( $this->cloned_cart, $context ); $this->calc_totals( $this->cloned_cart ); foreach ( $coupons as $coupon ) { $adp_cart_total_discount = 0; foreach( $this->cloned_cart->cart_contents as $hash => $item ) { $item_facade = new ADP\BaseVersion\Includes\External\WC\WcCartItemFacade( $context, $item ); $wc_coupons_discounts[ $hash ] = $this->get_discounts_applied_by_wc_coupons( $coupons, $item_facade, $item ); $adp_item_total_discount = $this->get_adp_item_total_discount( $item_facade ); $adp_cart_total_discount += $adp_item_total_discount; if ( ! $coupon->is_type('fixed_cart') && $wc_coupons_discounts[ $hash ]['coupon_total_discount'] > $adp_item_total_discount ) { if ( $adp_item_total_discount ) { if ( empty( $price = $item_facade->getProduct()->get_sale_price('edit') ) ) { $price = $item_facade->getOriginalPrice(); } $cart->cart_contents[ $hash ]['data']->set_price( $price ); } } else { $this->products_no_coupon_discount[] = $item_facade->getProductId(); } } if ( $coupon->is_type('fixed_cart') ) { $wc_coupons_total_discounts = round( array_reduce( $wc_coupons_discounts, function( $carry, $item ) { return $carry + $item['coupon_total_discount']; } ) ); if ( $adp_cart_total_discount > $wc_coupons_total_discounts ) { add_filter( 'woocommerce_coupon_is_valid_for_cart', '__return_false' ); } else { $this->reset_cart( $cart ); } } } $wcNoFilterWorker = new ADP\BaseVersion\Includes\External\WC\WcNoFilterWorker(); $wcNoFilterWorker->calculateTotals( $cart ); } private function reset_cart( WC_Cart $wc_cart ) { foreach ( $wc_cart->cart_contents as $hash => &$item ) { $item['data']->set_price( $this->cloned_cart->cart_contents[ $hash ]['data']->get_price() ); } unset( $item ); } public function coupon_is_valid_for_product( $valid, $product, $discount_obj, $values ) { if ( in_array( $product->get_id(), $this->products_no_coupon_discount ) ) { return false; } return $valid; } /** * Set price */ private function sanitize( WC_Cart $cart, ADP\BaseVersion\Includes\Context $context ) { foreach( $cart->cart_contents as $h => &$i ) { $item_facade = new ADP\BaseVersion\Includes\External\WC\WcCartItemFacade( $context, $i ); $item_facade->sanitize(); $i['data'] = $item_facade->getProduct(); } unset( $i ); } private function calc_totals( WC_Cart $wc_cart ) { new WC_Cart_Totals( $wc_cart ); } /** * Method returns the summ of discounts apllied by rules to the item * * @param ADP\BaseVersion\Includes\External\WC\WcCartItemFacade $item * @return int */ private function get_adp_item_total_discount( ADP\BaseVersion\Includes\External\WC\WcCartItemFacade $item ) { $itemTotalAdpDiscount = 0; $itemAdpDiscounts = $item->getDiscounts(); if ( ! empty( $itemAdpDiscounts ) ) { $itemTotalAdpDiscount = array_sum( array_map( function ( $amounts ) { return array_sum( $amounts ); }, $item->getDiscounts() ) ); } return $itemTotalAdpDiscount * $item->getQty(); } /** * Returns array with info about discounts. * $items_discounts['coupon_total_discount'] holds the summ of all discounts applied to cart item * $items_discounts['coupon_discount_info'] holds data of each discount applied to cart item * * @param array $coupons * @param ADP\BaseVersion\Includes\External\WC\WcCartItemFacade $item * @param array $wc_item_data Data of single item from cart */ private function get_discounts_applied_by_wc_coupons( array $coupons, ADP\BaseVersion\Includes\External\WC\WcCartItemFacade $item, array $wc_item_data ) :array { $items_discounts = array(); foreach( $coupons as $c ) { $facade_discount = new ADP_WC_Coupon_Facade( $c, $this->cloned_cart ); $singleCouponDiscount = $facade_discount->get_discount_amount( $item->getOriginalPrice(), $wc_item_data, true ) * $item->getQty(); if ( ! isset( $items_discounts['coupon_total_discount'] ) ) { $items_discounts['coupon_total_discount'] = 0; } $items_discounts['coupon_total_discount'] += $singleCouponDiscount; $items_discounts['coupon_discount_info'][ $c->get_code() ] = $singleCouponDiscount; } return $items_discounts; } } class ADP_WC_Coupon_Facade { private $cart; private $coupon; private static $coupon_static; public function __construct( WC_Coupon $coupon, WC_Cart $cart = null ) { if ( ! isset( $cart ) ) { $cart = WC()->cart; } $this->cart = $cart; $this->coupon = $coupon; self::$coupon_static = $coupon; } public function __call( $name, $arguments ) { return $this->coupon->$name( ...$arguments ); } public static function __callStatic( $name, $arguments ){ return self::$coupon_static::$name( ...$arguments ); } public function get_discount_amount( $discounting_amount, $cart_item = null, $single = false ) { $discount = 0; $cart_item_qty = is_null( $cart_item ) ? 1 : $cart_item['quantity']; if ( $this->is_type( array( 'percent' ) ) ) { $discount = (float) $this->get_amount() * ( $discounting_amount / 100 ); } elseif ( $this->is_type( 'fixed_cart' ) && ! is_null( $cart_item ) && $this->cart->subtotal_ex_tax ) { /** * 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 discounted. * * Get item discount by dividing item cost by subtotal to get a %. * * Uses price inc tax if prices include tax to work around https://github.com/woocommerce/woocommerce/issues/7669 and https://github.com/woocommerce/woocommerce/issues/8074. */ if ( wc_prices_include_tax() ) { $discount_percent = ( wc_get_price_including_tax( $cart_item['data'] ) * $cart_item_qty ) / $this->cart->subtotal; } else { $discount_percent = ( wc_get_price_excluding_tax( $cart_item['data'] ) * $cart_item_qty ) / $this->cart->subtotal_ex_tax; } $discount = ( (float) $this->get_amount() * $discount_percent ) / $cart_item_qty; } elseif ( $this->is_type( 'fixed_product' ) ) { $discount = min( $this->get_amount(), $discounting_amount ); $discount = $single ? $discount : $discount * $cart_item_qty; } return apply_filters( 'woocommerce_coupon_get_discount_amount', round( min( $discount, $discounting_amount ), wc_get_rounding_precision() ), $discounting_amount, $cart_item, $single, $this ); } } new ADP_WC_Coupon_Discount_Picker(); |