PluginProbe
Discount Rules for WooCommerce – Disco | Dynamic Pricing, Conditions, Bulk, Bundle, BOGO / 1.4.14
Discount Rules for WooCommerce – Disco | Dynamic Pricing, Conditions, Bulk, Bundle, BOGO v1.4.14
1.4.14 1.4.13 1.4.12 1.4.11 1.4.10 1.4.9 1.4.8 1.4.7 1.4.6 1.4.5 1.4.4 1.4.3 1.4.2 1.4.1 1.4.0 1.3.54 1.3.53 1.3.52 1.3.51 1.3.50 1.3.49 1.3.48 1.3.47 1.3.46 1.3.45 All 177 releases
disco / app / Calc / CalcFixedPerProduct.php

CalcFixedPerProduct.php in Discount Rules for WooCommerce – Disco | Dynamic Pricing, Conditions, Bulk, Bundle, BOGO 1.4.14, at app/Calc/CalcFixedPerProduct.php

195 lines 5.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php // phpcs:ignoreFile
2
3 namespace Disco\App\Calc;
4
5 /**
6 * Class CalcPercentPerProduct
7 *
8 * @package Disco
9 * @subpackage Disco\App\Calc
10 * @author Ohidul Islam <wahid0003@gmail.com>
11 * @link https://webappick.com
12 * @license https://opensource.org/licenses/gpl-license.php GNU Public License
13 * @category Plugin
14 */
15 class CalcFixedPerProduct extends CalcAbstract {
16
17 use \Disco\App\Intents\IntentHelper;
18
19 /**
20 * @var array
21 */
22 private $rule;
23
24 /**
25 * @var array
26 */
27 private $item;
28
29 /**
30 * @var object $cart Cart.
31 * @phpstan-ignore-next-line
32 */
33 private $cart;
34
35 /**
36 * @var string $discount_intent
37 */
38 private $discount_intent;
39
40 /**
41 * @var float
42 */
43 private $discounted_quantities;
44
45 /**
46 * CalcFixedPerProduct constructor.
47 *
48 * @param array $rule Campaign Rule.
49 * @param array $item Cart Item.
50 * @param object $cart Cart.
51 * @param object $campaign Campaign.
52 */
53 public function __construct( $rule, $item, $cart, $campaign ) {
54 // Constructor...
55 $this->rule = $rule;
56 $this->item = $item;
57 $this->cart = $cart;
58
59 // @phpstan-ignore-next-line
60 $this->discount_intent = $campaign->get_discount_intent(); // phpcs:ignore
61 }
62
63 /**
64 * Calculate Discount.
65 * This function calculates the discount amount based on the discount type, value and item quantity.
66 *
67 * @return array $discount
68 */
69 public function calculate(): array {
70 $discount = $this->calculate_discount();
71
72 return array(
73 'price' => $this->calculate_price( $discount ),
74 'discount' => $discount,
75 'line_subtotal' => $this->calculate_line_subtotal( $discount ),
76 'discounted_quantities' => $this->discounted_quantities,
77 );
78 }
79
80 /**
81 * Calculate Discount.
82 *
83 * @return float Discount Amount.
84 */
85 public function calculate_discount(): float { // phpcs:ignore
86 $discount_amount = 0;
87 $fixed_per_product = $this->rule['discount_value'];
88 $quantity = (int) $this->item['quantity'];
89
90 // "Count Quantity As" combined / variations: discount only the eligible units.
91 if ( isset( $this->item['disco_forced_qty'] ) ) {
92 $forced = max( 0, (int) $this->item['disco_forced_qty'] );
93 $this->discounted_quantities = $forced;
94
95 return apply_filters( 'disco_final_discounted_amount', $forced * $fixed_per_product, 'fixed_per_product' );
96 }
97 $min = $this->rule['min'] ? (int) $this->rule['min'] : 0; //phpcs:ignore
98 $max = ! empty( $this->rule['max'] ) ? (int) $this->rule['max'] : ( $this->discount_intent === 'Bulk' ? PHP_INT_MAX : 0 ); // phpcs:ignore
99 $recursive = ! empty( $this->rule['recursive'] ) && $this->rule['recursive'] === 'yes'; // phpcs:ignore
100 $item_id = $this->item['product_id'];
101 $rule_ids = array_column( $this->rule['get_ids'], 'id' );
102 $discount_qty = $this->rule['get_quantity'] ? (int) $this->rule['get_quantity'] : 0; // phpcs:ignore
103
104 // Default discount for quantities.
105 $discount_for_quantities = $min;
106
107 /**
108 * Bulk / range capping — only when NOT recursive. Recursive rules ignore
109 * max: the bundle size is always min, so the qualifying quantity must not
110 * be capped to max here, otherwise floor( qty / base ) would divide by
111 * max instead of min and undercount the bundles.
112 */
113 if ( ! $recursive && $max && $quantity >= $max ) {
114 $discount_for_quantities = $max;
115 }
116
117 // If quantity between min and max then apply discount.
118 if ( ! $recursive && $quantity >= $min && $quantity <= $max ) {
119 $discount_for_quantities = $quantity;
120 }
121
122 /**
123 * If discount intent is BuyXGetY then set the discount for quantities to 1.
124 * This is to ensure that the discount for selected item for BOGO discount.
125 * Here no need to check for min and max quantity.
126 */
127 if (
128 $this->discount_intent === 'BuyXGetY'
129 && ! empty( $rule_ids )
130 && (
131 in_array( $item_id, $rule_ids, true )
132 || $this->is_in_category( $item_id, $rule_ids )
133 )
134 ) {
135 $discount_for_quantities = $discount_qty;
136 }
137
138 // Apply for the Bundle & BOGO Discount when recursive is set.
139 $multiplier = 1;
140
141 if ( $recursive && $min > 0 && $quantity >= $min ) {
142 /**
143 * Recursive: the number of bundles is floor( qty / min ). Divide by
144 * min, never by $discount_for_quantities — for BuyXGetY the latter
145 * holds the reward quantity (get_quantity) and would inflate the
146 * multiplier (e.g. buy 2 get 1 with 2 in cart → 1 bundle, not 2).
147 */
148 $multiplier = (int) floor( $quantity / $min );
149 $discount_for_quantities *= $multiplier;
150 }
151
152 // Limit discount to Min or Max quantity.
153 if ( $quantity >= $discount_for_quantities ) {
154 $discount_for_quantities = min( $quantity, $discount_for_quantities );
155 // Set the discounted quantity for BOGO.
156 if ( ! empty( $this->rule['get_quantity'] ) ) { // phpcs:ignore
157 $discount_for_quantities = (int) $this->rule['get_quantity'];
158 $discount_for_quantities *= $multiplier;
159 }
160 $discount_amount = $discount_for_quantities * $fixed_per_product;
161 }
162
163 $this->discounted_quantities = $discount_for_quantities;
164
165 return apply_filters( 'disco_final_discounted_amount', $discount_amount, 'fixed_per_product' );
166 }
167
168 /**
169 * Calculate Price.
170 *
171 * @param float $discount Discount Amount.
172 * @return float Price.
173 */
174 public function calculate_price( $discount ): float {
175 $discounted_subtotal = $this->calculate_line_subtotal( $discount );
176
177 return $discounted_subtotal / $this->item['quantity'];
178 }
179
180 /**
181 * Calculate Line Subtotal.
182 *
183 * @param float $discount Discount Amount.
184 * @return float Line Subtotal.
185 */
186 public function calculate_line_subtotal( $discount ): float {
187 if ( isset( $this->item['line_subtotal'] ) ) {
188 return $this->item['line_subtotal'] - $discount;
189 }
190
191 return 0.0;
192 }
193
194 }
195