pay-lago 0.1.0 → 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|