rsb-entitlements 0.9.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +15 -0
  3. data/README.md +73 -0
  4. data/Rakefile +25 -0
  5. data/app/controllers/rsb/entitlements/admin/payment_requests_controller.rb +112 -0
  6. data/app/controllers/rsb/entitlements/admin/plans_controller.rb +91 -0
  7. data/app/controllers/rsb/entitlements/admin/usage_counters_controller.rb +69 -0
  8. data/app/jobs/rsb/entitlements/application_job.rb +8 -0
  9. data/app/jobs/rsb/entitlements/entitlement_expiration_job.rb +15 -0
  10. data/app/jobs/rsb/entitlements/payment_request_expiration_job.rb +31 -0
  11. data/app/models/concerns/rsb/entitlements/entitleable.rb +210 -0
  12. data/app/models/rsb/entitlements/application_record.rb +10 -0
  13. data/app/models/rsb/entitlements/entitlement.rb +68 -0
  14. data/app/models/rsb/entitlements/payment_request.rb +70 -0
  15. data/app/models/rsb/entitlements/plan.rb +83 -0
  16. data/app/models/rsb/entitlements/usage_counter.rb +64 -0
  17. data/app/services/rsb/entitlements/usage_counter_service.rb +94 -0
  18. data/app/views/rsb/entitlements/admin/payment_requests/index.html.erb +98 -0
  19. data/app/views/rsb/entitlements/admin/payment_requests/show.html.erb +137 -0
  20. data/app/views/rsb/entitlements/admin/plans/_form.html.erb +202 -0
  21. data/app/views/rsb/entitlements/admin/plans/edit.html.erb +9 -0
  22. data/app/views/rsb/entitlements/admin/plans/index.html.erb +74 -0
  23. data/app/views/rsb/entitlements/admin/plans/new.html.erb +9 -0
  24. data/app/views/rsb/entitlements/admin/plans/show.html.erb +94 -0
  25. data/app/views/rsb/entitlements/admin/usage_counters/index.html.erb +110 -0
  26. data/app/views/rsb/entitlements/admin/usage_counters/trend.html.erb +57 -0
  27. data/config/locales/admin.en.yml +25 -0
  28. data/db/migrate/20260208200001_create_rsb_entitlements_plans.rb +21 -0
  29. data/db/migrate/20260208200002_create_rsb_entitlements_entitlements.rb +23 -0
  30. data/db/migrate/20260208200003_create_rsb_entitlements_usage_counters.rb +21 -0
  31. data/db/migrate/20260208200004_create_rsb_entitlements_payment_requests.rb +37 -0
  32. data/db/migrate/20260213000001_rework_usage_counters_to_ledger.rb +81 -0
  33. data/lib/generators/rsb/entitlements/install/install_generator.rb +26 -0
  34. data/lib/rsb/entitlements/configuration.rb +19 -0
  35. data/lib/rsb/entitlements/engine.rb +134 -0
  36. data/lib/rsb/entitlements/payment_provider/base.rb +148 -0
  37. data/lib/rsb/entitlements/payment_provider/wire.rb +188 -0
  38. data/lib/rsb/entitlements/period_key_calculator.rb +57 -0
  39. data/lib/rsb/entitlements/provider_definition.rb +43 -0
  40. data/lib/rsb/entitlements/provider_registry.rb +145 -0
  41. data/lib/rsb/entitlements/settings_schema.rb +47 -0
  42. data/lib/rsb/entitlements/test_helper.rb +114 -0
  43. data/lib/rsb/entitlements/version.rb +9 -0
  44. data/lib/rsb/entitlements.rb +39 -0
  45. metadata +116 -0
