PluginProbe
Tiered Pricing Table for WooCommerce / 7.1.4
Tiered Pricing Table for WooCommerce v7.1.4
8.0.2 7.1.7 7.1.5 7.1.4 7.1.1 6.5.0 6.4.0 6.1.0 trunk 1.0 1.1 2.0 2.0.1 2.0.2 2.1 2.1.1 2.1.2 2.2.0 2.2.1 2.2.2 2.2.3 2.3.0 2.3.1 2.3.2 2.3.3 All 91 releases
tier-pricing-table / src / Addons / TieredPricingCart / TieredPricingCartService.php

TieredPricingCartService.php in Tiered Pricing Table for WooCommerce 7.1.4, at src/Addons/TieredPricingCart/TieredPricingCartService.php

228 lines 9.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace TierPricingTable\Addons\TieredPricingCart;
4
5 /*
6 * Class TieredPricingCartService
7 *
8 * Service modifies product's price in the cart based on quantity and tiered pricing rules
9 *
10 * @package TierPricingTable\Addons\TieredPricingCart
11 */
12 use TierPricingTable\CalculationLogic;
13 use TierPricingTable\Core\ServiceContainerTrait;
14 use TierPricingTable\PriceManager;
15 use WC_Product;
16 use WC_Cart;
17 class TieredPricingCartService {
18 use ServiceContainerTrait;
19 protected $originalPrices = [];
20
21 public function __construct() {
22 add_action(
23 'woocommerce_before_calculate_totals',
24 array($this, 'calculateTieredPricingInCart'),
25 99999,
26 3
27 );
28 add_action(
29 'woocommerce_before_mini_cart_contents',
30 array($this, 'triggerMiniCartUpdate'),
31 9999,
32 3
33 );
34 add_filter(
35 'woocommerce_cart_item_price',
36 array($this, 'calculateCartItemPrice'),
37 999,
38 2
39 );
40 add_filter(
41 'woocommerce_cart_item_subtotal',
42 array($this, 'modifyCartItemSubtotal'),
43 999,
44 3
45 );
46 }
47
48 public function modifyCartItemSubtotal( $subtotal, $cartItem, $cartItemKey ) {
49 $newPrice = $this->getCartItemPrice( $cartItem, $cartItemKey );
50 if ( false === $newPrice ) {
51 return $subtotal;
52 }
53 $recalculateCartItemSubtotal = apply_filters(
54 'tiered_pricing_table/cart/recalculate_cart_item_subtotal',
55 true,
56 $cartItem,
57 $cartItemKey,
58 $subtotal
59 );
60 if ( !$recalculateCartItemSubtotal ) {
61 return $subtotal;
62 }
63 $considerSalePriceAsDiscount = $this->getContainer()->getSettings()->get( 'consider_sale_price_as_discount_in_cart', 'no' ) === 'yes';
64 $considerSalePriceAsDiscount = apply_filters(
65 'tiered_pricing_table/cart/subtotal/consider_sale_price_as_discount',
66 $considerSalePriceAsDiscount,
67 $cartItem,
68 $cartItemKey
69 );
70 // Reset product instance because prices is already modified in the "woocommerce_before_calculate_totals" hook.
71 // We will not be able to get the original price
72 $product = wc_get_product( $cartItem['data']->get_id() );
73 if ( $product->is_taxable() ) {
74 if ( wc()->cart->display_prices_including_tax() ) {
75 $originalCartItemPrice = wc_get_price_including_tax( $product, array(
76 'qty' => $cartItem['quantity'],
77 'price' => ( $considerSalePriceAsDiscount ? $product->get_regular_price() : $product->get_price() ),
78 ) );
79 $newCartItemPrice = wc_get_price_including_tax( $product, array(
80 'qty' => $cartItem['quantity'],
81 'price' => $newPrice,
82 ) );
83 $originalProductSubtotal = wc_price( $originalCartItemPrice );
84 $newProductSubtotal = wc_price( $newCartItemPrice );
85 if ( !wc_prices_include_tax() && wc()->cart->get_subtotal_tax() > 0 ) {
86 $newProductSubtotal .= ' <small class="tax_label">' . WC()->countries->inc_tax_or_vat() . '</small>';
87 }
88 } else {
89 $originalCartItemPrice = wc_get_price_excluding_tax( $product, array(
90 'qty' => $cartItem['quantity'],
91 'price' => ( $considerSalePriceAsDiscount ? $product->get_regular_price() : $product->get_price() ),
92 ) );
93 $newCartItemPrice = wc_get_price_excluding_tax( $product, array(
94 'qty' => $cartItem['quantity'],
95 'price' => $newPrice,
96 ) );
97 $originalProductSubtotal = wc_price( $originalCartItemPrice );
98 $newProductSubtotal = wc_price( $newCartItemPrice );
99 if ( wc_prices_include_tax() && wc()->cart->get_subtotal_tax() > 0 ) {
100 $newProductSubtotal .= ' <small class="tax_label">' . WC()->countries->ex_tax_or_vat() . '</small>';
101 }
102 }
103 } else {
104 $_originalItemPrice = ( $considerSalePriceAsDiscount ? $product->get_regular_price() : $product->get_price() );
105 $originalCartItemPrice = (float) $_originalItemPrice * (float) $cartItem['quantity'];
106 $newCartItemPrice = (float) $newPrice * (float) $cartItem['quantity'];
107 $originalProductSubtotal = wc_price( $originalCartItemPrice );
108 $newProductSubtotal = wc_price( $newCartItemPrice );
109 }
110 return $newProductSubtotal;
111 }
112
113 public function getCartItemPrice( $cartItem, $cartItemKey, $cart = null ) {
114 $cart = ( $cart instanceof WC_Cart ? $cart : wc()->cart );
115 if ( !$cart instanceof WC_Cart ) {
116 return false;
117 }
118 $calculateTieredPriceForItem = apply_filters(
119 'tiered_pricing_table/cart/need_price_recalculation',
120 true,
121 $cartItem,
122 $cart
123 );
124 if ( !$calculateTieredPriceForItem ) {
125 return false;
126 }
127 if ( empty( $cartItem['data'] ) || !$cartItem['data'] instanceof WC_Product ) {
128 return false;
129 }
130 $pricingRule = PriceManager::getPricingRule( $cartItem['data']->get_id() );
131 $totalQuantity = $this->getTotalProductCount( $cartItem );
132 $newPrice = $pricingRule->getTierPrice( $totalQuantity, false, 'cart' );
133 return apply_filters(
134 'tiered_pricing_table/cart/product_cart_price',
135 $newPrice,
136 $cartItem,
137 $cartItemKey,
138 $totalQuantity
139 );
140 }
141
142 /**
143 * Calculate price by quantity rules
144 *
145 * @param WC_Cart $cart
146 */
147 public function calculateTieredPricingInCart( WC_Cart $cart ) {
148 if ( !empty( $cart->get_cart_contents() ) ) {
149 foreach ( $cart->get_cart_contents() as $key => $cartItem ) {
150 $newPrice = $this->getCartItemPrice( $cartItem, $key, $cart );
151 if ( false !== $newPrice ) {
152 if ( !isset( $this->originalPrices[$key] ) ) {
153 // Store the raw price prop ("edit" context) on purpose. The "view" context runs the
154 // "woocommerce_product_get_price" filter, which both RegularPricingService and currency
155 // switchers hook into. Storing an already filtered value and restoring it with
156 // set_price() would apply those filters a second time.
157 $this->originalPrices[$key] = $cartItem['data']->get_price( 'edit' );
158 }
159 $cartItem['data']->set_price( $newPrice );
160 $cartItem['data']->add_meta_data( 'tiered_pricing_cart_price_calculated', 'yes' );
161 } else {
162 if ( isset( $this->originalPrices[$key] ) ) {
163 // Fully revert the modification: put the raw price prop back and drop the flag, so the
164 // "woocommerce_product_get_price" filters (role-based pricing, currency conversion)
165 // apply to the restored price exactly once, as they would have without this service.
166 $cartItem['data']->set_price( $this->originalPrices[$key] );
167 $cartItem['data']->delete_meta_data( 'tiered_pricing_cart_price_calculated' );
168 unset($this->originalPrices[$key]);
169 }
170 }
171 // Update tiered pricing data
172 $cart->cart_contents[$key]['tiered_pricing_data'] = array(
173 'total_item_quantity' => $this->getTotalProductCount( $cartItem ),
174 );
175 }
176 }
177 }
178
179 /**
180 * Calculate price in mini cart
181 *
182 * @param string $price
183 * @param array $cartItem
184 *
185 * @return string
186 */
187 public function calculateCartItemPrice( $price, $cartItem ) {
188 $calculateTieredPriceForItem = apply_filters( 'tiered_pricing_table/cart/need_price_recalculation/item', true, $cartItem );
189 if ( $cartItem['data'] instanceof WC_Product && $calculateTieredPriceForItem ) {
190 $product = wc_get_product( $cartItem['data']->get_id() );
191 $pricingRule = PriceManager::getPricingRule( $cartItem['data']->get_id() );
192 $newPrice = $pricingRule->getTierPrice( $this->getTotalProductCount( $cartItem ), true, 'cart' );
193 $newPrice = apply_filters( 'tiered_pricing_table/cart/product_cart_price/item', $newPrice, $cartItem );
194 if ( false !== $newPrice ) {
195 return wc_price( $newPrice );
196 }
197 }
198 return $price;
199 }
200
201 public function triggerMiniCartUpdate() {
202 $cart = wc()->cart;
203 $cart->calculate_totals();
204 }
205
206 /**
207 * Get total product count depends on user's settings
208 *
209 * @param ?array $cartItem
210 *
211 * @return int
212 */
213 public function getTotalProductCount( ?array $cartItem ) : int {
214 if ( CalculationLogic::considerProductVariationAsOneProduct() ) {
215 $count = 0;
216 foreach ( wc()->cart->cart_contents as $cart_content ) {
217 if ( $cart_content['product_id'] == $cartItem['product_id'] ) {
218 $count += $cart_content['quantity'];
219 }
220 }
221 } else {
222 $count = $cartItem['quantity'];
223 }
224 return (int) apply_filters( 'tiered_pricing_table/cart/total_product_count', $count, $cartItem );
225 }
226
227 }
228