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.
- checksums.yaml +7 -0
- data/LICENSE +15 -0
- data/README.md +73 -0
- data/Rakefile +25 -0
- data/app/controllers/rsb/entitlements/admin/payment_requests_controller.rb +112 -0
- data/app/controllers/rsb/entitlements/admin/plans_controller.rb +91 -0
- data/app/controllers/rsb/entitlements/admin/usage_counters_controller.rb +69 -0
- data/app/jobs/rsb/entitlements/application_job.rb +8 -0
- data/app/jobs/rsb/entitlements/entitlement_expiration_job.rb +15 -0
- data/app/jobs/rsb/entitlements/payment_request_expiration_job.rb +31 -0
- data/app/models/concerns/rsb/entitlements/entitleable.rb +210 -0
- data/app/models/rsb/entitlements/application_record.rb +10 -0
- data/app/models/rsb/entitlements/entitlement.rb +68 -0
- data/app/models/rsb/entitlements/payment_request.rb +70 -0
- data/app/models/rsb/entitlements/plan.rb +83 -0
- data/app/models/rsb/entitlements/usage_counter.rb +64 -0
- data/app/services/rsb/entitlements/usage_counter_service.rb +94 -0
- data/app/views/rsb/entitlements/admin/payment_requests/index.html.erb +98 -0
- data/app/views/rsb/entitlements/admin/payment_requests/show.html.erb +137 -0
- data/app/views/rsb/entitlements/admin/plans/_form.html.erb +202 -0
- data/app/views/rsb/entitlements/admin/plans/edit.html.erb +9 -0
- data/app/views/rsb/entitlements/admin/plans/index.html.erb +74 -0
- data/app/views/rsb/entitlements/admin/plans/new.html.erb +9 -0
- data/app/views/rsb/entitlements/admin/plans/show.html.erb +94 -0
- data/app/views/rsb/entitlements/admin/usage_counters/index.html.erb +110 -0
- data/app/views/rsb/entitlements/admin/usage_counters/trend.html.erb +57 -0
- data/config/locales/admin.en.yml +25 -0
- data/db/migrate/20260208200001_create_rsb_entitlements_plans.rb +21 -0
- data/db/migrate/20260208200002_create_rsb_entitlements_entitlements.rb +23 -0
- data/db/migrate/20260208200003_create_rsb_entitlements_usage_counters.rb +21 -0
- data/db/migrate/20260208200004_create_rsb_entitlements_payment_requests.rb +37 -0
- data/db/migrate/20260213000001_rework_usage_counters_to_ledger.rb +81 -0
- data/lib/generators/rsb/entitlements/install/install_generator.rb +26 -0
- data/lib/rsb/entitlements/configuration.rb +19 -0
- data/lib/rsb/entitlements/engine.rb +134 -0
- data/lib/rsb/entitlements/payment_provider/base.rb +148 -0
- data/lib/rsb/entitlements/payment_provider/wire.rb +188 -0
- data/lib/rsb/entitlements/period_key_calculator.rb +57 -0
- data/lib/rsb/entitlements/provider_definition.rb +43 -0
- data/lib/rsb/entitlements/provider_registry.rb +145 -0
- data/lib/rsb/entitlements/settings_schema.rb +47 -0
- data/lib/rsb/entitlements/test_helper.rb +114 -0
- data/lib/rsb/entitlements/version.rb +9 -0
- data/lib/rsb/entitlements.rb +39 -0
- 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,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: []
|