@@ -0,0 +1,57 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RSB
4
+ module Entitlements
5
+ # Computes period keys for usage tracking from period types.
6
+ #
7
+ # Period keys are used to bucket usage records by time period:
8
+ # - daily: "YYYY-MM-DD" (ISO 8601 date)
9
+ # - weekly: "YYYY-WNN" (ISO 8601 week number, Monday start)
10
+ # - monthly: "YYYY-MM"
11
+ # - nil/empty: "__cumulative__" (lifetime/no reset)
12
+ #
13
+ # @example
14
+ # PeriodKeyCalculator.current_key("daily")
15
+ # # => "2026-02-13"
16
+ #
17
+ # PeriodKeyCalculator.current_key("weekly", Time.new(2026, 2, 13))
18
+ # # => "2026-W07"
19
+ #
20
+ # PeriodKeyCalculator.current_key(nil)
21
+ # # => "__cumulative__"
22
+ module PeriodKeyCalculator
23
+ # Constant for cumulative (non-resetting) period keys.
24
+ CUMULATIVE_KEY = '__cumulative__'
25
+
26
+ # Compute the period key for a given period type and time.
27
+ #
28
+ # @param period [String, Symbol, nil] The period type ("daily", "weekly", "monthly", or nil)
29
+ # @param time [Time, ActiveSupport::TimeWithZone] The time to compute the key for (defaults to Time.current)
30
+ # @return [String] The period key string
31
+ #
32
+ # @example Daily period
33
+ # current_key("daily", Time.new(2026, 2, 13, 10, 30, 0))
34
+ # # => "2026-02-13"
35
+ #
36
+ # @example Weekly period
37
+ # current_key("weekly", Time.new(2026, 2, 13, 10, 0, 0))
38
+ # # => "2026-W07"
39
+ #
40
+ # @example Monthly period
41
+ # current_key("monthly", Time.new(2026, 2, 13, 10, 0, 0))
42
+ # # => "2026-02"
43
+ #
44
+ # @example Cumulative period
45
+ # current_key(nil)
46
+ # # => "__cumulative__"
47
+ def self.current_key(period, time = Time.current)
48
+ case period&.to_s
49
+ when 'daily' then time.strftime('%Y-%m-%d')
50
+ when 'weekly' then time.strftime('%G-W%V')
51
+ when 'monthly' then time.strftime('%Y-%m')
52
+ else CUMULATIVE_KEY
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RSB
4
+ module Entitlements
5
+ # Immutable data object representing a registered payment provider.
6
+ # Built from a PaymentProvider::Base subclass via .build_from.
7
+ #
8
+ # @example
9
+ # definition = ProviderDefinition.build_from(MyProvider)
10
+ # definition.key # => :my_provider
11
+ # definition.label # => "My Provider"
12
+ # definition.provider_class # => MyProvider
13
+ ProviderDefinition = Data.define(
14
+ :key, # Symbol — unique provider key
15
+ :label, # String — human-readable label
16
+ :provider_class, # Class — the PaymentProvider::Base subclass
17
+ :manual_resolution, # Boolean — whether admin must approve/reject
18
+ :admin_actions, # Array<Symbol> — actions admin can take
19
+ :refundable # Boolean — whether refunds are supported
20
+ ) do
21
+ # Build a ProviderDefinition from a PaymentProvider::Base subclass.
22
+ #
23
+ # @param klass [Class] a class inheriting from PaymentProvider::Base
24
+ # @return [ProviderDefinition]
25
+ # @raise [ArgumentError] if klass does not inherit from Base
26
+ def self.build_from(klass)
27
+ unless klass < PaymentProvider::Base
28
+ raise ArgumentError,
29
+ "#{klass} must inherit from RSB::Entitlements::PaymentProvider::Base"
30
+ end
31
+
32
+ new(
33
+ key: klass.provider_key,
34
+ label: klass.provider_label,
35
+ provider_class: klass,
36
+ manual_resolution: klass.manual_resolution?,
37
+ admin_actions: klass.admin_actions,
38
+ refundable: klass.refundable?
39
+ )
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,145 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RSB
4
+ module Entitlements
5
+ # Registry for payment provider classes. Providers register by passing
6
+ # their class (which must inherit from PaymentProvider::Base).
7
+ # The registry validates the class, builds a ProviderDefinition,
8
+ # and registers the provider's settings schema into RSB::Settings.
9
+ #
10
+ # @example
11
+ # RSB::Entitlements.providers.register(MyProvider)
12
+ # RSB::Entitlements.providers.find(:my_provider)
13
+ # RSB::Entitlements.providers.enabled
14
+ class ProviderRegistry
15
+ def initialize
16
+ @definitions = {}
17
+ end
18
+
19
+ # Register a payment provider class.
20
+ #
21
+ # @param provider_class [Class] must inherit from PaymentProvider::Base
22
+ # @return [ProviderDefinition]
23
+ # @raise [ArgumentError] if class is invalid, key is duplicate, or required settings are missing
24
+ def register(provider_class)
25
+ unless provider_class.is_a?(Class) && provider_class < PaymentProvider::Base
26
+ raise ArgumentError,
27
+ "#{provider_class} must inherit from RSB::Entitlements::PaymentProvider::Base"
28
+ end
29
+
30
+ key = provider_class.provider_key
31
+ raise ArgumentError, "Provider key :#{key} is already registered" if @definitions.key?(key)
32
+
33
+ # Register provider's settings schema (if declared)
34
+ register_provider_settings(provider_class)
35
+
36
+ # Validate required settings have non-default values
37
+ validate_required_settings(provider_class)
38
+
39
+ # Build and store the definition
40
+ definition = ProviderDefinition.build_from(provider_class)
41
+ @definitions[key] = definition
42
+ definition
43
+ end
44
+
45
+ # Find a provider definition by key.
46
+ #
47
+ # @param key [Symbol, String] provider key
48
+ # @return [ProviderDefinition, nil]
49
+ def find(key)
50
+ @definitions[key.to_sym]
51
+ end
52
+
53
+ # All registered provider definitions.
54
+ #
55
+ # @return [Array<ProviderDefinition>]
56
+ def all
57
+ @definitions.values
58
+ end
59
+
60
+ # All registered provider keys.
61
+ #
62
+ # @return [Array<Symbol>]
63
+ def keys
64
+ @definitions.keys
65
+ end
66
+
67
+ # Providers where the `entitlements.providers.<key>.enabled` setting is true.
68
+ #
69
+ # @return [Array<ProviderDefinition>]
70
+ def enabled
71
+ all.reject do |definition|
72
+ RSB::Settings.get("entitlements.providers.#{definition.key}.enabled") == false
73
+ end
74
+ end
75
+
76
+ # Array of [label, key] pairs for form dropdowns. Only includes enabled providers.
77
+ #
78
+ # @return [Array<Array(String, String)>]
79
+ def for_select
80
+ enabled.map { |d| [d.label, d.key.to_s] }
81
+ end
82
+
83
+ private
84
+
85
+ # Register the provider's settings schema into RSB::Settings
86
+ # under the `entitlements` category with compound keys like
87
+ # `providers.<key>.enabled`.
88
+ # Adds an `enabled` setting (default: true) unless the provider
89
+ # defines its own `enabled` setting.
90
+ def register_provider_settings(provider_class)
91
+ key = provider_class.provider_key
92
+ schema_block = provider_class.settings_schema
93
+ prefix = "providers.#{key}"
94
+ provider_label = provider_class.provider_label
95
+
96
+ schema = RSB::Settings::Schema.new('entitlements')
97
+
98
+ # Collect provider's custom settings first to check for enabled override
99
+ custom_settings = []
100
+ provider_defines_enabled = false
101
+
102
+ if schema_block
103
+ collector = RSB::Settings::Schema.new('_collector')
104
+ collector.instance_eval(&schema_block)
105
+ custom_settings = collector.definitions
106
+ provider_defines_enabled = custom_settings.any? { |defn| defn.key == :enabled }
107
+ end
108
+
109
+ # Add auto-generated enabled setting only if provider doesn't define it
110
+ unless provider_defines_enabled
111
+ schema.setting :"#{prefix}.enabled",
112
+ type: :boolean,
113
+ default: true,
114
+ description: "Enable #{provider_label} provider"
115
+ end
116
+
117
+ # Register all provider's settings with the prefix
118
+ custom_settings.each do |defn|
119
+ schema.setting :"#{prefix}.#{defn.key}",
120
+ type: defn.type,
121
+ default: defn.default,
122
+ description: defn.description
123
+ end
124
+
125
+ RSB::Settings.registry.register(schema)
126
+ end
127
+
128
+ # Validate that all required settings have non-default values.
129
+ def validate_required_settings(provider_class)
130
+ return if provider_class.required_settings.empty?
131
+
132
+ key = provider_class.provider_key
133
+ missing = provider_class.required_settings.select do |setting_key|
134
+ value = RSB::Settings.get("entitlements.providers.#{key}.#{setting_key}")
135
+ value.nil? || value == ''
136
+ end
137
+
138
+ return if missing.empty?
139
+
140
+ raise ArgumentError,
141
+ "Provider :#{key} has required settings that are not configured: #{missing.join(', ')}"
142
+ end
143
+ end
144
+ end
145
+ end
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RSB
4
+ module Entitlements
5
+ class SettingsSchema
6
+ def self.build
7
+ RSB::Settings::Schema.new('entitlements') do
8
+ setting :default_currency,
9
+ type: :string,
10
+ default: 'usd',
11
+ group: 'General',
12
+ description: 'Default currency code'
13
+
14
+ setting :trial_days,
15
+ type: :integer,
16
+ default: 14,
17
+ group: 'General',
18
+ description: 'Default trial period in days'
19
+
20
+ setting :grace_period_days,
21
+ type: :integer,
22
+ default: 3,
23
+ group: 'General',
24
+ description: 'Grace period after entitlement expiry (days)'
25
+
26
+ setting :auto_create_counters,
27
+ type: :boolean,
28
+ default: true,
29
+ group: 'General',
30
+ description: 'Auto-create usage counters when entitlement is granted'
31
+
32
+ setting :on_plan_change_usage,
33
+ type: :string,
34
+ default: 'continue',
35
+ group: 'General',
36
+ description: "Behavior on plan change: 'continue' (carry over usage) or 'reset' (fresh counter)"
37
+
38
+ setting :payment_request_expiry_hours,
39
+ type: :integer,
40
+ default: 72,
41
+ group: 'General',
42
+ description: 'Default expiry for payment requests (hours)'
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,114 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RSB
4
+ module Entitlements
5
+ module TestHelper
6
+ extend ActiveSupport::Concern
7
+
8
+ included do
9
+ setup do
10
+ RSB::Entitlements.reset!
11
+ end
12
+
13
+ teardown do
14
+ RSB::Entitlements.reset!
15
+ end
16
+ end
17
+
18
+ def create_test_plan(name: 'Test Plan', slug: nil, **overrides)
19
+ slug ||= "test-plan-#{SecureRandom.hex(4)}"
20
+ RSB::Entitlements::Plan.create!({
21
+ name: name,
22
+ slug: slug,
23
+ interval: 'monthly',
24
+ price_cents: 1000,
25
+ currency: 'usd',
26
+ features: {},
27
+ limits: {},
28
+ metadata: {},
29
+ active: true
30
+ }.merge(overrides))
31
+ end
32
+
33
+ def grant_test_entitlement(entitleable, plan: nil, provider: 'admin')
34
+ plan ||= create_test_plan
35
+ entitleable.grant_entitlement(plan: plan, provider: provider)
36
+ end
37
+
38
+ # Register a minimal test provider for use in tests.
39
+ # Returns the provider class.
40
+ #
41
+ # @param key [Symbol] provider key (default: :test)
42
+ # @param label [String] provider label (default: "Test Provider")
43
+ # @param manual_resolution [Boolean] (default: false)
44
+ # @param admin_actions [Array<Symbol>] (default: [])
45
+ # @param refundable [Boolean] (default: false)
46
+ # @param initiate_result [Hash] what initiate! returns (default: { status: :completed })
47
+ # @return [Class] the provider class
48
+ def register_test_provider(
49
+ key: :test,
50
+ label: 'Test Provider',
51
+ manual_resolution: false,
52
+ admin_actions: [],
53
+ refundable: false,
54
+ initiate_result: { status: :completed }
55
+ )
56
+ provider_class = Class.new(RSB::Entitlements::PaymentProvider::Base) do
57
+ define_singleton_method(:provider_key) { key }
58
+ define_singleton_method(:provider_label) { label }
59
+ define_singleton_method(:manual_resolution?) { manual_resolution }
60
+ define_singleton_method(:admin_actions) { admin_actions }
61
+ define_singleton_method(:refundable?) { refundable }
62
+
63
+ define_method(:initiate!) { initiate_result }
64
+ define_method(:complete!) { |_params = {}| nil }
65
+ define_method(:reject!) { |_params = {}| nil }
66
+ end
67
+
68
+ RSB::Entitlements.providers.register(provider_class)
69
+ provider_class
70
+ end
71
+
72
+ # Create a test payment request.
73
+ #
74
+ # @param requestable [ActiveRecord::Base] the polymorphic owner
75
+ # @param plan [RSB::Entitlements::Plan] the plan
76
+ # @param provider_key [String] provider key (default: "wire")
77
+ # @param status [String] status (default: "pending")
78
+ # @return [RSB::Entitlements::PaymentRequest]
79
+ def create_test_payment_request(requestable:, plan:, provider_key: 'wire', status: 'pending', **overrides)
80
+ RSB::Entitlements::PaymentRequest.create!({
81
+ requestable: requestable,
82
+ plan: plan,
83
+ provider_key: provider_key.to_s,
84
+ status: status,
85
+ amount_cents: plan.price_cents,
86
+ currency: plan.currency,
87
+ provider_data: {},
88
+ metadata: {}
89
+ }.merge(overrides))
90
+ end
91
+
92
+ # Create a test usage counter.
93
+ #
94
+ # @param countable [ActiveRecord::Base] the polymorphic owner
95
+ # @param metric [String] metric name
96
+ # @param plan [RSB::Entitlements::Plan] the plan
97
+ # @param period_key [String] period key (default: "__cumulative__")
98
+ # @param current_value [Integer] current usage value (default: 0)
99
+ # @param limit [Integer, nil] usage limit
100
+ # @return [RSB::Entitlements::UsageCounter]
101
+ def create_test_usage_counter(countable:, metric:, plan:, period_key: '__cumulative__', current_value: 0,
102
+ limit: nil)
103
+ RSB::Entitlements::UsageCounter.create!(
104
+ countable: countable,
105
+ metric: metric.to_s,
106
+ plan: plan,
107
+ period_key: period_key,
108
+ current_value: current_value,
109
+ limit: limit
110
+ )
111
+ end
112
+ end
113
+ end
114
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../../../../lib/rsb/version' unless defined?(RSB::VERSION)
4
+
5
+ module RSB
6
+ module Entitlements
7
+ VERSION = RSB::VERSION
8
+ end
9
+ end
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rsb/settings'
4
+ require 'rsb/entitlements/version'
5
+ require 'rsb/entitlements/engine'
6
+ require 'rsb/entitlements/configuration'
7
+ require 'rsb/entitlements/provider_definition'
8
+ require 'rsb/entitlements/provider_registry'
9
+ require 'rsb/entitlements/payment_provider/base'
10
+ require 'rsb/entitlements/payment_provider/wire'
11
+ require 'rsb/entitlements/settings_schema'
12
+ require 'rsb/entitlements/period_key_calculator'
13
+
14
+ module RSB
15
+ module Entitlements
16
+ class << self
17
+ def providers
18
+ @providers ||= ProviderRegistry.new
19
+ end
20
+
21
+ def configure
22
+ yield(configuration)
23
+ end
24
+
25
+ def configuration
26
+ @configuration ||= Configuration.new
27
+ end
28
+
29
+ def settings_schema
30
+ @settings_schema ||= SettingsSchema.build
31
+ end
32
+
33
+ def reset!
34
+ @providers = ProviderRegistry.new
35
+ @configuration = Configuration.new
36
+ end
37
+ end
38
+ end
39
+ end
metadata ADDED
@@ -0,0 +1,116 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rsb-entitlements
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.9.1
5
+ platform: ruby
6
+ authors:
7
+ - Aleksandr Marchenko
8
+ bindir: bin
9
+ cert_chain: []
10
+ date: 1980-01-02 00:00:00.000000000 Z
11
+ dependencies:
12
+ - !ruby/object:Gem::Dependency
13
+ name: rails
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - ">="
17
+ - !ruby/object:Gem::Version
18
+ version: '8.0'
19
+ type: :runtime
20
+ prerelease: false
21
+ version_requirements: !ruby/object:Gem::Requirement
22
+ requirements:
23
+ - - ">="
24
+ - !ruby/object:Gem::Version
25
+ version: '8.0'
26
+ - !ruby/object:Gem::Dependency
27
+ name: rsb-settings
28
+ requirement: !ruby/object:Gem::Requirement
29
+ requirements:
30
+ - - '='
31
+ - !ruby/object:Gem::Version
32
+ version: 0.9.1
33
+ type: :runtime
34
+ prerelease: false
35
+ version_requirements: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - '='
38
+ - !ruby/object:Gem::Version
39
+ version: 0.9.1
40
+ description: Flexible plan-based feature gating, entitlements, and metered usage tracking.
41
+ Drop-in Entitleable concern for any model. Extensible provider registry for payment
42
+ integrations.
43
+ email:
44
+ - alex@marchenko.me
45
+ executables: []
46
+ extensions: []
47
+ extra_rdoc_files: []
48
+ files:
49
+ - LICENSE
50
+ - README.md
51
+ - Rakefile
52
+ - app/controllers/rsb/entitlements/admin/payment_requests_controller.rb
53
+ - app/controllers/rsb/entitlements/admin/plans_controller.rb
54
+ - app/controllers/rsb/entitlements/admin/usage_counters_controller.rb
55
+ - app/jobs/rsb/entitlements/application_job.rb
56
+ - app/jobs/rsb/entitlements/entitlement_expiration_job.rb
57
+ - app/jobs/rsb/entitlements/payment_request_expiration_job.rb
58
+ - app/models/concerns/rsb/entitlements/entitleable.rb
59
+ - app/models/rsb/entitlements/application_record.rb
60
+ - app/models/rsb/entitlements/entitlement.rb
61
+ - app/models/rsb/entitlements/payment_request.rb
62
+ - app/models/rsb/entitlements/plan.rb
63
+ - app/models/rsb/entitlements/usage_counter.rb
64
+ - app/services/rsb/entitlements/usage_counter_service.rb
65
+ - app/views/rsb/entitlements/admin/payment_requests/index.html.erb
66
+ - app/views/rsb/entitlements/admin/payment_requests/show.html.erb
67
+ - app/views/rsb/entitlements/admin/plans/_form.html.erb
68
+ - app/views/rsb/entitlements/admin/plans/edit.html.erb
69
+ - app/views/rsb/entitlements/admin/plans/index.html.erb
70
+ - app/views/rsb/entitlements/admin/plans/new.html.erb
71
+ - app/views/rsb/entitlements/admin/plans/show.html.erb
72
+ - app/views/rsb/entitlements/admin/usage_counters/index.html.erb
73
+ - app/views/rsb/entitlements/admin/usage_counters/trend.html.erb
74
+ - config/locales/admin.en.yml
75
+ - db/migrate/20260208200001_create_rsb_entitlements_plans.rb
76
+ - db/migrate/20260208200002_create_rsb_entitlements_entitlements.rb
77
+ - db/migrate/20260208200003_create_rsb_entitlements_usage_counters.rb
78
+ - db/migrate/20260208200004_create_rsb_entitlements_payment_requests.rb
79
+ - db/migrate/20260213000001_rework_usage_counters_to_ledger.rb
80
+ - lib/generators/rsb/entitlements/install/install_generator.rb
81
+ - lib/rsb/entitlements.rb
82
+ - lib/rsb/entitlements/configuration.rb
83
+ - lib/rsb/entitlements/engine.rb
84
+ - lib/rsb/entitlements/payment_provider/base.rb
85
+ - lib/rsb/entitlements/payment_provider/wire.rb
86
+ - lib/rsb/entitlements/period_key_calculator.rb
87
+ - lib/rsb/entitlements/provider_definition.rb
88
+ - lib/rsb/entitlements/provider_registry.rb
89
+ - lib/rsb/entitlements/settings_schema.rb
90
+ - lib/rsb/entitlements/test_helper.rb
91
+ - lib/rsb/entitlements/version.rb
92
+ homepage: https://github.com/Rails-SaaS-Builder/rails-saas-builder
93
+ licenses:
94
+ - LGPL-3.0
95
+ metadata:
96
+ source_code_uri: https://github.com/Rails-SaaS-Builder/rails-saas-builder
97
+ bug_tracker_uri: https://github.com/Rails-SaaS-Builder/rails-saas-builder/issues
98
+ changelog_uri: https://github.com/Rails-SaaS-Builder/rails-saas-builder/blob/master/CHANGELOG.md
99
+ rdoc_options: []
100
+ require_paths:
101
+ - lib
102
+ required_ruby_version: !ruby/object:Gem::Requirement
103
+ requirements:
104
+ - - ">="
105
+ - !ruby/object:Gem::Version
106
+ version: '3.2'
107
+ required_rubygems_version: !ruby/object:Gem::Requirement
108
+ requirements:
109
+ - - ">="
110
+ - !ruby/object:Gem::Version
111
+ version: '0'
112
+ requirements: []
113
+ rubygems_version: 3.6.8
114
+ specification_version: 4
115
+ summary: Plans, entitlements & usage tracking for Rails SaaS Builder
116
+ test_files: []