PluginProbe
Discount Rules for WooCommerce – Disco | Dynamic Pricing, Conditions, Bulk, Bundle, BOGO / 1.4.22
Discount Rules for WooCommerce – Disco | Dynamic Pricing, Conditions, Bulk, Bundle, BOGO v1.4.22
1.4.22 1.4.21 1.4.20 1.4.19 1.4.18 1.4.17 1.4.16 1.4.15 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 All 185 releases
← All changes | app/Intents/IntentHelper.php +70 -19 1.4.16 → 1.4.22 View file →
@@ -64,9 +64,9 @@
64 64 ) {
65 65 continue;
66 66 }
67 67
68 - if ( $campaign->discount_intent === 'BOGO' ) {
68 + if ( 'BOGO' === $campaign->discount_intent ) {
69 69 $campaign->discount_intent = 'BuyXGetX';
70 70
71 71 if ( in_array( $campaign->bogo_type, array( 'products', 'categories' ), true ) ) {
72 72 $campaign->discount_intent = 'BuyXGetY';
@@ -97,9 +97,9 @@
97 97 /**
98 98 * Check if the discount type is BuyXGetY and the Y product is in the cart.
99 99 * If so, add the Y product to the items array.
100 100 */
101 - if ( $discount_type === 'BuyXGetY' ) {
101 + if ( 'BuyXGetY' === $discount_type ) {
102 102 $rule_ids = $campaign->get_rule_product_ids();
103 103 $y_products = $this->get_y_product( $rule_ids, $cart_items, $bogo_type );
104 104 $verified_yproducts = $this->verify_yproduct_in_cart( $rule_ids, $cart_items, $bogo_type );
105 105 }
@@ -134,9 +134,9 @@
134 134 * Check if the discount type is BuyXGetY and the Y product is in the cart.
135 135 * If so, add the Y product to the items array.
136 136 * These products not need to be passed the filter.
137 137 */
138 - if ( $discount_type === 'BuyXGetY' && $verified_yproducts ) {
138 + if ( 'BuyXGetY' === $discount_type && $verified_yproducts ) {
139 139 $items = array_merge( $items, $y_products );
140 140 }
141 141
142 142 $items[] = $item;
@@ -251,17 +251,39 @@
251 251 public function calculate_discount( $cost, $discount_type, $discount_value ) {
252 252 $cost = (float) $cost;
253 253 $discount_value = (float) $discount_value;
254 254
255 - if ( 'percent' === $discount_type ) {
256 - $cost = $cost * $discount_value / 100;
257 - }
255 + switch ( $discount_type ) {
256 + case 'percent':
257 + return $cost * $discount_value / 100;
258 258
259 - if ( 'fixed' === $discount_type || 'fixed_per_product' === $discount_type ) {
260 - $cost = $discount_value;
261 - }
259 + case 'fixed':
260 + case 'fixed_per_product':
261 + return $discount_value;
262 262
263 - return $cost;
263 + case 'free':
264 + // The whole cost comes off, which is what makes the item free.
265 + return $cost;
266 +
267 + default:
268 + /**
269 + * Anything else discounts nothing.
270 + *
271 + * This used to fall through and return $cost untouched, which the
272 + * callers then treat as the discount: ProductIntent hands it the
273 + * product price and CartIntent the cart subtotal, so an
274 + * unrecognised type gave away the product or the entire cart.
275 + *
276 + * Only Bulk, Bundle and BOGO route through the Calc classes,
277 + * where every type has an implementation; Product and Cart come
278 + * straight here, so the gap was reachable by any rule carrying a
279 + * type this method does not know: a campaign saved while
280 + * fixed_price and percent_per_product were still offered in the
281 + * builder, a REST write (discount_type inside discount_rules is
282 + * not validated), or a hand edited row.
283 + */
284 + return 0.0;
285 + }//end switch
264 286 }
265 287
266 288 /**
267 289 * Get the discounted price.
@@ -304,9 +326,9 @@
304 326 * @return bool Returns true if the number is a multiple of the given number, false otherwise.
305 327 */
306 328 public function is_multiple( $number, $of ) {
307 329 if ( $of >= $number ) {
308 - return (float) $of % (float) $number === 0;
330 + return 0 === (float) $of % (float) $number;
309 331 }
310 332
311 333 return false;
312 334 }
@@ -493,8 +515,37 @@
493 515 }
494 516
495 517 $discountable_units = $this->grouped_discount_budget( $rule, $total_qualifying_units );
496 518
519 + /**
520 + * A flat amount is charged for the pooled group as a whole.
521 + *
522 + * Pooling exists so the cart together can reach the tier minimum, so
523 + * the rule qualifies for the group rather than for each line that
524 + * contributed quantity. The Calc layer returns the rule value whole
525 + * for every line it is handed, because a flat amount does not scale
526 + * with units, so spreading it across lines multiplied the discount by
527 + * the line count: a flat 10 came out as 20 over two lines.
528 + *
529 + * It is applied to the first eligible line carrying the entire pooled
530 + * budget, which is what lets a recursive rule still charge once per
531 + * bundle: the Calc layer derives the bundle count from that quantity.
532 + * Per unit types keep every line, since their amount is meant to
533 + * scale with the units.
534 + */
535 + if ( in_array( $rule['discount_type'], array( 'fixed', 'fixed_price' ), true ) ) {
536 + $first_line = reset( $eligible_lines );
537 +
538 + if ( ! empty( $first_line['item'] ) && $discountable_units > 0 ) {
539 + $item = $first_line['item'];
540 + $item['disco_forced_qty'] = $discountable_units;
541 +
542 + $this->apply_rule_to_discount( $discounts, $campaign, $rule, $item, $cart, $total_applicable_qty );
543 + }
544 +
545 + continue;
546 + }
547 +
497 548 // Hand out the discountable units across the eligible lines in cart order.
498 549 foreach ( $eligible_lines as $eligible_line ) {
499 550 if ( $discountable_units <= 0 ) {
500 551 break;
@@ -572,9 +623,9 @@
572 623 // Set discount applies to
573 624 $discounts[ $effective_product_id ]['discount_applies_to'][ $rule_key ] = CalcFactory::discount_applies_to( $rule, $campaign );
574 625
575 626 // Set Discounts.
576 - if ( $rule['discount_type'] === 'free' ) {
627 + if ( 'free' === $rule['discount_type'] ) {
577 628 $discounted_amount = array(
578 629 'price' => $product->get_price(),
579 630 'discount' => 0,
580 631 'line_subtotal' => $product->get_price() * $item['quantity'],
@@ -1464,10 +1515,10 @@
1464 1515 */
1465 1516 private function verify_bundle_rule( int $quantity, array $rule ): bool {
1466 1517 $rule_basis = abs( $rule['min'] );
1467 1518
1468 - if ( $rule['recursive'] === 'yes' ) {
1469 - if ( $quantity >= $rule_basis && ( $quantity % $rule_basis === 0 || $quantity > $rule_basis ) ) {
1519 + if ( 'yes' === $rule['recursive'] ) {
1520 + if ( $quantity >= $rule_basis && ( 0 === $quantity % $rule_basis || $quantity > $rule_basis ) ) {
1470 1521 return true;
1471 1522 }
1472 1523 } elseif ( $quantity >= $rule_basis ) {
1473 1524 return true;
@@ -1486,16 +1537,16 @@
1486 1537 private function verify_buyxgetx_rule( float $quantity, array $item, array $rule ): bool {//phpcs:ignore
1487 1538
1488 1539 $verified = ( $quantity >= $rule['min'] && $quantity <= $rule['max'] );
1489 1540
1490 - if ( $verified && $rule['recursive'] === 'no' ) {
1541 + if ( $verified && 'no' === $rule['recursive'] ) {
1491 1542 return true;
1492 1543 }
1493 1544
1494 1545 $base_quantity = abs( $rule['min'] );
1495 1546
1496 - if ( $rule['recursive'] === 'yes' && ! isset( $rule['max'] ) ) {
1497 - if ( $quantity >= $base_quantity && $quantity % $base_quantity === 0 ) {
1547 + if ( 'yes' === $rule['recursive'] && ! isset( $rule['max'] ) ) {
1548 + if ( $quantity >= $base_quantity && 0 === $quantity % $base_quantity ) {
1498 1549 return true;
1499 1550 }
1500 1551 } elseif ( $quantity >= $base_quantity ) {
1501 1552 return true;
@@ -1522,9 +1573,9 @@
1522 1573
1523 1574 /**
1524 1575 * This code use for automatically apply free items rule for all product BOGO campaigns.
1525 1576 */
1526 - if ( $rule['discount_type'] === 'free' && 'all' === $campaign->get_bogo_type() ) {
1577 + if ( 'free' === $rule['discount_type'] && 'all' === $campaign->get_bogo_type() ) {
1527 1578 return $this->verify_buyxgetx_rule( $quantity, $item, $rule );
1528 1579 }
1529 1580
1530 1581 /**
@@ -1529,9 +1580,9 @@
1529 1580
1530 1581 /**
1531 1582 * This code use for automatically apply free items rule product based BOGO campaigns.
1532 1583 */
1533 - if ( $rule['discount_type'] === 'free' && 'products' === $campaign->get_bogo_type() ) {
1584 + if ( 'free' === $rule['discount_type'] && 'products' === $campaign->get_bogo_type() ) {
1534 1585 return $this->verify_xproduct_cart_rule( $campaign, $rule );
1535 1586 }
1536 1587
1537 1588 if ( 'products' === $campaign->get_bogo_type() && in_array( $id, $rule_ids, true ) ) {