Skip to content

Commit 882e320

Browse files
committed
feat(products): seed subscriptions on the product catalog
The catalog seed stopped at the offer: no subscription existed, so nothing exercised materialization, the authoring window, or gave the billing engine an entry to bill locally. It also predated the v1 immutability rules, under which the order of operations matters. Extend the Hooli v2 seed past the plan: a rate card and rate for the platform fee item (second plan entry), a launch-offer phase ramp on the usage entry — authored before the first subscription, since a subscribed plan locks — then an active subscription with its materialized entries, and a pending subscription with a directly attached card carrying negotiated phases, showing the authoring window that closes at activation.
1 parent 92741b4 commit 882e320

1 file changed

Lines changed: 94 additions & 2 deletions

File tree

db/seeds/30_product_catalog.rb

Lines changed: 94 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,26 @@
9797
}
9898
)
9999

100-
# Assign the rate card to a plan so the catalog is wired into an offer.
100+
platform_fee_card = RateCards::CreateService.call!(
101+
product_item: ProductItem.find_by!(organization:, code: "platform_fee"),
102+
params: {
103+
name: "Platform fee USD",
104+
code: "platform_fee_usd",
105+
currency: "USD"
106+
}
107+
).rate_card
108+
109+
RateCardRates::CreateService.call!(
110+
rate_card: platform_fee_card,
111+
params: {
112+
effective_datetime: 1.month.ago,
113+
rate_model: "standard",
114+
rate_properties: {amount: "99"},
115+
billing_interval_unit: "month"
116+
}
117+
)
118+
119+
# Assign the rate cards to a plan so the catalog is wired into an offer.
101120
plan = Plans::CreateService.call!({
102121
organization_id: organization.id,
103122
name: "Growth",
@@ -106,8 +125,81 @@
106125
pricing_type: "product_catalog"
107126
}).plan
108127

109-
PlanProductItems::CreateService.call!(
128+
usage_entry = PlanProductItems::CreateService.call!(
110129
plan:,
111130
params: {rate_card_code: rate_card.code}
131+
).plan_product_item
132+
133+
PlanProductItems::CreateService.call!(
134+
plan:,
135+
params: {rate_card_code: platform_fee_card.code, units: 1}
136+
)
137+
138+
# Phases must be authored before the first subscription: a subscribed plan
139+
# is immutable (cards, phases and rates all lock).
140+
RatePhases::ReplaceService.call!(
141+
plan_product_item: usage_entry,
142+
phases_params: [
143+
{
144+
position: 1,
145+
name: "Launch offer",
146+
billing_interval_cycle_count: 3,
147+
rate_override: {rate_model: "standard", rate_properties: {amount: "0.005"}}
148+
},
149+
{position: 2, name: "Standard", billing_interval_cycle_count: nil}
150+
]
151+
)
152+
153+
billing_entity = organization.billing_entities.find_by!(code: "hooli_v2")
154+
155+
# An active subscription: materialization gives each plan card its own
156+
# billing lifecycle on the subscription, pricing stays on the plan.
157+
richard = Customer.create_with(
158+
name: "Richard Hendricks",
159+
currency: "USD",
160+
email: "richard@piedpiper.com"
161+
).find_or_create_by!(organization:, billing_entity:, external_id: "cust_hooli_v2_1")
162+
163+
active_subscription = Subscription.create_with(
164+
organization:,
165+
started_at: 1.month.ago,
166+
subscription_at: 1.month.ago,
167+
status: :active,
168+
billing_time: :anniversary
169+
).find_or_create_by!(customer: richard, plan:, external_id: "sub_hooli_v2_1")
170+
171+
Subscriptions::ProductCatalog::MaterializeService.call!(subscription: active_subscription)
172+
173+
# A pending subscription still in its authoring window: rate cards and
174+
# phases can be added, edited or removed until activation.
175+
monica = Customer.create_with(
176+
name: "Monica Hall",
177+
currency: "USD",
178+
email: "monica@raviga.com"
179+
).find_or_create_by!(organization:, billing_entity:, external_id: "cust_hooli_v2_2")
180+
181+
pending_subscription = Subscription.create_with(
182+
organization:,
183+
subscription_at: 1.month.from_now,
184+
status: :pending,
185+
billing_time: :anniversary
186+
).find_or_create_by!(customer: monica, plan:, external_id: "sub_hooli_v2_2")
187+
188+
negotiated_entry = SubscriptionProductItems::CreateService.call!(
189+
subscription: pending_subscription,
190+
params: {rate_card_code: platform_fee_card.code, units: 1, started_at: 1.month.from_now.iso8601}
191+
).subscription_product_item
192+
193+
RatePhases::ReplaceService.call!(
194+
subscription_product_item: negotiated_entry,
195+
phases_params: [
196+
{
197+
position: 1,
198+
name: "Negotiated intro",
199+
billing_interval_cycle_count: 3,
200+
rate_override: {rate_model: "standard", rate_properties: {amount: "49"}}
201+
},
202+
{position: 2, name: "Standard", billing_interval_cycle_count: nil}
203+
]
112204
)
113205
end

0 commit comments

Comments
 (0)