PluginProbe
Discount Rules for WooCommerce – Disco | Dynamic Pricing, Conditions, Bulk, Bundle, BOGO / 1.4.16
Discount Rules for WooCommerce – Disco | Dynamic Pricing, Conditions, Bulk, Bundle, BOGO v1.4.16
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 1.3.52 1.3.51 1.3.50 1.3.49 1.3.48 All 180 releases
← All changes | app/Intents/IntentHelper.php +52 -7 1.4.141.4.16 View file →
@@ -663,13 +663,19 @@
663 663 if ( empty( $get_discounts ) ) {
664 664 continue;
665 665 }
666 666
667 - // Only stage campaigns whose discount actually applied to the cart.
668 - ( new UserLimit )->disco_start_session_on_checkout( $intent->campaign->id );
669 -
670 667 foreach ( $get_discounts as $item_id => $discount ) {
668 + /**
669 + * Keep the campaign alongside its amount at the same index.
670 + *
671 + * Staging cannot happen yet: several campaigns can offer an amount
672 + * for the same item and only one of them survives the min/max
673 + * reduction below. Crediting every campaign here would consume the
674 + * usage limit of campaigns whose discount never reached the cart.
675 + */
671 676 $discounts[ $item_id ]['discounts'][] = max( $discount['discounts'] );
677 + $discounts[ $item_id ]['campaigns'][] = (int) $intent->campaign->id;
672 678 }
673 679 }
674 680
675 681 // Check if the discounts are empty.
@@ -676,13 +682,27 @@
676 682 if ( empty( $discounts ) ) {
677 683 return false;
678 684 }
679 685
686 + $applied_campaign_ids = array();
687 +
680 688 // Get the min or max discount amount for each item.
681 689 foreach ( $discounts as $item_id => $discount ) {
682 - $discounts[ $item_id ] = $this->min_max_average( $discount['discounts'] );
690 + $winning_amount = $this->min_max_average( $discount['discounts'] );
691 + $winning_index = array_search( $winning_amount, $discount['discounts'], true );
692 +
693 + if ( false !== $winning_index && isset( $discount['campaigns'][ $winning_index ] ) ) {
694 + $applied_campaign_ids[ $discount['campaigns'][ $winning_index ] ] = true;
695 + }
696 +
697 + $discounts[ $item_id ] = $winning_amount;
683 698 }
684 699
700 + // Stage only the campaigns that actually won an item.
701 + foreach ( array_keys( $applied_campaign_ids ) as $applied_campaign_id ) {
702 + ( new UserLimit )->disco_start_session_on_checkout( $applied_campaign_id );
703 + }
704 +
685 705 return $discounts;
686 706 }
687 707
688 708 /**
@@ -761,9 +781,10 @@
761 781 if ( empty( $intents ) ) {
762 782 return false;
763 783 }
764 784
765 - $discounts = array();
785 + $discounts = array();
786 + $candidate_campaign_ids = array();
766 787
767 788 // Loop through the intents.
768 789 foreach ( $intents as $intent ) {
769 790 /**
@@ -781,10 +802,18 @@
781 802 if ( empty( $get_discounts ) ) {
782 803 continue;
783 804 }
784 805
785 - // Only stage campaigns whose discount actually applied to the cart.
786 - ( new UserLimit )->disco_start_session_on_checkout( $intent->campaign->id );
806 + /**
807 + * Collect the campaign now, stage it later.
808 + *
809 + * What this method finally grants is decided well below: the rewards
810 + * are unioned across campaigns and a BuyXGetY (products) campaign can
811 + * then override the whole result authoritatively. Crediting a campaign
812 + * here would consume its usage limit even when the final result grants
813 + * it nothing.
814 + */
815 + $candidate_campaign_ids[] = (int) $intent->campaign->id;
787 816
788 817 foreach ( $get_discounts as $item_id => $discount ) {
789 818 $discounts[ $item_id ]['discounts'][] = max( $discount['discounts'] ); // phpcs:ignore
790 819 $discounts[ $item_id ]['free'] = $discount['free']; // phpcs:ignore
@@ -871,8 +900,24 @@
871 900 $discounts['get_qty'] = empty( $reward_map ) ? 0 : max( $reward_map ); // phpcs:ignore
872 901 $discounts['free'] = ! empty( $reward_map ); // phpcs:ignore
873 902 $discounts['bogo_type'] = $bogo_type;
874 903 $discounts['free_item_selection'] = $intent->campaign->get_free_item_selection();
904 +
905 + /**
906 + * This branch is authoritative for the whole result, so the campaign
907 + * that owns it is the only one that can be credited.
908 + */
909 + $candidate_campaign_ids = array( (int) $intent->campaign->id );
910 + }
911 +
912 + /**
913 + * Stage the campaigns only once the result is final, and only when it
914 + * actually grants free items.
915 + */
916 + if ( ! empty( $discounts['free'] ) ) {
917 + foreach ( array_unique( $candidate_campaign_ids ) as $applied_campaign_id ) {
918 + ( new UserLimit )->disco_start_session_on_checkout( $applied_campaign_id );
919 + }
875 920 }
876 921
877 922 return $discounts;
878 923 }