|
32 | 32 | condition.preferred_operator = "gt" |
33 | 33 | expect(condition.preferred_operator).to eq("gt") |
34 | 34 | end |
| 35 | + |
| 36 | + it "defaults preferred_match_policy to 'include'" do |
| 37 | + expect(condition.preferred_match_policy).to eq("include") |
| 38 | + end |
| 39 | + |
| 40 | + it "accepts 'exclude' as a valid match policy" do |
| 41 | + condition.preferred_match_policy = "exclude" |
| 42 | + expect(condition.preferred_match_policy).to eq("exclude") |
| 43 | + end |
| 44 | + |
| 45 | + it "is invalid with an unrecognized match policy" do |
| 46 | + condition.preferred_match_policy = "some_other_policy" |
| 47 | + expect(condition).not_to be_valid |
| 48 | + expect(condition.errors[:preferred_match_policy]).to be_present |
| 49 | + end |
35 | 50 | end |
36 | 51 |
|
37 | 52 | describe "taxons association" do |
|
54 | 69 | } |
55 | 70 | end |
56 | 71 |
|
| 72 | + describe ".match_policy_options" do |
| 73 | + subject(:match_policy_options) { described_class.match_policy_options } |
| 74 | + |
| 75 | + it { |
| 76 | + is_expected.to contain_exactly( |
| 77 | + ["Revenue from selected taxons", "include"], |
| 78 | + ["Revenue excluding selected taxons", "exclude"] |
| 79 | + ) |
| 80 | + } |
| 81 | + end |
| 82 | + |
57 | 83 | describe "#order_eligible?" do |
58 | 84 | context "with operator 'gte' (default)" do |
59 | 85 | context "when the taxon revenue equals the threshold" do |
|
179 | 205 | expect(condition).not_to be_order_eligible(order) |
180 | 206 | end |
181 | 207 | end |
| 208 | + |
| 209 | + context "when preferred_match_policy is 'exclude'" do |
| 210 | + before { condition.preferred_match_policy = "exclude" } |
| 211 | + |
| 212 | + context "when the non-excluded-taxon revenue equals the threshold" do |
| 213 | + let(:preferred_amount) { 50 } |
| 214 | + |
| 215 | + it "is eligible" do |
| 216 | + # matching_item (in matching_taxon) is excluded from the sum; |
| 217 | + # only non_matching_item (50) counts, and 50 >= 50 |
| 218 | + expect(condition).to be_order_eligible(order) |
| 219 | + end |
| 220 | + end |
| 221 | + |
| 222 | + context "when the non-excluded-taxon revenue exceeds the threshold" do |
| 223 | + let(:preferred_amount) { 40 } |
| 224 | + |
| 225 | + it "is eligible" do |
| 226 | + expect(condition).to be_order_eligible(order) |
| 227 | + end |
| 228 | + end |
| 229 | + |
| 230 | + context "when the non-excluded-taxon revenue is below the threshold" do |
| 231 | + let(:preferred_amount) { 60 } |
| 232 | + |
| 233 | + it "is not eligible" do |
| 234 | + # only non_matching_item (50) counts, 50 < 60 |
| 235 | + expect(condition).not_to be_order_eligible(order) |
| 236 | + end |
| 237 | + end |
| 238 | + |
| 239 | + it "does not count revenue from line items in the excluded taxon" do |
| 240 | + # If the excluded item were counted, total would be 80 (30 + 50). |
| 241 | + # With it excluded, only 50 counts, so a threshold of 51 is not met. |
| 242 | + condition.preferred_amount = 51 |
| 243 | + expect(condition).not_to be_order_eligible(order) |
| 244 | + end |
| 245 | + |
| 246 | + context "when all line items belong to the excluded taxon" do |
| 247 | + let(:order) { build_stubbed(:order, line_items: [matching_item]) } |
| 248 | + let(:preferred_amount) { 1 } |
| 249 | + |
| 250 | + it "is not eligible because the non-excluded revenue is zero" do |
| 251 | + expect(condition).not_to be_order_eligible(order) |
| 252 | + end |
| 253 | + |
| 254 | + context "when the preferred amount is zero" do |
| 255 | + let(:preferred_amount) { 0 } |
| 256 | + |
| 257 | + it { is_expected.to be_order_eligible(order) } |
| 258 | + end |
| 259 | + end |
| 260 | + |
| 261 | + context "when multiple taxons are excluded" do |
| 262 | + let(:other_excluded_item) { build(:line_item, price: 25, product: non_matching_product) } |
| 263 | + let(:third_taxon) { create(:taxon) } |
| 264 | + let(:third_product) { build(:product, taxons: [third_taxon]) } |
| 265 | + let(:remaining_item) { build(:line_item, price: 15, product: third_product) } |
| 266 | + let(:order) { build_stubbed(:order, line_items: [matching_item, other_excluded_item, remaining_item]) } |
| 267 | + let(:preferred_amount) { 15 } |
| 268 | + |
| 269 | + before do |
| 270 | + condition.taxons << other_taxon |
| 271 | + end |
| 272 | + |
| 273 | + it "only counts revenue from line items outside every excluded taxon" do |
| 274 | + # matching_item (matching_taxon) and other_excluded_item (other_taxon) are excluded; |
| 275 | + # only remaining_item (15) counts, and 15 >= 15 |
| 276 | + expect(condition).to be_order_eligible(order) |
| 277 | + end |
| 278 | + end |
| 279 | + |
| 280 | + context "when a line item belongs to both an excluded and a non-excluded taxon" do |
| 281 | + let(:multi_taxon_item) { build(:line_item, price: 30, product: multi_taxon_product) } |
| 282 | + let(:multi_taxon_product) { build(:product, taxons: [matching_taxon, other_taxon]) } |
| 283 | + let(:order) { build_stubbed(:order, line_items: [multi_taxon_item]) } |
| 284 | + let(:preferred_amount) { 1 } |
| 285 | + |
| 286 | + it "is excluded, since it belongs to the excluded taxon" do |
| 287 | + expect(condition).not_to be_order_eligible(order) |
| 288 | + end |
| 289 | + end |
| 290 | + |
| 291 | + context "when no taxons are configured on the condition" do |
| 292 | + subject(:condition) { described_class.new(preferred_amount:, preferred_match_policy: "exclude") } |
| 293 | + let(:preferred_amount) { 79 } |
| 294 | + |
| 295 | + it "counts all line items, since none belong to an excluded taxon" do |
| 296 | + # 30 + 50 = 80 >= 79 |
| 297 | + expect(condition).to be_order_eligible(order) |
| 298 | + end |
| 299 | + end |
| 300 | + end |
182 | 301 | end |
183 | 302 | end |
0 commit comments