pay-lago 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.github/workflows/main.yml +27 -0
- data/.gitignore +28 -0
- data/.rspec +3 -0
- data/.standard.yml +3 -0
- data/CHANGELOG.md +2 -0
- data/CODE_OF_CONDUCT.md +84 -0
- data/Gemfile +25 -0
- data/Gemfile.lock +292 -0
- data/LICENSE.txt +21 -0
- data/README.md +85 -0
- data/Rakefile +32 -0
- data/app/controllers/pay/webhooks/lago_controller.rb +41 -0
- data/app/models/concerns/pay/lago/pay_customer_extensions.rb +15 -0
- data/app/models/concerns/pay/lago/pay_extensions.rb +15 -0
- data/bin/console +15 -0
- data/bin/rails +16 -0
- data/bin/setup +8 -0
- data/config/routes.rb +5 -0
- data/docs/1_customers.md +18 -0
- data/docs/2_charges.md +72 -0
- data/docs/3_subscriptions.md +67 -0
- data/docs/4_webhooks.md +66 -0
- data/lib/pay/lago/attributes.rb +24 -0
- data/lib/pay/lago/billable.rb +148 -0
- data/lib/pay/lago/charge.rb +82 -0
- data/lib/pay/lago/engine.rb +27 -0
- data/lib/pay/lago/error.rb +9 -0
- data/lib/pay/lago/payment_method.rb +37 -0
- data/lib/pay/lago/subscription.rb +134 -0
- data/lib/pay/lago/version.rb +7 -0
- data/lib/pay/lago/webhook_extensions.rb +10 -0
- data/lib/pay/lago/webhooks/customer_payment_provider_created.rb +18 -0
- data/lib/pay/lago/webhooks/invoice_created.rb +15 -0
- data/lib/pay/lago/webhooks/invoice_drafted.rb +11 -0
- data/lib/pay/lago/webhooks/invoice_one_off_created.rb +15 -0
- data/lib/pay/lago/webhooks/invoice_payment_status_updated.rb +14 -0
- data/lib/pay/lago/webhooks/subscription_started.rb +12 -0
- data/lib/pay/lago/webhooks/subscription_terminated.rb +12 -0
- data/lib/pay/lago.rb +91 -0
- data/pay-lago.gemspec +27 -0
- data/sig/pay/lago.rbs +6 -0
- data/test/controllers/pay/webhooks/lago_controller_test.rb +37 -0
- data/test/dummy/.browserslistrc +1 -0
- data/test/dummy/Rakefile +6 -0
- data/test/dummy/app/assets/config/manifest.js +4 -0
- data/test/dummy/app/assets/images/.keep +0 -0
- data/test/dummy/app/assets/stylesheets/application.css +15 -0
- data/test/dummy/app/channels/application_cable/channel.rb +4 -0
- data/test/dummy/app/channels/application_cable/connection.rb +4 -0
- data/test/dummy/app/controllers/application_controller.rb +4 -0
- data/test/dummy/app/controllers/concerns/.keep +0 -0
- data/test/dummy/app/controllers/main_controller.rb +4 -0
- data/test/dummy/app/controllers/payment_methods_controller.rb +5 -0
- data/test/dummy/app/helpers/application_helper.rb +2 -0
- data/test/dummy/app/helpers/current_helper.rb +9 -0
- data/test/dummy/app/javascript/application.js +9 -0
- data/test/dummy/app/javascript/controllers/application.js +10 -0
- data/test/dummy/app/javascript/controllers/index.js +11 -0
- data/test/dummy/app/jobs/application_job.rb +2 -0
- data/test/dummy/app/mailers/application_mailer.rb +4 -0
- data/test/dummy/app/models/account.rb +3 -0
- data/test/dummy/app/models/application_record.rb +3 -0
- data/test/dummy/app/models/concerns/.keep +0 -0
- data/test/dummy/app/models/team.rb +10 -0
- data/test/dummy/app/models/user.rb +3 -0
- data/test/dummy/app/views/layouts/application.html.erb +36 -0
- data/test/dummy/app/views/layouts/mailer.html.erb +13 -0
- data/test/dummy/app/views/layouts/mailer.text.erb +1 -0
- data/test/dummy/app/webhooks/charge_succeeded.rb +5 -0
- data/test/dummy/bin/importmap +4 -0
- data/test/dummy/bin/rails +4 -0
- data/test/dummy/bin/rake +4 -0
- data/test/dummy/bin/setup +33 -0
- data/test/dummy/bin/webpack +18 -0
- data/test/dummy/bin/webpack-dev-server +18 -0
- data/test/dummy/config/application.rb +25 -0
- data/test/dummy/config/boot.rb +6 -0
- data/test/dummy/config/cable.yml +9 -0
- data/test/dummy/config/database.yml +3 -0
- data/test/dummy/config/environment.rb +5 -0
- data/test/dummy/config/environments/development.rb +70 -0
- data/test/dummy/config/environments/production.rb +86 -0
- data/test/dummy/config/environments/test.rb +60 -0
- data/test/dummy/config/importmap.rb +8 -0
- data/test/dummy/config/initializers/application_controller_renderer.rb +6 -0
- data/test/dummy/config/initializers/assets.rb +11 -0
- data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/test/dummy/config/initializers/cookies_serializer.rb +5 -0
- data/test/dummy/config/initializers/filter_parameter_logging.rb +4 -0
- data/test/dummy/config/initializers/inflections.rb +16 -0
- data/test/dummy/config/initializers/mime_types.rb +4 -0
- data/test/dummy/config/initializers/pay.rb +11 -0
- data/test/dummy/config/initializers/session_store.rb +3 -0
- data/test/dummy/config/initializers/wrap_parameters.rb +14 -0
- data/test/dummy/config/locales/en.yml +23 -0
- data/test/dummy/config/puma.rb +47 -0
- data/test/dummy/config/routes.rb +4 -0
- data/test/dummy/config/secrets.yml +22 -0
- data/test/dummy/config/spring.rb +6 -0
- data/test/dummy/config/storage.yml +34 -0
- data/test/dummy/config.ru +6 -0
- data/test/dummy/db/migrate/20170205000000_create_users.rb +22 -0
- data/test/dummy/db/schema.rb +125 -0
- data/test/dummy/lib/assets/.keep +0 -0
- data/test/dummy/log/.keep +0 -0
- data/test/dummy/public/404.html +67 -0
- data/test/dummy/public/422.html +67 -0
- data/test/dummy/public/500.html +66 -0
- data/test/dummy/public/apple-touch-icon-precomposed.png +0 -0
- data/test/dummy/public/apple-touch-icon.png +0 -0
- data/test/dummy/public/favicon.ico +0 -0
- data/test/dummy/vendor/javascript/.keep +0 -0
- data/test/fixtures/accounts.yml +2 -0
- data/test/fixtures/pay/customers.yml +7 -0
- data/test/fixtures/teams.yml +4 -0
- data/test/fixtures/users.yml +11 -0
- data/test/pay/lago/billable_test.rb +42 -0
- data/test/pay/lago/charge_test.rb +23 -0
- data/test/pay/lago/subscription_test.rb +48 -0
- data/test/support/fixtures/lago/invoice.one_off_created.json +120 -0
- data/test/support/vcr.rb +28 -0
- data/test/test_helper.rb +66 -0
- data/test/vcr_cassettes/test_add_payment_method_to_lago.yml +56 -0
- data/test/vcr_cassettes/test_can_get_lago_processor_customer.yml +56 -0
- data/test/vcr_cassettes/test_can_make_a_lago_processor_charge.yml +163 -0
- data/test/vcr_cassettes/test_generates_lago_processor_id.yml +107 -0
- data/test/vcr_cassettes/test_lago_cannot_change_quantity.yml +108 -0
- data/test/vcr_cassettes/test_lago_processor_cancel.yml +212 -0
- data/test/vcr_cassettes/test_lago_processor_charge.yml +325 -0
- data/test/vcr_cassettes/test_lago_processor_on_grace_period__is_always_false.yml +108 -0
- data/test/vcr_cassettes/test_lago_processor_pause_raises_an_error.yml +108 -0
- data/test/vcr_cassettes/test_lago_processor_paused__is_always_false.yml +108 -0
- data/test/vcr_cassettes/test_lago_processor_refund_with_premium.yml +378 -0
- data/test/vcr_cassettes/test_lago_processor_refund_without_premium.yml +375 -0
- data/test/vcr_cassettes/test_lago_processor_resume_raises_an_error.yml +108 -0
- data/test/vcr_cassettes/test_lago_processor_subscribe.yml +108 -0
- data/test/vcr_cassettes/test_lago_processor_subscription.yml +160 -0
- data/test/vcr_cassettes/test_lago_processor_swap.yml +212 -0
- metadata +212 -0
@@ -0,0 +1,134 @@
|
|
1
|
+
module Pay
|
2
|
+
module Lago
|
3
|
+
class Subscription
|
4
|
+
STATUS_MAP = {
|
5
|
+
"pending" => "active",
|
6
|
+
"terminated" => "canceled"
|
7
|
+
}
|
8
|
+
attr_reader :pay_subscription
|
9
|
+
|
10
|
+
delegate :active?,
|
11
|
+
:canceled?,
|
12
|
+
:on_grace_period?,
|
13
|
+
:on_trial?,
|
14
|
+
:ends_at,
|
15
|
+
:ends_at?,
|
16
|
+
:owner,
|
17
|
+
:processor_subscription,
|
18
|
+
:processor_id,
|
19
|
+
:prorate,
|
20
|
+
:processor_plan,
|
21
|
+
:quantity?,
|
22
|
+
:quantity,
|
23
|
+
to: :pay_subscription
|
24
|
+
|
25
|
+
def self.sync(customer_id, subscription_id, object: nil, try: 0, retries: 1)
|
26
|
+
object ||= get_subscription(customer_id, subscription_id)
|
27
|
+
|
28
|
+
pay_customer = Pay::Customer.find_by(processor: :lago, processor_id: customer_id)
|
29
|
+
if pay_customer.blank?
|
30
|
+
Rails.logger.debug "Pay::Customer #{object.customer} is not in the database while syncing Lago Subscription #{object.lago_id}"
|
31
|
+
return
|
32
|
+
end
|
33
|
+
|
34
|
+
attrs = {
|
35
|
+
name: object.name.present? ? object.name : Pay.default_plan_name,
|
36
|
+
processor_id: object.external_id,
|
37
|
+
processor_plan: object.plan_code,
|
38
|
+
ends_at: object.cancelled_at || object.terminated_at,
|
39
|
+
quantity: 1,
|
40
|
+
status: STATUS_MAP.fetch(object.status, object.status),
|
41
|
+
data: Lago.openstruct_to_h(object)
|
42
|
+
}
|
43
|
+
|
44
|
+
# Update or create the charge
|
45
|
+
if (pay_subscription = pay_customer.subscriptions.find_by(processor_id: subscription_id))
|
46
|
+
pay_subscription.with_lock do
|
47
|
+
pay_subscription.update!(attrs)
|
48
|
+
end
|
49
|
+
pay_subscription
|
50
|
+
else
|
51
|
+
pay_customer.subscriptions.create!(attrs)
|
52
|
+
end
|
53
|
+
rescue ActiveRecord::RecordInvalid, ActiveRecord::RecordNotUnique
|
54
|
+
try += 1
|
55
|
+
if try <= retries
|
56
|
+
sleep 0.1
|
57
|
+
retry
|
58
|
+
else
|
59
|
+
raise
|
60
|
+
end
|
61
|
+
end
|
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
|
+
def initialize(pay_subscription)
|
72
|
+
@pay_subscription = pay_subscription
|
73
|
+
end
|
74
|
+
|
75
|
+
def subscription
|
76
|
+
@lago_subscription ||= self.class.get_subscription(pay_subscription.customer.processor_id, processor_id)
|
77
|
+
end
|
78
|
+
|
79
|
+
def cancel(**options)
|
80
|
+
customer_id = subscription.external_customer_id
|
81
|
+
response = Lago.client.subscriptions.destroy(URI.encode_www_form_component(processor_id), options: options)
|
82
|
+
self.class.sync(customer_id, processor_id, object: response)
|
83
|
+
rescue ::Lago::Api::HttpError => e
|
84
|
+
raise Pay::Lago::Error, e
|
85
|
+
end
|
86
|
+
|
87
|
+
def cancel_now!(**options)
|
88
|
+
cancel(options)
|
89
|
+
end
|
90
|
+
|
91
|
+
def change_quantity(_quantity, **_options)
|
92
|
+
raise Pay::Lago::Error.new("Lago subscriptions do not implement quantity.")
|
93
|
+
end
|
94
|
+
|
95
|
+
def on_grace_period?
|
96
|
+
false
|
97
|
+
end
|
98
|
+
|
99
|
+
def paused?
|
100
|
+
false
|
101
|
+
end
|
102
|
+
|
103
|
+
def changing_plan?
|
104
|
+
return false unless subscription.downgrade_plan_date
|
105
|
+
subscription.downgrade_plan_date > Time.now
|
106
|
+
end
|
107
|
+
|
108
|
+
def pause
|
109
|
+
raise Pay::Lago::Error.new("Lago subscriptions cannot be paused.")
|
110
|
+
end
|
111
|
+
|
112
|
+
def resume
|
113
|
+
raise Pay::Lago::Error.new("Lago subscriptions cannot be paused.")
|
114
|
+
end
|
115
|
+
|
116
|
+
def swap(plan, **options)
|
117
|
+
customer_id = subscription.external_customer_id
|
118
|
+
attributes = options.merge(
|
119
|
+
external_customer_id: customer_id,
|
120
|
+
external_id: processor_id, plan_code: plan
|
121
|
+
)
|
122
|
+
new_subscription = Lago.client.subscriptions.create(attributes)
|
123
|
+
self.class.sync(customer_id, processor_id, object: new_subscription)
|
124
|
+
rescue ::Lago::Api::HttpError => e
|
125
|
+
raise Pay::Lago::Error, e
|
126
|
+
end
|
127
|
+
|
128
|
+
# Retries the latest invoice for a Past Due subscription
|
129
|
+
def retry_failed_payment
|
130
|
+
raise Pay::Lago::Error.new("Lago subscriptions cannot be retried.")
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Pay
|
2
|
+
module Lago
|
3
|
+
module Webhooks
|
4
|
+
class CustomerPaymentProviderCreated
|
5
|
+
def call(event)
|
6
|
+
customer = event.customer
|
7
|
+
pay_customer = Pay::Customer.find_by(processor_id: customer.external_id)
|
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))
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module Pay
|
2
|
+
module Lago
|
3
|
+
module Webhooks
|
4
|
+
class InvoiceCreated
|
5
|
+
def call(event)
|
6
|
+
pay_charge = Pay::Lago::Charge.sync(event.invoice.lago_id, object: event.invoice)
|
7
|
+
|
8
|
+
if pay_charge && Pay.send_email?(:receipt, pay_charge)
|
9
|
+
Pay.mailer.with(pay_customer: pay_charge.customer, pay_charge: pay_charge).receipt.deliver_later
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module Pay
|
2
|
+
module Lago
|
3
|
+
module Webhooks
|
4
|
+
class InvoiceOneOffCreated
|
5
|
+
def call(event)
|
6
|
+
pay_charge = Pay::Lago::Charge.sync(event.invoice.lago_id, object: event.invoice)
|
7
|
+
|
8
|
+
if pay_charge && Pay.send_email?(:receipt, pay_charge)
|
9
|
+
Pay.mailer.with(pay_customer: pay_charge.customer, pay_charge: pay_charge).receipt.deliver_later
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module Pay
|
2
|
+
module Lago
|
3
|
+
module Webhooks
|
4
|
+
class InvoicePaymentStatusUpdated
|
5
|
+
def call(event)
|
6
|
+
charge = Pay::Charge.find_by_processor_and_id(:lago, event.invoice.lago_id)
|
7
|
+
return unless charge.present?
|
8
|
+
charge.data.merge!(payment_status: event.invoice.payment_status)
|
9
|
+
charge.save!
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
module Pay
|
2
|
+
module Lago
|
3
|
+
module Webhooks
|
4
|
+
class SubscriptionStarted
|
5
|
+
def call(event)
|
6
|
+
subscription = event.subscription
|
7
|
+
Pay::Lago::Subscription.sync(subscription.external_customer_id, subscription.external_id, object: subscription)
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
module Pay
|
2
|
+
module Lago
|
3
|
+
module Webhooks
|
4
|
+
class SubscriptionTerminated
|
5
|
+
def call(event)
|
6
|
+
subscription = event.subscription
|
7
|
+
Pay::Lago::Subscription.sync(subscription.external_customer_id, subscription.external_id, object: subscription)
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
data/lib/pay/lago.rb
ADDED
@@ -0,0 +1,91 @@
|
|
1
|
+
require "pay/lago/version"
|
2
|
+
require "pay/lago/engine"
|
3
|
+
|
4
|
+
require "lago-ruby-client"
|
5
|
+
|
6
|
+
require "action_mailer"
|
7
|
+
require "active_support"
|
8
|
+
|
9
|
+
module Pay
|
10
|
+
module Lago
|
11
|
+
autoload :Attributes, "pay/lago/attributes"
|
12
|
+
autoload :Billable, "pay/lago/billable"
|
13
|
+
autoload :Charge, "pay/lago/charge"
|
14
|
+
autoload :Error, "pay/lago/error"
|
15
|
+
autoload :PaymentMethod, "pay/lago/payment_method"
|
16
|
+
autoload :Subscription, "pay/lago/subscription"
|
17
|
+
autoload :WebhookExtensions, "pay/lago/webhook_extensions"
|
18
|
+
|
19
|
+
module Webhooks
|
20
|
+
autoload :CustomerPaymentProviderCreated, "pay/lago/webhooks/customer_payment_provider_created"
|
21
|
+
autoload :InvoiceCreated, "pay/lago/webhooks/invoice_created"
|
22
|
+
autoload :InvoiceDrafted, "pay/lago/webhooks/invoice_drafted"
|
23
|
+
autoload :InvoiceOneOffCreated, "pay/lago/webhooks/invoice_one_off_created"
|
24
|
+
autoload :InvoicePaymentStatusUpdated, "pay/lago/webhooks/invoice_payment_status_updated"
|
25
|
+
autoload :SubscriptionStarted, "pay/lago/webhooks/subscription_started"
|
26
|
+
autoload :SubscriptionTerminated, "pay/lago/webhooks/subscription_terminated"
|
27
|
+
end
|
28
|
+
|
29
|
+
extend Pay::Env
|
30
|
+
|
31
|
+
class << self
|
32
|
+
def enabled?
|
33
|
+
defined?(::Lago)
|
34
|
+
end
|
35
|
+
|
36
|
+
def client
|
37
|
+
@client ||= ::Lago::Api::Client.new(api_key: api_key, api_url: api_url)
|
38
|
+
end
|
39
|
+
|
40
|
+
def valid_auth?
|
41
|
+
webhook_public_key
|
42
|
+
true
|
43
|
+
rescue
|
44
|
+
false
|
45
|
+
end
|
46
|
+
|
47
|
+
def create_webhook!(url, mount = Pay.routes_path)
|
48
|
+
uri = URI(url)
|
49
|
+
raise Pay::Lago::Error.new("Invalid URI: #{uri}") unless uri.host.present?
|
50
|
+
uri.scheme = "https" unless %w[http https].include?(uri.scheme)
|
51
|
+
uri.path = "/#{mount}/webhooks/lago".squeeze("/")
|
52
|
+
client.webhook_endpoints.create(signature_algo: "jwt", webhook_url: uri.to_s)
|
53
|
+
true
|
54
|
+
rescue ::Lago::Api::HttpError => e
|
55
|
+
return true if e.error_code == 422
|
56
|
+
raise Pay::Lago::Error, e
|
57
|
+
end
|
58
|
+
|
59
|
+
def webhook_public_key
|
60
|
+
@webhook_public_key ||= client.webhooks.public_key
|
61
|
+
end
|
62
|
+
|
63
|
+
def api_key
|
64
|
+
find_value_by_name(:lago, :api_key)
|
65
|
+
end
|
66
|
+
|
67
|
+
def api_url
|
68
|
+
find_value_by_name(:lago, :api_url)
|
69
|
+
end
|
70
|
+
|
71
|
+
def configure_webhooks
|
72
|
+
Pay::Webhooks.configure do |events|
|
73
|
+
events.subscribe "lago.customer.payment_provider_created", Pay::Lago::Webhooks::CustomerPaymentProviderCreated.new
|
74
|
+
events.subscribe "lago.invoice.created", Pay::Lago::Webhooks::InvoiceCreated.new
|
75
|
+
events.subscribe "lago.invoice.drafted", Pay::Lago::Webhooks::InvoiceDrafted.new
|
76
|
+
events.subscribe "lago.invoice.one_off_created", Pay::Lago::Webhooks::InvoiceOneOffCreated.new
|
77
|
+
events.subscribe "lago.invoice.payment_status_updated", Pay::Lago::Webhooks::InvoicePaymentStatusUpdated.new
|
78
|
+
events.subscribe "lago.subscription.started", Pay::Lago::Webhooks::SubscriptionStarted.new
|
79
|
+
events.subscribe "lago.subscription.terminated", Pay::Lago::Webhooks::SubscriptionTerminated.new
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
# Helpers for working with Lago client
|
84
|
+
def openstruct_to_h(ostruct)
|
85
|
+
return ostruct.to_h.transform_values { |value| openstruct_to_h(value) } if ostruct.is_a?(OpenStruct) || ostruct.is_a?(Hash)
|
86
|
+
return ostruct.map { |value| openstruct_to_h(value) } if ostruct.is_a?(Array)
|
87
|
+
ostruct
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
data/pay-lago.gemspec
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
require_relative "lib/pay/lago/version"
|
2
|
+
|
3
|
+
Gem::Specification.new do |spec|
|
4
|
+
spec.name = "pay-lago"
|
5
|
+
spec.version = Pay::Lago::VERSION
|
6
|
+
spec.authors = ["Moxvallix"]
|
7
|
+
spec.email = ["dev@moxvallix.com"]
|
8
|
+
|
9
|
+
spec.summary = "Lago processor support for Pay gem."
|
10
|
+
spec.homepage = "https://github.com/demingfactor/pay-lago"
|
11
|
+
spec.license = "MIT"
|
12
|
+
|
13
|
+
spec.metadata["homepage_uri"] = spec.homepage
|
14
|
+
spec.metadata["source_code_uri"] = "https://github.com/demingfactor/pay-lago"
|
15
|
+
spec.metadata["changelog_uri"] = "https://github.com/demingfactor/pay-lago/blob/main/CHANGELOG.md"
|
16
|
+
|
17
|
+
# Specify which files should be added to the gem when it is released.
|
18
|
+
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
19
|
+
spec.files = `git ls-files -z`.split("\u0000")
|
20
|
+
|
21
|
+
# Uncomment to register a new dependency of your gem
|
22
|
+
spec.add_dependency "pay", "~> 6.8"
|
23
|
+
spec.add_dependency "lago-ruby-client", "0.50.0-beta"
|
24
|
+
|
25
|
+
# For more information and examples about making a new gem, check out our
|
26
|
+
# guide at: https://bundler.io/guides/creating_gem.html
|
27
|
+
end
|
data/sig/pay/lago.rbs
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
# require "test_helper"
|
2
|
+
|
3
|
+
module Pay
|
4
|
+
class LagoWebhooksControllerTest < ActionDispatch::IntegrationTest
|
5
|
+
include Pay::Engine.routes.url_helpers
|
6
|
+
|
7
|
+
setup do
|
8
|
+
@routes = Lago::Engine.routes
|
9
|
+
end
|
10
|
+
|
11
|
+
test "should handle lago post requests" do
|
12
|
+
post webhooks_lago_path
|
13
|
+
assert_response :bad_request
|
14
|
+
end
|
15
|
+
|
16
|
+
test "should parse a lago webhook" do
|
17
|
+
lago_event = fake_event("lago/invoice.one_off_created")
|
18
|
+
Pay::Webhooks::LagoController.any_instance.expects(:verified_event).returns(lago_event)
|
19
|
+
|
20
|
+
pay_customer = pay_customers(:lago)
|
21
|
+
pay_customer.update(processor_id: lago_event.dig("invoice", "customer", "external_id"))
|
22
|
+
|
23
|
+
assert_difference "Pay::Webhook.count" do
|
24
|
+
assert_enqueued_with(job: Pay::Webhooks::ProcessJob) do
|
25
|
+
post webhooks_lago_path, params: lago_event
|
26
|
+
assert_response :success
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
assert_difference "Pay::Charge.count" do
|
31
|
+
perform_enqueued_jobs
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
module Lago
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
defaults
|
data/test/dummy/Rakefile
ADDED
File without changes
|
@@ -0,0 +1,15 @@
|
|
1
|
+
/*
|
2
|
+
* This is a manifest file that'll be compiled into application.css, which will include all the files
|
3
|
+
* listed below.
|
4
|
+
*
|
5
|
+
* Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets,
|
6
|
+
* or any plugin's vendor/assets/stylesheets directory can be referenced here using a relative path.
|
7
|
+
*
|
8
|
+
* You're free to add application-wide styles to this file and they'll appear at the bottom of the
|
9
|
+
* compiled file so the styles you add here take precedence over styles defined in any other CSS/SCSS
|
10
|
+
* files in this directory. Styles in this file should be added after the last require_* statement.
|
11
|
+
* It is generally better to create a new file per style scope.
|
12
|
+
*
|
13
|
+
*= require_tree .
|
14
|
+
*= require_self
|
15
|
+
*/
|
File without changes
|
@@ -0,0 +1,9 @@
|
|
1
|
+
module CurrentHelper
|
2
|
+
def current_user
|
3
|
+
@current_user ||= User.first || User.create!(email: "test@user.com", first_name: "Test", last_name: "User")
|
4
|
+
end
|
5
|
+
|
6
|
+
def current_team
|
7
|
+
@current_user ||= Team.first || Team.create!(name: "Test Team", email: "test@team.com", owner: current_user)
|
8
|
+
end
|
9
|
+
end
|
@@ -0,0 +1,9 @@
|
|
1
|
+
// Configure your import map in config/importmap.rb. Read more: https://github.com/rails/importmap-rails
|
2
|
+
import "@hotwired/turbo-rails"
|
3
|
+
import "controllers"
|
4
|
+
|
5
|
+
// Bootstrap
|
6
|
+
document.addEventListener("turbo:load", function() {
|
7
|
+
$('[data-toggle="tooltip"]').tooltip()
|
8
|
+
$('[data-toggle="popover"]').popover()
|
9
|
+
})
|
@@ -0,0 +1,11 @@
|
|
1
|
+
// Import and register all your controllers from the importmap under controllers/*
|
2
|
+
|
3
|
+
import { application } from "controllers/application"
|
4
|
+
|
5
|
+
// Eager load all controllers defined in the import map under controllers/**/*_controller
|
6
|
+
import { eagerLoadControllersFrom } from "@hotwired/stimulus-loading"
|
7
|
+
eagerLoadControllersFrom("controllers", application)
|
8
|
+
|
9
|
+
// Lazy load controllers as they appear in the DOM (remember not to preload controllers in import map!)
|
10
|
+
// import { lazyLoadControllersFrom } from "@hotwired/stimulus-loading"
|
11
|
+
// lazyLoadControllersFrom("controllers", application)
|
File without changes
|
@@ -0,0 +1,36 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html>
|
3
|
+
<head>
|
4
|
+
<title>Dummy</title>
|
5
|
+
<%= csrf_meta_tags %>
|
6
|
+
|
7
|
+
<%# Bootstrap %>
|
8
|
+
<link rel="stylesheet" href="https://unpkg.com/bootstrap@4.5.3/dist/css/bootstrap.min.css" integrity="sha384-TX8t27EcRE3e/ihU7zmQxVncDAy5uIKz4rEkgIXeMed4M0jlfIDPvg6uqKI2xXr2" crossorigin="anonymous">
|
9
|
+
<script src="https://code.jquery.com/jquery-3.5.1.slim.min.js" integrity="sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj" crossorigin="anonymous"></script>
|
10
|
+
<script src="https://unpkg.com/bootstrap@4.5.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-ho+j7jyWK8fNQe+A12Hb8AhRq26LrZ/JpcUGGOn+Y7RsweNrtN/tE3MoK7ZeZDyx" crossorigin="anonymous"></script>
|
11
|
+
|
12
|
+
<%= stylesheet_link_tag "application", "data-turbo-track": "reload" %>
|
13
|
+
<%= javascript_importmap_tags %>
|
14
|
+
</head>
|
15
|
+
|
16
|
+
<body>
|
17
|
+
<nav class="navbar navbar-expand-lg navbar-light bg-light">
|
18
|
+
<%= link_to "Pay Examples", root_path, class: "navbar-brand" %>
|
19
|
+
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
|
20
|
+
<span class="navbar-toggler-icon"></span>
|
21
|
+
</button>
|
22
|
+
</nav>
|
23
|
+
|
24
|
+
<div class="container mx-auto">
|
25
|
+
<% if notice %>
|
26
|
+
<div class="alert alert-notice"><%= notice %></div>
|
27
|
+
<% end %>
|
28
|
+
|
29
|
+
<% if alert %>
|
30
|
+
<div class="alert alert-warning"><%= alert %></div>
|
31
|
+
<% end %>
|
32
|
+
|
33
|
+
<%= yield %>
|
34
|
+
</div>
|
35
|
+
</body>
|
36
|
+
</html>
|
@@ -0,0 +1 @@
|
|
1
|
+
<%= yield %>
|