Skip to content

Commit ecad245

Browse files
committed
feat(backend): add billing cadence and pro-rating config to subscription
1 parent 91b9362 commit ecad245

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

52 files changed

+2869
-1096
lines changed

api/api.gen.go

Lines changed: 409 additions & 390 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

api/client/go/client.gen.go

Lines changed: 631 additions & 613 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

api/client/javascript/src/client/schemas.ts

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9280,6 +9280,24 @@ export interface components {
92809280
* @default USD
92819281
*/
92829282
currency: components['schemas']['CurrencyCode']
9283+
/**
9284+
* Billing cadence
9285+
* Format: duration
9286+
* @description The default billing cadence for subscriptions using this plan.
9287+
* Defines how often customers are billed using ISO8601 duration format.
9288+
* Examples: "P1M" (monthly), "P3M" (quarterly), "P1Y" (annually).
9289+
* @example P1M
9290+
*/
9291+
readonly billingCadence: string
9292+
/**
9293+
* Pro-rating configuration
9294+
* @description Default pro-rating configuration for subscriptions using this plan.
9295+
* @default {
9296+
* "enabled": true,
9297+
* "mode": "prorate_prices"
9298+
* }
9299+
*/
9300+
readonly proRatingConfig?: components['schemas']['ProRatingConfig']
92839301
}
92849302
/** @description A subscription add-on, represents concrete instances of an add-on for a given subscription. */
92859303
SubscriptionAddon: {
@@ -9631,6 +9649,24 @@ export interface components {
96319649
* @default USD
96329650
*/
96339651
currency: components['schemas']['CurrencyCode']
9652+
/**
9653+
* Billing cadence
9654+
* Format: duration
9655+
* @description The default billing cadence for subscriptions using this plan.
9656+
* Defines how often customers are billed using ISO8601 duration format.
9657+
* Examples: "P1M" (monthly), "P3M" (quarterly), "P1Y" (annually).
9658+
* @example P1M
9659+
*/
9660+
readonly billingCadence: string
9661+
/**
9662+
* Pro-rating configuration
9663+
* @description Default pro-rating configuration for subscriptions using this plan.
9664+
* @default {
9665+
* "enabled": true,
9666+
* "mode": "prorate_prices"
9667+
* }
9668+
*/
9669+
readonly proRatingConfig?: components['schemas']['ProRatingConfig']
96349670
/** @description Alignment details enriched with the current billing period. */
96359671
alignment?: components['schemas']['SubscriptionAlignment']
96369672
/** @description The phases of the subscription. */

api/openapi.cloud.yaml

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20830,6 +20830,7 @@ components:
2083020830
- status
2083120831
- customerId
2083220832
- currency
20833+
- billingCadence
2083320834
properties:
2083420835
id:
2083520836
type: string
@@ -20913,6 +20914,25 @@ components:
2091320914
Will be revised once we add multi currency support.
2091420915
title: Currency
2091520916
default: USD
20917+
billingCadence:
20918+
type: string
20919+
format: duration
20920+
description: |-
20921+
The default billing cadence for subscriptions using this plan.
20922+
Defines how often customers are billed using ISO8601 duration format.
20923+
Examples: "P1M" (monthly), "P3M" (quarterly), "P1Y" (annually).
20924+
title: Billing cadence
20925+
example: P1M
20926+
readOnly: true
20927+
proRatingConfig:
20928+
allOf:
20929+
- $ref: '#/components/schemas/ProRatingConfig'
20930+
description: Default pro-rating configuration for subscriptions using this plan.
20931+
title: Pro-rating configuration
20932+
default:
20933+
enabled: true
20934+
mode: prorate_prices
20935+
readOnly: true
2091620936
description: Subscription is an exact subscription instance.
2091720937
SubscriptionAddon:
2091820938
type: object
@@ -21285,6 +21305,7 @@ components:
2128521305
- status
2128621306
- customerId
2128721307
- currency
21308+
- billingCadence
2128821309
- phases
2128921310
properties:
2129021311
id:
@@ -21365,6 +21386,25 @@ components:
2136521386
Will be revised once we add multi currency support.
2136621387
title: Currency
2136721388
default: USD
21389+
billingCadence:
21390+
type: string
21391+
format: duration
21392+
description: |-
21393+
The default billing cadence for subscriptions using this plan.
21394+
Defines how often customers are billed using ISO8601 duration format.
21395+
Examples: "P1M" (monthly), "P3M" (quarterly), "P1Y" (annually).
21396+
title: Billing cadence
21397+
example: P1M
21398+
readOnly: true
21399+
proRatingConfig:
21400+
allOf:
21401+
- $ref: '#/components/schemas/ProRatingConfig'
21402+
description: Default pro-rating configuration for subscriptions using this plan.
21403+
title: Pro-rating configuration
21404+
default:
21405+
enabled: true
21406+
mode: prorate_prices
21407+
readOnly: true
2136821408
alignment:
2136921409
allOf:
2137021410
- $ref: '#/components/schemas/SubscriptionAlignment'

api/openapi.yaml

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21364,6 +21364,7 @@ components:
2136421364
- status
2136521365
- customerId
2136621366
- currency
21367+
- billingCadence
2136721368
properties:
2136821369
id:
2136921370
type: string
@@ -21447,6 +21448,25 @@ components:
2144721448
Will be revised once we add multi currency support.
2144821449
title: Currency
2144921450
default: USD
21451+
billingCadence:
21452+
type: string
21453+
format: duration
21454+
description: |-
21455+
The default billing cadence for subscriptions using this plan.
21456+
Defines how often customers are billed using ISO8601 duration format.
21457+
Examples: "P1M" (monthly), "P3M" (quarterly), "P1Y" (annually).
21458+
title: Billing cadence
21459+
example: P1M
21460+
readOnly: true
21461+
proRatingConfig:
21462+
allOf:
21463+
- $ref: '#/components/schemas/ProRatingConfig'
21464+
description: Default pro-rating configuration for subscriptions using this plan.
21465+
title: Pro-rating configuration
21466+
default:
21467+
enabled: true
21468+
mode: prorate_prices
21469+
readOnly: true
2145021470
description: Subscription is an exact subscription instance.
2145121471
SubscriptionAddon:
2145221472
type: object
@@ -21819,6 +21839,7 @@ components:
2181921839
- status
2182021840
- customerId
2182121841
- currency
21842+
- billingCadence
2182221843
- phases
2182321844
properties:
2182421845
id:
@@ -21899,6 +21920,25 @@ components:
2189921920
Will be revised once we add multi currency support.
2190021921
title: Currency
2190121922
default: USD
21923+
billingCadence:
21924+
type: string
21925+
format: duration
21926+
description: |-
21927+
The default billing cadence for subscriptions using this plan.
21928+
Defines how often customers are billed using ISO8601 duration format.
21929+
Examples: "P1M" (monthly), "P3M" (quarterly), "P1Y" (annually).
21930+
title: Billing cadence
21931+
example: P1M
21932+
readOnly: true
21933+
proRatingConfig:
21934+
allOf:
21935+
- $ref: '#/components/schemas/ProRatingConfig'
21936+
description: Default pro-rating configuration for subscriptions using this plan.
21937+
title: Pro-rating configuration
21938+
default:
21939+
enabled: true
21940+
mode: prorate_prices
21941+
readOnly: true
2190221942
alignment:
2190321943
allOf:
2190421944
- $ref: '#/components/schemas/SubscriptionAlignment'

api/spec/src/productcatalog/subscription.tsp

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ import "@typespec/http";
22
import "@typespec/rest";
33
import "@typespec/openapi";
44
import "@typespec/openapi3";
5-
import "@typespec/versioning";
65

76
import "../types.tsp";
87
import "../errors.tsp";
@@ -11,10 +10,7 @@ import "./ratecards.tsp";
1110
import "./discounts.tsp";
1211
import "../entitlements/main.tsp";
1312

14-
using TypeSpec.Http;
15-
using TypeSpec.Rest;
1613
using TypeSpec.OpenAPI;
17-
using TypeSpec.Versioning;
1814

1915
namespace OpenMeter.ProductCatalog;
2016

@@ -95,6 +91,24 @@ model Subscription {
9591
*/
9692
@summary("Currency")
9793
currency: CurrencyCode = "USD";
94+
95+
/**
96+
* The billing cadence for the subscriptions.
97+
* Defines how often customers are billed using ISO8601 duration format.
98+
* Examples: "P1M" (monthly), "P3M" (quarterly), "P1Y" (annually).
99+
*/
100+
@visibility(Lifecycle.Read)
101+
@summary("Billing cadence")
102+
@encode(DurationKnownEncoding.ISO8601)
103+
@example(duration.fromISO("P1M"))
104+
billingCadence: duration;
105+
106+
/**
107+
* The pro-rating configuration for the subscriptions.
108+
*/
109+
@visibility(Lifecycle.Read)
110+
@summary("Pro-rating configuration")
111+
proRatingConfig?: ProRatingConfig = #{ enabled: true, mode: ProRatingMode.proratePrices };
98112
}
99113

100114
/**

e2e/productcatalog_test.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -237,6 +237,10 @@ func TestPlan(t *testing.T) {
237237
Description: planCreate.Description,
238238
BillingCadence: planCreate.BillingCadence,
239239
Phases: planCreate.Phases,
240+
ProRatingConfig: &api.ProRatingConfig{
241+
Mode: "prorate_prices",
242+
Enabled: true,
243+
},
240244
}
241245

242246
t.Run("Should create a plan on happy path", func(t *testing.T) {
@@ -432,6 +436,9 @@ func TestPlan(t *testing.T) {
432436
assert.Nil(t, subscription.Plan)
433437

434438
customSubscriptionId = subscription.Id
439+
require.Equal(t, "P1M", subscription.BillingCadence)
440+
require.Equal(t, api.ProRatingModeProratePrices, subscription.ProRatingConfig.Mode)
441+
require.True(t, subscription.ProRatingConfig.Enabled)
435442
})
436443

437444
t.Run("Should list customer subscriptions", func(t *testing.T) {
@@ -487,6 +494,9 @@ func TestPlan(t *testing.T) {
487494
assert.Equal(t, planId, subscription.Plan.Id)
488495

489496
subscriptionId = subscription.Id
497+
require.Equal(t, "P1M", subscription.BillingCadence)
498+
require.Equal(t, api.ProRatingModeProratePrices, subscription.ProRatingConfig.Mode)
499+
require.True(t, subscription.ProRatingConfig.Enabled)
490500
})
491501

492502
t.Run("Should retrieve the subscription", func(t *testing.T) {

openmeter/billing/worker/subscription/sync_test.go

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -158,7 +158,7 @@ func (s *SubscriptionHandlerTestSuite) TestSubscriptionHappyPath() {
158158
Key: "test-plan",
159159
Version: 1,
160160
Currency: currency.USD,
161-
BillingCadence: isodate.String("P1M"),
161+
BillingCadence: isodate.MustParse(s.T(), "P1M"),
162162
ProRatingConfig: productcatalog.ProRatingConfig{
163163
Enabled: true,
164164
Mode: productcatalog.ProRatingModeProratePrices,
@@ -575,7 +575,7 @@ func (s *SubscriptionHandlerTestSuite) TestInArrearsProrating() {
575575
Key: "test-plan",
576576
Version: 1,
577577
Currency: currency.USD,
578-
BillingCadence: isodate.String("P1M"),
578+
BillingCadence: isodate.MustParse(s.T(), "P1M"),
579579
ProRatingConfig: productcatalog.ProRatingConfig{
580580
Enabled: true,
581581
Mode: productcatalog.ProRatingModeProratePrices,
@@ -1388,7 +1388,7 @@ func (s *SubscriptionHandlerTestSuite) TestDefactoZeroPrices() {
13881388
Alignment: productcatalog.Alignment{
13891389
BillablesMustAlign: true,
13901390
},
1391-
BillingCadence: isodate.String("P1M"),
1391+
BillingCadence: isodate.MustParse(s.T(), "P1M"),
13921392
ProRatingConfig: productcatalog.ProRatingConfig{
13931393
Enabled: true,
13941394
Mode: productcatalog.ProRatingModeProratePrices,
@@ -1464,7 +1464,7 @@ func (s *SubscriptionHandlerTestSuite) TestAlignedSubscriptionInvoicing() {
14641464
Alignment: productcatalog.Alignment{
14651465
BillablesMustAlign: true,
14661466
},
1467-
BillingCadence: isodate.String("P1M"),
1467+
BillingCadence: isodate.MustParse(s.T(), "P1M"),
14681468
ProRatingConfig: productcatalog.ProRatingConfig{
14691469
Enabled: true,
14701470
Mode: productcatalog.ProRatingModeProratePrices,
@@ -1687,7 +1687,7 @@ func (s *SubscriptionHandlerTestSuite) TestAlignedSubscriptionCancellation() {
16871687
Alignment: productcatalog.Alignment{
16881688
BillablesMustAlign: true,
16891689
},
1690-
BillingCadence: isodate.String("P1M"),
1690+
BillingCadence: isodate.MustParse(s.T(), "P1M"),
16911691
ProRatingConfig: productcatalog.ProRatingConfig{
16921692
Enabled: true,
16931693
Mode: productcatalog.ProRatingModeProratePrices,
@@ -1856,7 +1856,7 @@ func (s *SubscriptionHandlerTestSuite) TestAlignedSubscriptionProgressiveBilling
18561856
Alignment: productcatalog.Alignment{
18571857
BillablesMustAlign: true,
18581858
},
1859-
BillingCadence: isodate.String("P1M"),
1859+
BillingCadence: isodate.MustParse(s.T(), "P1M"),
18601860
ProRatingConfig: productcatalog.ProRatingConfig{
18611861
Enabled: true,
18621862
Mode: productcatalog.ProRatingModeProratePrices,
@@ -3807,7 +3807,7 @@ func (s *SubscriptionHandlerTestSuite) createSubscriptionFromPlanPhases(phases [
38073807
Key: "test-plan",
38083808
Version: 1,
38093809
Currency: currency.USD,
3810-
BillingCadence: isodate.String("P1M"),
3810+
BillingCadence: isodate.MustParse(s.T(), "P1M"),
38113811
ProRatingConfig: productcatalog.ProRatingConfig{
38123812
Enabled: true,
38133813
Mode: productcatalog.ProRatingModeProratePrices,

openmeter/ent/db/migrate/schema.go

Lines changed: 5 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)