pay-lago 0.1.0 → 0.1.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 +4 -4
- data/CHANGELOG.md +12 -0
- data/Gemfile.lock +2 -2
- data/README.md +2 -5
- data/app/models/concerns/pay/lago/pay_payment_method_extensions.rb +23 -0
- data/docs/4_payment_methods.md +40 -0
- data/lib/pay/lago/billable.rb +53 -12
- data/lib/pay/lago/engine.rb +2 -1
- data/lib/pay/lago/payment_method.rb +44 -6
- data/lib/pay/lago/subscription.rb +6 -13
- data/lib/pay/lago/version.rb +1 -1
- data/lib/pay/lago/webhooks/customer_payment_provider_created.rb +1 -7
- data/pay-lago.gemspec +1 -1
- data/test/dummy/db/migrate/1_create_pay_tables.rb +93 -0
- data/test/dummy/db/schema.rb +17 -16
- data/test/fixtures/pay/customers.yml +1 -0
- data/test/pay/lago/billable_test.rb +1 -1
- data/test/pay/lago/payment_method_test.rb +34 -0
- data/test/pay/lago/subscription_test.rb +3 -5
- data/test/vcr_cassettes/test_PaymentMethod_can_be_made_default__updating_Lago.yml +163 -0
- data/test/vcr_cassettes/test_add_payment_method_to_lago.yml +62 -8
- data/test/vcr_cassettes/test_can_get_lago_processor_customer.yml +7 -7
- data/test/vcr_cassettes/test_can_make_a_lago_processor_charge.yml +22 -22
- data/test/vcr_cassettes/test_generates_lago_processor_id.yml +8 -59
- data/test/vcr_cassettes/test_lago_cannot_change_quantity.yml +16 -16
- data/test/vcr_cassettes/test_lago_processor_cancel.yml +32 -32
- data/test/vcr_cassettes/test_lago_processor_charge.yml +55 -55
- data/test/vcr_cassettes/test_lago_processor_on_grace_period__is_always_false.yml +16 -16
- data/test/vcr_cassettes/test_lago_processor_pause_raises_an_error.yml +16 -16
- data/test/vcr_cassettes/test_lago_processor_paused__is_always_false.yml +16 -16
- data/test/vcr_cassettes/test_lago_processor_refund_with_premium.yml +64 -64
- data/test/vcr_cassettes/test_lago_processor_resume_raises_an_error.yml +16 -16
- data/test/vcr_cassettes/test_lago_processor_subscribe.yml +17 -16
- data/test/vcr_cassettes/test_lago_processor_subscription.yml +24 -24
- data/test/vcr_cassettes/test_lago_processor_swap.yml +86 -32
- metadata +10 -5
- /data/docs/{4_webhooks.md → 5_webhooks.md} +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: '09ba7ef76f7ab46e24c8a7602c22eaba9705551eb7406304ff9b3533fcda48a4'
|
4
|
+
data.tar.gz: a5c1b1cfee26e0afd36431a5e2480807ee03a378bf01829facbf0bcf9dc271de
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 427777503e12fbddfc7b63ec98d945f98695dfb7f3aee42cfed8a3acd9002cf892c2fc0cce52c46b63cfdfda596da479a7862eb706e05b680a0fa81d97d6be80
|
7
|
+
data.tar.gz: c579510c4be89f0e92b30ce057722561c5fed149c9808f77a1518f867dbebde53560de1662885f85f1e7d401313658914653eaf018382b7dae55b40e42cd89b6
|
data/CHANGELOG.md
CHANGED
@@ -1,2 +1,14 @@
|
|
1
|
+
## [0.1.1] - 2023-12-11
|
2
|
+
### Added
|
3
|
+
- Scope for Lago payment methods with a given provider.
|
4
|
+
- Method to find a Lago payment method by provider, and provider id.
|
5
|
+
- Added `pull!` and `push!` methods to billable, and payment method, to better control syncing with Lago.
|
6
|
+
- Method to retrieve a payment method on billable.
|
7
|
+
|
8
|
+
### Changed
|
9
|
+
- Dependency `lago-ruby-client` was upgraded to version 0.52.2.pre.beta.
|
10
|
+
- Improved API for adding a payment method to billable.
|
11
|
+
- Method `subscription` on subscription can be passed `reload: true` to reload the subscription data.
|
12
|
+
|
1
13
|
## [0.1.0] - 2023-10-23
|
2
14
|
- Initial release
|
data/Gemfile.lock
CHANGED
@@ -11,7 +11,7 @@ PATH
|
|
11
11
|
remote: .
|
12
12
|
specs:
|
13
13
|
pay-lago (0.1.0)
|
14
|
-
lago-ruby-client (= 0.
|
14
|
+
lago-ruby-client (= 0.53.0.pre.beta)
|
15
15
|
pay (~> 6.8)
|
16
16
|
|
17
17
|
GEM
|
@@ -119,7 +119,7 @@ GEM
|
|
119
119
|
reline (>= 0.3.8)
|
120
120
|
json (2.6.3)
|
121
121
|
jwt (2.7.1)
|
122
|
-
lago-ruby-client (0.
|
122
|
+
lago-ruby-client (0.53.0.pre.beta)
|
123
123
|
jwt
|
124
124
|
openssl
|
125
125
|
language_server-protocol (3.17.0.3)
|
data/README.md
CHANGED
@@ -63,9 +63,6 @@ for direct use of the [Lago API](https://docs.getlago.com/api-reference/intro).
|
|
63
63
|
|
64
64
|
The client instance can be accessed from `Pay::Lago.client`.
|
65
65
|
|
66
|
-
#### Please Note:
|
67
|
-
For any API calls that would use a GET, the external_id must be [URI encoded](https://ruby-doc.org/current/stdlibs/uri/URI.html#method-c-encode_www_form_component), as the lago-ruby-client gem does not currently do this itself. See [this issue](https://github.com/getlago/lago-ruby-client/issues/136).
|
68
|
-
|
69
66
|
## Development
|
70
67
|
|
71
68
|
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
@@ -74,7 +71,7 @@ To install this gem onto your local machine, run `bundle exec rake install`. To
|
|
74
71
|
|
75
72
|
## Contributing
|
76
73
|
|
77
|
-
Bug reports and pull requests are welcome on GitHub at https://github.com/
|
74
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/demingfactor/pay-lago. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://github.com/demingfactor/pay-lago/blob/master/CODE_OF_CONDUCT.md).
|
78
75
|
|
79
76
|
## License
|
80
77
|
|
@@ -82,4 +79,4 @@ The gem is available as open source under the terms of the [MIT License](https:/
|
|
82
79
|
|
83
80
|
## Code of Conduct
|
84
81
|
|
85
|
-
Everyone interacting in the Pay::Lago project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/
|
82
|
+
Everyone interacting in the Pay::Lago project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/demingfactor/pay-lago/blob/master/CODE_OF_CONDUCT.md).
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Pay
|
2
|
+
module Lago
|
3
|
+
module PayPaymentMethodExtensions
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
|
6
|
+
included do
|
7
|
+
scope :with_provider, ->(provider) { where("pay_payment_methods.data->>'payment_provider' = ?", provider) }
|
8
|
+
end
|
9
|
+
|
10
|
+
def provider
|
11
|
+
data["payment_provider"].to_sym
|
12
|
+
rescue
|
13
|
+
nil
|
14
|
+
end
|
15
|
+
|
16
|
+
class_methods do
|
17
|
+
def find_by_lago_provider_and_id(provider, provider_id)
|
18
|
+
with_provider(provider).find_by_processor_and_id(:lago, provider_id)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
# Payment Methods
|
2
|
+
|
3
|
+
## Adding a Payment Method to a Customer
|
4
|
+
|
5
|
+
Lago uses the default method of payment for a given customer. As such, Payment Methods in this gem actually
|
6
|
+
store customer information of the given provider, rather than the payment method itself.
|
7
|
+
|
8
|
+
```ruby
|
9
|
+
# Adding a Stripe customer as a Payment Method
|
10
|
+
customer = Pay::Customer.find(1234)
|
11
|
+
customer.add_payment_method(:stripe, "cus_1234")
|
12
|
+
```
|
13
|
+
|
14
|
+
```ruby
|
15
|
+
# Adding a Stripe customer as a Payment Method, but make it not the default.
|
16
|
+
customer = Pay::Customer.find(1234)
|
17
|
+
customer.add_payment_method(:stripe, "cus_1234", default: false)
|
18
|
+
```
|
19
|
+
|
20
|
+
```ruby
|
21
|
+
# Adding a Stripe customer as a Payment Method, but make it not sync with Lago.
|
22
|
+
# NOTE: Syncing with Lago will only work anyways if default is true (which it is by default).
|
23
|
+
customer = Pay::Customer.find(1234)
|
24
|
+
customer.add_payment_method(:stripe, "cus_1234", sync: false)
|
25
|
+
```
|
26
|
+
|
27
|
+
## Retrieving a Payment Method
|
28
|
+
|
29
|
+
```ruby
|
30
|
+
# Retrieve a Payment Method with a given ID.
|
31
|
+
customer = Pay::Customer.find(1234)
|
32
|
+
customer.get_payment_method(:stripe, "cus_1234")
|
33
|
+
```
|
34
|
+
|
35
|
+
```ruby
|
36
|
+
# If no Payment Method ID is given, it will return either the first Payment Method
|
37
|
+
# for the customer with the given provider, or the default Payment Method (if provider matches).
|
38
|
+
customer = Pay::Customer.find(1234)
|
39
|
+
customer.get_payment_method(:stripe)
|
40
|
+
```
|
data/lib/pay/lago/billable.rb
CHANGED
@@ -39,21 +39,36 @@ module Pay
|
|
39
39
|
|
40
40
|
def customer
|
41
41
|
begin
|
42
|
-
lago_customer = Lago.client.customers.get(
|
42
|
+
lago_customer = Lago.client.customers.get(pay_external_id)
|
43
43
|
rescue ::Lago::Api::HttpError
|
44
44
|
lago_customer = Lago.client.customers.create(customer_attributes(pay_external_id))
|
45
45
|
end
|
46
|
-
|
46
|
+
pull!(lago_customer)
|
47
47
|
lago_customer
|
48
48
|
rescue ::Lago::Api::HttpError => e
|
49
49
|
raise Pay::Lago::Error, e
|
50
50
|
end
|
51
51
|
|
52
|
-
def update_customer!(
|
52
|
+
def update_customer!(attributes = {})
|
53
|
+
attributes = symbolize_recursive(attributes)
|
53
54
|
new_attributes = Lago.openstruct_to_h(customer).except(:lago_id)
|
54
|
-
Lago.client.customers.create(
|
55
|
+
lago_customer = Lago.client.customers.create(
|
55
56
|
new_attributes.merge(attributes.except(:external_id))
|
56
57
|
)
|
58
|
+
pull!(lago_customer)
|
59
|
+
lago_customer
|
60
|
+
end
|
61
|
+
|
62
|
+
def pull!(lago_customer = customer, force: false)
|
63
|
+
if pay_customer.processor_id.present? && pay_customer.processor_id != lago_customer.external_id && !force
|
64
|
+
raise Pay::Lago::Error.new("Error syncing Lago Customer: IDs do not match!")
|
65
|
+
end
|
66
|
+
new_data = Pay::Lago.openstruct_to_h(lago_customer)
|
67
|
+
pay_customer.update!(processor_id: lago_customer.external_id, data: new_data)
|
68
|
+
end
|
69
|
+
|
70
|
+
def push!
|
71
|
+
update_customer!(pay_customer.data)
|
57
72
|
end
|
58
73
|
|
59
74
|
def charge(amount = nil, addon: nil, options: {})
|
@@ -91,7 +106,7 @@ module Pay
|
|
91
106
|
|
92
107
|
begin
|
93
108
|
subscription = Lago.client.subscriptions.create(attributes)
|
94
|
-
rescue ::Lago::Api::HttpError
|
109
|
+
rescue ::Lago::Api::HttpError => e
|
95
110
|
pay_subscription.destroy!
|
96
111
|
raise Pay::Lago::Error, e
|
97
112
|
end
|
@@ -100,12 +115,38 @@ module Pay
|
|
100
115
|
Pay::Lago::Subscription.sync(lago_customer.external_id, external_id, object: subscription)
|
101
116
|
end
|
102
117
|
|
103
|
-
def
|
104
|
-
Pay::Lago::
|
118
|
+
def get_payment_method(provider, provider_id = nil)
|
119
|
+
raise Pay::Lago::Error.new("Invalid provider!") unless Pay::Lago::PaymentMethod.valid_provider?(provider)
|
120
|
+
return Pay::PaymentMethod.find_by_lago_provider_and_id(provider, provider_id) if provider_id.present?
|
121
|
+
return pay_customer.default_payment_method if pay_customer.default_payment_method&.provider == provider
|
122
|
+
Pay::PaymentMethod.with_provider(provider).first
|
123
|
+
end
|
124
|
+
|
125
|
+
def add_payment_method(provider, provider_id, default: true, sync: true, options: {})
|
126
|
+
raise Pay::Lago::Error.new("Invalid provider!") unless Pay::Lago::PaymentMethod.valid_provider?(provider)
|
127
|
+
|
128
|
+
payment_method = pay_customer.payment_methods.with_provider(provider).where(processor_id: provider_id).first
|
129
|
+
payment_method ||= Pay::PaymentMethod.create(
|
130
|
+
processor_id: provider_id,
|
131
|
+
type: "card",
|
132
|
+
customer: pay_customer, data: options.merge(payment_provider: provider, provider_customer_id: provider_id)
|
133
|
+
)
|
134
|
+
|
135
|
+
payment_method.make_default! if default
|
136
|
+
payment_method.payment_processor.push! if sync && default
|
137
|
+
|
138
|
+
payment_method
|
139
|
+
end
|
140
|
+
|
141
|
+
def clear_payment_method!
|
142
|
+
data = (pay_customer.data || {}).merge(
|
143
|
+
"billing_configuration": {payment_provider: nil, payment_method_id: nil, provider_customer_id: nil, provider_payment_methods: nil}
|
144
|
+
)
|
145
|
+
update_customer!(data)
|
105
146
|
end
|
106
147
|
|
107
|
-
def processor_subscription(subscription_id,
|
108
|
-
Pay::Lago
|
148
|
+
def processor_subscription(subscription_id, **_options)
|
149
|
+
Pay::Lago.client.subscriptions.get(subscription_id)
|
109
150
|
end
|
110
151
|
|
111
152
|
def trial_end_date(subscription)
|
@@ -139,9 +180,9 @@ module Pay
|
|
139
180
|
raise Pay::Lago::Error, e
|
140
181
|
end
|
141
182
|
|
142
|
-
def
|
143
|
-
return
|
144
|
-
|
183
|
+
def symbolize_recursive(hash)
|
184
|
+
return hash unless hash.is_a? Hash
|
185
|
+
hash.map { |key, value| [key.is_a?(String) ? key.to_sym : key, symbolize_recursive(value)] }.to_h
|
145
186
|
end
|
146
187
|
end
|
147
188
|
end
|
data/lib/pay/lago/engine.rb
CHANGED
@@ -3,7 +3,7 @@ module Pay
|
|
3
3
|
class Engine < ::Rails::Engine
|
4
4
|
engine_name "pay_lago"
|
5
5
|
|
6
|
-
initializer "pay_lago.processors" do |app|
|
6
|
+
initializer "pay_lago.processors", after: "pay.processors" do |app|
|
7
7
|
ActiveSupport.on_load(:active_record) do
|
8
8
|
include Pay::Lago::Attributes
|
9
9
|
end
|
@@ -18,6 +18,7 @@ module Pay
|
|
18
18
|
Pay::Customer.include Pay::Lago::PayCustomerExtensions
|
19
19
|
Pay::Charge.include Pay::Lago::PayExtensions
|
20
20
|
Pay::Subscription.include Pay::Lago::PayExtensions
|
21
|
+
Pay::PaymentMethod.include Pay::Lago::PayPaymentMethodExtensions
|
21
22
|
|
22
23
|
# Prepend Pay::Lago extensions
|
23
24
|
Pay::Webhook.prepend Pay::Lago::WebhookExtensions
|
@@ -1,23 +1,40 @@
|
|
1
1
|
module Pay
|
2
2
|
module Lago
|
3
3
|
class PaymentMethod
|
4
|
+
VALID_PROVIDERS = %i[stripe adyen gocardless]
|
4
5
|
attr_reader :pay_payment_method
|
5
6
|
|
6
7
|
delegate :customer, :processor_id, to: :pay_payment_method
|
7
8
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
def self.valid_provider?(provider)
|
10
|
+
VALID_PROVIDERS.include?(provider.to_s.to_sym)
|
11
|
+
end
|
12
|
+
|
13
|
+
# Lago doesn't provide PaymentMethod IDs, so we have to lookup via the Customer.
|
14
|
+
# The most recently synced payment method is *always* the default.
|
15
|
+
def self.sync(lago_customer)
|
16
|
+
pay_customer = Pay::Customer.find_by(processor_id: lago_customer.external_id)
|
17
|
+
if pay_customer.blank?
|
18
|
+
Rails.logger.debug "Pay::Customer #{lago_customer.external_id} is not in the database while syncing Payment Method
|
19
|
+
#{lago_customer.provider_customer_id}"
|
20
|
+
return
|
21
|
+
end
|
22
|
+
|
12
23
|
payment_data = lago_customer.billing_configuration
|
24
|
+
provider_id = payment_data.provider_customer_id
|
25
|
+
|
26
|
+
payment_method = pay_customer.payment_methods.find_by(processor_id: provider_id)
|
27
|
+
payment_method ||= pay_customer.build_default_payment_method
|
13
28
|
|
14
29
|
payment_method_attr = {
|
15
|
-
processor_id:
|
30
|
+
processor_id: provider_id,
|
16
31
|
type: "card",
|
17
32
|
data: Lago.openstruct_to_h(payment_data)
|
18
33
|
}
|
19
34
|
|
20
35
|
payment_method.update!(payment_method_attr)
|
36
|
+
payment_method.make_default!
|
37
|
+
|
21
38
|
payment_method
|
22
39
|
rescue ::Lago::Api::HttpError => e
|
23
40
|
raise Pay::Lago::Error, e
|
@@ -27,10 +44,31 @@ module Pay
|
|
27
44
|
@pay_payment_method = pay_payment_method
|
28
45
|
end
|
29
46
|
|
47
|
+
def pull!
|
48
|
+
return false unless pay_payment_method.default?
|
49
|
+
customer.pull!
|
50
|
+
pay_payment_method.update!(data: customer.data["billing_configuration"])
|
51
|
+
end
|
52
|
+
|
53
|
+
def push!
|
54
|
+
return false unless pay_payment_method.default?
|
55
|
+
update_customer!
|
56
|
+
customer.push!
|
57
|
+
end
|
58
|
+
|
30
59
|
def make_default!
|
60
|
+
update_customer!
|
31
61
|
end
|
32
62
|
|
33
|
-
def detach
|
63
|
+
def detach!
|
64
|
+
customer.clear_payment_method!
|
65
|
+
end
|
66
|
+
|
67
|
+
private
|
68
|
+
|
69
|
+
def update_customer!
|
70
|
+
data = (customer.data || {}).merge("billing_configuration": pay_payment_method.data)
|
71
|
+
customer.update!(data: data)
|
34
72
|
end
|
35
73
|
end
|
36
74
|
end
|
@@ -23,7 +23,7 @@ module Pay
|
|
23
23
|
to: :pay_subscription
|
24
24
|
|
25
25
|
def self.sync(customer_id, subscription_id, object: nil, try: 0, retries: 1)
|
26
|
-
object ||=
|
26
|
+
object ||= Pay::Lago.client.subscriptions.get(subscription_id)
|
27
27
|
|
28
28
|
pay_customer = Pay::Customer.find_by(processor: :lago, processor_id: customer_id)
|
29
29
|
if pay_customer.blank?
|
@@ -60,25 +60,18 @@ module Pay
|
|
60
60
|
end
|
61
61
|
end
|
62
62
|
|
63
|
-
def self.get_subscription(customer_id, external_id)
|
64
|
-
result = Lago.client.subscriptions.get_all(external_customer_id: customer_id, per_page: 9223372036854775807)
|
65
|
-
result.subscriptions.each { |sub| return sub if sub.external_id == external_id }
|
66
|
-
raise Pay::Lago::Error.new("No subscription could be found.")
|
67
|
-
rescue ::Lago::Api::HttpError => e
|
68
|
-
raise Pay::Lago::Error, e
|
69
|
-
end
|
70
|
-
|
71
63
|
def initialize(pay_subscription)
|
72
64
|
@pay_subscription = pay_subscription
|
73
65
|
end
|
74
66
|
|
75
|
-
def subscription
|
76
|
-
@lago_subscription
|
67
|
+
def subscription(reload: false)
|
68
|
+
@lago_subscription = nil if reload
|
69
|
+
@lago_subscription ||= Pay::Lago.client.subscriptions.get(processor_id)
|
77
70
|
end
|
78
71
|
|
79
72
|
def cancel(**options)
|
80
73
|
customer_id = subscription.external_customer_id
|
81
|
-
response = Lago.client.subscriptions.destroy(
|
74
|
+
response = Lago.client.subscriptions.destroy(processor_id, options: options)
|
82
75
|
self.class.sync(customer_id, processor_id, object: response)
|
83
76
|
rescue ::Lago::Api::HttpError => e
|
84
77
|
raise Pay::Lago::Error, e
|
@@ -117,7 +110,7 @@ module Pay
|
|
117
110
|
customer_id = subscription.external_customer_id
|
118
111
|
attributes = options.merge(
|
119
112
|
external_customer_id: customer_id,
|
120
|
-
external_id: processor_id, plan_code: plan
|
113
|
+
external_id: processor_id, plan_code: plan.to_s
|
121
114
|
)
|
122
115
|
new_subscription = Lago.client.subscriptions.create(attributes)
|
123
116
|
self.class.sync(customer_id, processor_id, object: new_subscription)
|
data/lib/pay/lago/version.rb
CHANGED
@@ -4,13 +4,7 @@ module Pay
|
|
4
4
|
class CustomerPaymentProviderCreated
|
5
5
|
def call(event)
|
6
6
|
customer = event.customer
|
7
|
-
|
8
|
-
unless pay_customer.present?
|
9
|
-
Rails.logger.debug "Pay::Customer #{customer.external_id} is not in the database while syncing Payment Information"
|
10
|
-
return false
|
11
|
-
end
|
12
|
-
|
13
|
-
pay_customer.update!(data: Pay::Lago.openstruct_to_h(customer))
|
7
|
+
PaymentMethod.sync(customer)
|
14
8
|
end
|
15
9
|
end
|
16
10
|
end
|
data/pay-lago.gemspec
CHANGED
@@ -20,7 +20,7 @@ Gem::Specification.new do |spec|
|
|
20
20
|
|
21
21
|
# Uncomment to register a new dependency of your gem
|
22
22
|
spec.add_dependency "pay", "~> 6.8"
|
23
|
-
spec.add_dependency "lago-ruby-client", "0.
|
23
|
+
spec.add_dependency "lago-ruby-client", "0.53.0-beta"
|
24
24
|
|
25
25
|
# For more information and examples about making a new gem, check out our
|
26
26
|
# guide at: https://bundler.io/guides/creating_gem.html
|
@@ -0,0 +1,93 @@
|
|
1
|
+
class CreatePayTables < ActiveRecord::Migration[6.0]
|
2
|
+
def change
|
3
|
+
primary_key_type, foreign_key_type = primary_and_foreign_key_types
|
4
|
+
|
5
|
+
create_table :pay_customers, id: primary_key_type do |t|
|
6
|
+
t.belongs_to :owner, polymorphic: true, index: false, type: foreign_key_type
|
7
|
+
t.string :processor, null: false
|
8
|
+
t.string :processor_id
|
9
|
+
t.boolean :default
|
10
|
+
t.public_send Pay::Adapter.json_column_type, :data
|
11
|
+
t.datetime :deleted_at
|
12
|
+
t.string :stripe_account
|
13
|
+
t.timestamps
|
14
|
+
end
|
15
|
+
add_index :pay_customers, [:owner_type, :owner_id, :deleted_at], name: :pay_customer_owner_index, unique: true
|
16
|
+
add_index :pay_customers, [:processor, :processor_id], unique: true
|
17
|
+
|
18
|
+
create_table :pay_merchants, id: primary_key_type do |t|
|
19
|
+
t.belongs_to :owner, polymorphic: true, index: false, type: foreign_key_type
|
20
|
+
t.string :processor, null: false
|
21
|
+
t.string :processor_id
|
22
|
+
t.boolean :default
|
23
|
+
t.public_send Pay::Adapter.json_column_type, :data
|
24
|
+
t.timestamps
|
25
|
+
end
|
26
|
+
add_index :pay_merchants, [:owner_type, :owner_id, :processor]
|
27
|
+
|
28
|
+
create_table :pay_payment_methods, id: primary_key_type do |t|
|
29
|
+
t.belongs_to :customer, foreign_key: {to_table: :pay_customers}, null: false, index: false, type: foreign_key_type
|
30
|
+
t.string :processor_id, null: false
|
31
|
+
t.boolean :default
|
32
|
+
t.string :type
|
33
|
+
t.public_send Pay::Adapter.json_column_type, :data
|
34
|
+
t.timestamps
|
35
|
+
end
|
36
|
+
add_index :pay_payment_methods, [:customer_id, :processor_id], unique: true
|
37
|
+
|
38
|
+
create_table :pay_subscriptions, id: primary_key_type do |t|
|
39
|
+
t.belongs_to :customer, foreign_key: {to_table: :pay_customers}, null: false, index: false, type: foreign_key_type
|
40
|
+
t.string :name, null: false
|
41
|
+
t.string :processor_id, null: false
|
42
|
+
t.string :processor_plan, null: false
|
43
|
+
t.integer :quantity, default: 1, null: false
|
44
|
+
t.string :status, null: false
|
45
|
+
t.datetime :current_period_start
|
46
|
+
t.datetime :current_period_end
|
47
|
+
t.datetime :trial_ends_at
|
48
|
+
t.datetime :ends_at
|
49
|
+
t.boolean :metered
|
50
|
+
t.string :pause_behavior
|
51
|
+
t.datetime :pause_starts_at
|
52
|
+
t.datetime :pause_resumes_at
|
53
|
+
t.decimal :application_fee_percent, precision: 8, scale: 2
|
54
|
+
t.public_send Pay::Adapter.json_column_type, :metadata
|
55
|
+
t.public_send Pay::Adapter.json_column_type, :data
|
56
|
+
t.timestamps
|
57
|
+
end
|
58
|
+
add_index :pay_subscriptions, [:customer_id, :processor_id], unique: true
|
59
|
+
add_index :pay_subscriptions, [:metered]
|
60
|
+
add_index :pay_subscriptions, [:pause_starts_at]
|
61
|
+
|
62
|
+
create_table :pay_charges, id: primary_key_type do |t|
|
63
|
+
t.belongs_to :customer, foreign_key: {to_table: :pay_customers}, null: false, index: false, type: foreign_key_type
|
64
|
+
t.belongs_to :subscription, foreign_key: {to_table: :pay_subscriptions}, null: true, type: foreign_key_type
|
65
|
+
t.string :processor_id, null: false
|
66
|
+
t.integer :amount, null: false
|
67
|
+
t.string :currency
|
68
|
+
t.integer :application_fee_amount
|
69
|
+
t.integer :amount_refunded
|
70
|
+
t.public_send Pay::Adapter.json_column_type, :metadata
|
71
|
+
t.public_send Pay::Adapter.json_column_type, :data
|
72
|
+
t.timestamps
|
73
|
+
end
|
74
|
+
add_index :pay_charges, [:customer_id, :processor_id], unique: true
|
75
|
+
|
76
|
+
create_table :pay_webhooks, id: primary_key_type do |t|
|
77
|
+
t.string :processor
|
78
|
+
t.string :event_type
|
79
|
+
t.public_send Pay::Adapter.json_column_type, :event
|
80
|
+
t.timestamps
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
private
|
85
|
+
|
86
|
+
def primary_and_foreign_key_types
|
87
|
+
config = Rails.configuration.generators
|
88
|
+
setting = config.options[config.orm][:primary_key_type]
|
89
|
+
primary_key_type = setting || :primary_key
|
90
|
+
foreign_key_type = setting || :bigint
|
91
|
+
[primary_key_type, foreign_key_type]
|
92
|
+
end
|
93
|
+
end
|
data/test/dummy/db/schema.rb
CHANGED
@@ -10,7 +10,7 @@
|
|
10
10
|
#
|
11
11
|
# It's strongly recommended that you check this file into your version control system.
|
12
12
|
|
13
|
-
ActiveRecord::Schema[7.1].define(version:
|
13
|
+
ActiveRecord::Schema[7.1].define(version: 2017_02_05_000000) do
|
14
14
|
create_table "accounts", force: :cascade do |t|
|
15
15
|
t.string "email"
|
16
16
|
t.string "merchant_processor"
|
@@ -18,8 +18,8 @@ ActiveRecord::Schema[7.1].define(version: 2022_08_31_153001) do
|
|
18
18
|
end
|
19
19
|
|
20
20
|
create_table "pay_charges", force: :cascade do |t|
|
21
|
-
t.
|
22
|
-
t.
|
21
|
+
t.bigint "customer_id", null: false
|
22
|
+
t.bigint "subscription_id"
|
23
23
|
t.string "processor_id", null: false
|
24
24
|
t.integer "amount", null: false
|
25
25
|
t.string "currency"
|
@@ -40,10 +40,11 @@ ActiveRecord::Schema[7.1].define(version: 2022_08_31_153001) do
|
|
40
40
|
t.string "processor_id"
|
41
41
|
t.boolean "default"
|
42
42
|
t.json "data"
|
43
|
-
t.datetime "deleted_at"
|
43
|
+
t.datetime "deleted_at", precision: nil
|
44
|
+
t.string "stripe_account"
|
44
45
|
t.datetime "created_at", null: false
|
45
46
|
t.datetime "updated_at", null: false
|
46
|
-
t.index ["owner_type", "owner_id", "deleted_at"
|
47
|
+
t.index ["owner_type", "owner_id", "deleted_at"], name: "pay_customer_owner_index", unique: true
|
47
48
|
t.index ["processor", "processor_id"], name: "index_pay_customers_on_processor_and_processor_id", unique: true
|
48
49
|
end
|
49
50
|
|
@@ -60,7 +61,7 @@ ActiveRecord::Schema[7.1].define(version: 2022_08_31_153001) do
|
|
60
61
|
end
|
61
62
|
|
62
63
|
create_table "pay_payment_methods", force: :cascade do |t|
|
63
|
-
t.
|
64
|
+
t.bigint "customer_id", null: false
|
64
65
|
t.string "processor_id", null: false
|
65
66
|
t.boolean "default"
|
66
67
|
t.string "type"
|
@@ -71,25 +72,25 @@ ActiveRecord::Schema[7.1].define(version: 2022_08_31_153001) do
|
|
71
72
|
end
|
72
73
|
|
73
74
|
create_table "pay_subscriptions", force: :cascade do |t|
|
74
|
-
t.
|
75
|
+
t.bigint "customer_id", null: false
|
75
76
|
t.string "name", null: false
|
76
77
|
t.string "processor_id", null: false
|
77
78
|
t.string "processor_plan", null: false
|
78
79
|
t.integer "quantity", default: 1, null: false
|
79
80
|
t.string "status", null: false
|
80
|
-
t.datetime "current_period_start"
|
81
|
-
t.datetime "current_period_end"
|
82
|
-
t.datetime "trial_ends_at"
|
83
|
-
t.datetime "ends_at"
|
81
|
+
t.datetime "current_period_start", precision: nil
|
82
|
+
t.datetime "current_period_end", precision: nil
|
83
|
+
t.datetime "trial_ends_at", precision: nil
|
84
|
+
t.datetime "ends_at", precision: nil
|
85
|
+
t.boolean "metered"
|
86
|
+
t.string "pause_behavior"
|
87
|
+
t.datetime "pause_starts_at", precision: nil
|
88
|
+
t.datetime "pause_resumes_at", precision: nil
|
84
89
|
t.decimal "application_fee_percent", precision: 8, scale: 2
|
85
90
|
t.json "metadata"
|
86
91
|
t.json "data"
|
87
92
|
t.datetime "created_at", null: false
|
88
93
|
t.datetime "updated_at", null: false
|
89
|
-
t.boolean "metered"
|
90
|
-
t.string "pause_behavior"
|
91
|
-
t.datetime "pause_starts_at"
|
92
|
-
t.datetime "pause_resumes_at"
|
93
94
|
t.index ["customer_id", "processor_id"], name: "index_pay_subscriptions_on_customer_id_and_processor_id", unique: true
|
94
95
|
t.index ["metered"], name: "index_pay_subscriptions_on_metered"
|
95
96
|
t.index ["pause_starts_at"], name: "index_pay_subscriptions_on_pause_starts_at"
|
@@ -107,7 +108,7 @@ ActiveRecord::Schema[7.1].define(version: 2022_08_31_153001) do
|
|
107
108
|
t.string "email"
|
108
109
|
t.string "name"
|
109
110
|
t.string "owner_type"
|
110
|
-
t.
|
111
|
+
t.integer "owner_id"
|
111
112
|
t.index ["owner_type", "owner_id"], name: "index_teams_on_owner_type_and_owner_id"
|
112
113
|
end
|
113
114
|
|
@@ -33,7 +33,7 @@ class Pay::Lago::Billable::Test < ActiveSupport::TestCase
|
|
33
33
|
|
34
34
|
test "add payment method to lago" do
|
35
35
|
assert_difference "Pay::PaymentMethod.count" do
|
36
|
-
@pay_customer.add_payment_method("x", default: true)
|
36
|
+
@pay_customer.add_payment_method(:stripe, "x", default: true)
|
37
37
|
end
|
38
38
|
|
39
39
|
payment_method = @pay_customer.default_payment_method
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require "test_helper"
|
2
|
+
require "uri"
|
3
|
+
|
4
|
+
class Pay::Lago::PaymentMethodTest < ActiveSupport::TestCase
|
5
|
+
setup do
|
6
|
+
@pay_customer = pay_customers(:lago)
|
7
|
+
end
|
8
|
+
|
9
|
+
test "Lago sync returns Pay::PaymentMethod" do
|
10
|
+
lago_customer = OpenStruct.new(
|
11
|
+
external_id: @pay_customer.processor_id,
|
12
|
+
billing_configuration: OpenStruct.new(
|
13
|
+
payment_provider: "stripe",
|
14
|
+
provider_customer_id: "x"
|
15
|
+
)
|
16
|
+
)
|
17
|
+
pay_payment_method = Pay::Lago::PaymentMethod.sync(lago_customer)
|
18
|
+
assert pay_payment_method.is_a?(Pay::PaymentMethod)
|
19
|
+
assert pay_payment_method.processor_id == "x"
|
20
|
+
assert @pay_customer.default_payment_method == pay_payment_method
|
21
|
+
end
|
22
|
+
|
23
|
+
test "PaymentMethod does not push or pull if not default" do
|
24
|
+
pay_payment_method = @pay_customer.add_payment_method(:stripe, "test_1234", default: false, sync: false).payment_processor
|
25
|
+
assert pay_payment_method.push! == false
|
26
|
+
assert pay_payment_method.pull! == false
|
27
|
+
end
|
28
|
+
|
29
|
+
test "PaymentMethod can be made default, updating Lago" do
|
30
|
+
pay_payment_method = @pay_customer.add_payment_method(:stripe, "test_1234_a", sync: true)
|
31
|
+
lago_customer = Pay::Lago.client.customers.get(@pay_customer.pay_external_id)
|
32
|
+
assert lago_customer.billing_configuration.provider_customer_id == pay_payment_method.processor_id
|
33
|
+
end
|
34
|
+
end
|