Skip to content

Commit 99efd84

Browse files
committed
feat(products): add attached_to_plan_or_subscription? to catalog models
## Context Structural catalog fields (code, product attachment, filter values) must stop being editable once an item is in use. An item is in use as soon as it is part of a plan, not only when a subscription exists. ## Description Add attached_to_plan_or_subscription? to Product, ProductItem and ProductItemFilter. A product item is attached when a plan_product_item or a subscription_product_item references it; a product when it belongs to a plan or any of its items is on a subscription; a filter delegates to its item.
1 parent 86f2c73 commit 99efd84

6 files changed

Lines changed: 68 additions & 0 deletions

File tree

app/models/product.rb

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,12 @@ def self.ransackable_attributes(_auth_object = nil)
2626
def invoice_name
2727
invoice_display_name.presence || name
2828
end
29+
30+
def attached_to_plan_or_subscription?
31+
return true if plan_products.exists?
32+
33+
SubscriptionProductItem.where(product_item_id: product_items.select(:id)).exists?
34+
end
2935
end
3036

3137
# == Schema Information

app/models/product_item.rb

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,10 @@ def invoice_name
4141
invoice_display_name.presence || name
4242
end
4343

44+
def attached_to_plan_or_subscription?
45+
plan_product_items.exists? || subscription_product_items.exists?
46+
end
47+
4448
private
4549

4650
def validate_billable_metric_presence

app/models/product_item_filter.rb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ class ProductItemFilter < ApplicationRecord
1212
has_many :values, class_name: "ProductItemFilterValue"
1313
has_many :billable_metric_filters, through: :values
1414

15+
delegate :attached_to_plan_or_subscription?, to: :product_item
16+
1517
validates :name, presence: true
1618
validates :code,
1719
presence: true,

spec/models/product_item_filter_spec.rb

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,4 +66,17 @@
6666
expect(filter.reload.to_h).to eq("region" => %w[us eu], "scheme" => %w[visa])
6767
end
6868
end
69+
70+
describe "#attached_to_plan_or_subscription?" do
71+
let(:product_item) { create(:product_item) }
72+
let(:filter) { create(:product_item_filter, organization: product_item.organization, product_item:) }
73+
74+
it "delegates to the product item" do
75+
expect(filter.attached_to_plan_or_subscription?).to be(false)
76+
77+
create(:subscription_product_item, organization: product_item.organization, product_item:)
78+
79+
expect(filter.attached_to_plan_or_subscription?).to be(true)
80+
end
81+
end
6982
end

spec/models/product_item_spec.rb

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,4 +82,24 @@
8282
end
8383
end
8484
end
85+
86+
describe "#attached_to_plan_or_subscription?" do
87+
let(:product_item) { create(:product_item) }
88+
89+
it "is false when no plan or subscription references it" do
90+
expect(product_item.attached_to_plan_or_subscription?).to be(false)
91+
end
92+
93+
it "is true when a plan product item references it" do
94+
create(:plan_product_item, organization: product_item.organization, product_item:)
95+
96+
expect(product_item.attached_to_plan_or_subscription?).to be(true)
97+
end
98+
99+
it "is true when a subscription product item references it" do
100+
create(:subscription_product_item, organization: product_item.organization, product_item:)
101+
102+
expect(product_item.attached_to_plan_or_subscription?).to be(true)
103+
end
104+
end
85105
end

spec/models/product_spec.rb

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,4 +51,27 @@
5151
expect(product.invoice_name).to eq("Name")
5252
end
5353
end
54+
55+
describe "#attached_to_plan_or_subscription?" do
56+
let(:product) { create(:product) }
57+
58+
it "is false when the product is not in a plan and none of its items has a subscription" do
59+
create(:product_item, organization: product.organization, product:)
60+
61+
expect(product.attached_to_plan_or_subscription?).to be(false)
62+
end
63+
64+
it "is true when the product is attached to a plan" do
65+
create(:plan_product, organization: product.organization, product:)
66+
67+
expect(product.attached_to_plan_or_subscription?).to be(true)
68+
end
69+
70+
it "is true when one of its items has a subscription product item" do
71+
item = create(:product_item, organization: product.organization, product:)
72+
create(:subscription_product_item, organization: product.organization, product_item: item)
73+
74+
expect(product.attached_to_plan_or_subscription?).to be(true)
75+
end
76+
end
5477
end

0 commit comments

Comments
 (0)