pay-abacatepay 0.1.0.pre.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +10 -0
  3. data/MIT-LICENSE +21 -0
  4. data/README.md +248 -0
  5. data/app/controllers/pay/webhooks/abacatepay_controller.rb +104 -0
  6. data/lib/generators/pay_abacatepay/install/install_generator.rb +21 -0
  7. data/lib/generators/pay_abacatepay/install/templates/create_pay_abacatepay_processed_webhooks.rb.tt +15 -0
  8. data/lib/pay/abacatepay/charge.rb +77 -0
  9. data/lib/pay/abacatepay/customer.rb +136 -0
  10. data/lib/pay/abacatepay/engine.rb +33 -0
  11. data/lib/pay/abacatepay/payment_method.rb +21 -0
  12. data/lib/pay/abacatepay/processed_webhook.rb +19 -0
  13. data/lib/pay/abacatepay/subscription.rb +88 -0
  14. data/lib/pay/abacatepay/version.rb +5 -0
  15. data/lib/pay/abacatepay/webhooks/checkout_completed.rb +52 -0
  16. data/lib/pay/abacatepay/webhooks/checkout_disputed.rb +11 -0
  17. data/lib/pay/abacatepay/webhooks/checkout_lost.rb +11 -0
  18. data/lib/pay/abacatepay/webhooks/checkout_refunded.rb +38 -0
  19. data/lib/pay/abacatepay/webhooks/event.rb +95 -0
  20. data/lib/pay/abacatepay/webhooks/payout_completed.rb +11 -0
  21. data/lib/pay/abacatepay/webhooks/payout_failed.rb +11 -0
  22. data/lib/pay/abacatepay/webhooks/subscription_cancelled.rb +34 -0
  23. data/lib/pay/abacatepay/webhooks/subscription_completed.rb +53 -0
  24. data/lib/pay/abacatepay/webhooks/subscription_renewed.rb +45 -0
  25. data/lib/pay/abacatepay/webhooks/subscription_trial_started.rb +13 -0
  26. data/lib/pay/abacatepay/webhooks/transfer_completed.rb +11 -0
  27. data/lib/pay/abacatepay/webhooks/transfer_failed.rb +11 -0
  28. data/lib/pay/abacatepay/webhooks/transparent_completed.rb +11 -0
  29. data/lib/pay/abacatepay/webhooks/transparent_disputed.rb +11 -0
  30. data/lib/pay/abacatepay/webhooks/transparent_lost.rb +11 -0
  31. data/lib/pay/abacatepay/webhooks/transparent_refunded.rb +11 -0
  32. data/lib/pay/abacatepay/webhooks.rb +23 -0
  33. data/lib/pay/abacatepay.rb +75 -0
  34. data/lib/pay-abacatepay.rb +1 -0
  35. metadata +105 -0
@@ -0,0 +1,21 @@
1
+ module Pay
2
+ module Abacatepay
3
+ # Stub STI class for Pay::PaymentMethod scoped to AbacatePay.
4
+ #
5
+ # AbacatePay does not (yet) expose tokenized payment methods that we can
6
+ # store and reuse — every transparent transaction needs full card data.
7
+ # This class exists so that:
8
+ #
9
+ # 1. `Pay::Abacatepay::Customer has_many :payment_methods` resolves
10
+ # correctly (avoids `Missing model class` error on customer destroy).
11
+ # 2. We can persist tokenized payment methods later without breaking
12
+ # existing data when transparent checkout lands (Fase 5).
13
+ #
14
+ # Until transparent checkout is implemented, instances of this class
15
+ # are not created — the relation is empty for every customer.
16
+ class PaymentMethod < Pay::PaymentMethod
17
+ end
18
+ end
19
+ end
20
+
21
+ ActiveSupport.run_load_hooks :pay_abacatepay_payment_method, Pay::Abacatepay::PaymentMethod
@@ -0,0 +1,19 @@
1
+ module Pay
2
+ module Abacatepay
3
+ class ProcessedWebhook < ActiveRecord::Base
4
+ self.table_name = "pay_abacatepay_processed_webhooks"
5
+
6
+ validates :event_type, :event_id, presence: true
7
+
8
+ def self.process!(event_type:, event_id:)
9
+ transaction(requires_new: true) do
10
+ create!(event_type: event_type, event_id: event_id, processed_at: Time.current)
11
+ yield if block_given?
12
+ end
13
+ nil
14
+ rescue ActiveRecord::RecordNotUnique
15
+ :already_processed
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,88 @@
1
+ module Pay
2
+ module Abacatepay
3
+ class Subscription < Pay::Subscription
4
+ STATUS_FROM_EVENT = {
5
+ "subscription.completed" => "active",
6
+ "subscription.renewed" => "active",
7
+ "subscription.cancelled" => "canceled"
8
+ }.freeze
9
+
10
+ def self.sync(processor_id, event: nil)
11
+ return if processor_id.blank?
12
+
13
+ subscription = Pay::Abacatepay::Subscription.find_by(processor_id: processor_id)
14
+ customer = subscription&.customer
15
+ customer ||= Pay::Customer.find_by(processor: "abacatepay", processor_id: event&.customer_id) if event
16
+
17
+ if customer.nil?
18
+ Rails.logger.warn("[pay-abacatepay] cannot sync subscription #{processor_id}: Pay::Customer not found")
19
+ return
20
+ end
21
+
22
+ subscription ||= Pay::Abacatepay::Subscription.new(customer: customer, processor_id: processor_id)
23
+ assign_attributes_from(subscription, event) if event
24
+ subscription.save!
25
+ subscription
26
+ end
27
+
28
+ def self.assign_attributes_from(subscription, event)
29
+ status = STATUS_FROM_EVENT[event.type] || subscription.status || "active"
30
+ period_start = event.paid_at || event.subscription_created_at || Time.current
31
+ interval = event.interval
32
+
33
+ subscription.assign_attributes(
34
+ name: event.product_id || subscription.name || "default",
35
+ processor_plan: event.product_id || subscription.processor_plan || "default",
36
+ status: status,
37
+ current_period_start: period_start,
38
+ current_period_end: interval ? period_start + interval : subscription.current_period_end,
39
+ ends_at: (status == "canceled") ? (event.canceled_at || Time.current) : subscription.ends_at
40
+ )
41
+ end
42
+ private_class_method :assign_attributes_from
43
+
44
+ def cancel(**options)
45
+ Rails.logger.warn(
46
+ "[pay-abacatepay] AbacatePay does not support cancel-at-period-end; cancelling immediately"
47
+ )
48
+ cancel_now!(**options)
49
+ end
50
+
51
+ def cancel_now!(**_options)
52
+ ::AbacatePay.subscriptions.send(:request, "POST", "cancel", params: {id: processor_id})
53
+ update!(status: "canceled", ends_at: Time.current)
54
+ rescue ::AbacatePay::Error => e
55
+ raise Pay::Abacatepay::Error, e.message
56
+ end
57
+
58
+ def resume
59
+ raise NotImplementedError,
60
+ "AbacatePay does not support resuming cancelled subscriptions; create a new subscription"
61
+ end
62
+
63
+ def swap(_plan, **_options)
64
+ raise NotImplementedError,
65
+ "AbacatePay does not support plan swap; cancel the subscription and create a new one"
66
+ end
67
+
68
+ def change_quantity(_quantity, **_options)
69
+ raise NotImplementedError,
70
+ "AbacatePay does not support quantity changes"
71
+ end
72
+
73
+ # AbacatePay does not emit payment-failure events, so we cannot observe
74
+ # a past_due state. Always false.
75
+ def past_due?
76
+ false
77
+ end
78
+
79
+ def api_record
80
+ ::AbacatePay.subscriptions.send(:request, "GET", "get", params: {id: processor_id})
81
+ rescue ::AbacatePay::Error => e
82
+ raise Pay::Abacatepay::Error, e.message
83
+ end
84
+ end
85
+ end
86
+ end
87
+
88
+ ActiveSupport.run_load_hooks :pay_abacatepay_subscription, Pay::Abacatepay::Subscription
@@ -0,0 +1,5 @@
1
+ module Pay
2
+ module Abacatepay
3
+ VERSION = "0.1.0.pre.1"
4
+ end
5
+ end
@@ -0,0 +1,52 @@
1
+ module Pay
2
+ module Abacatepay
3
+ module Webhooks
4
+ class CheckoutCompleted
5
+ def call(event_hash)
6
+ event = Pay::Abacatepay::Webhooks::Event.new(event_hash)
7
+ result = Pay::Abacatepay::ProcessedWebhook.process!(event_type: event.type, event_id: event.id) do
8
+ handle(event)
9
+ end
10
+ log_already_processed(event) if result == :already_processed
11
+ end
12
+
13
+ private
14
+
15
+ def handle(event)
16
+ if event.checkout_frequency && event.checkout_frequency != "ONE_TIME"
17
+ Rails.logger.debug(
18
+ "[pay-abacatepay] checkout.completed for #{event.checkout_id} is a subscription payment " \
19
+ "(frequency=#{event.checkout_frequency}); skipping — subscription.renewed handles it"
20
+ )
21
+ return
22
+ end
23
+
24
+ customer = Pay::Customer.find_by(processor: "abacatepay", processor_id: event.customer_id)
25
+ if customer.nil?
26
+ Rails.logger.warn(
27
+ "[pay-abacatepay] checkout.completed for unknown customer #{event.customer_id}; " \
28
+ "Pay::Customer must be created via the app signup flow before the webhook arrives"
29
+ )
30
+ return
31
+ end
32
+
33
+ charge = Pay::Abacatepay::Charge.find_or_initialize_by(
34
+ customer: customer,
35
+ processor_id: event.checkout_id
36
+ )
37
+ charge.amount = event.checkout_paid_amount_cents || event.checkout_amount_cents
38
+ charge.currency ||= "BRL"
39
+ charge.application_fee_amount = event.checkout_platform_fee_cents
40
+ charge.status = "paid"
41
+ charge.checkout_url = event.checkout_url if event.checkout_url
42
+ charge.created_at = event.paid_at if charge.new_record? && event.paid_at
43
+ charge.save!
44
+ end
45
+
46
+ def log_already_processed(event)
47
+ Rails.logger.info("[pay-abacatepay] #{event.type} #{event.id} already processed")
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,11 @@
1
+ module Pay
2
+ module Abacatepay
3
+ module Webhooks
4
+ class CheckoutDisputed
5
+ # TODO: Fase 5 — dispute handling
6
+ def call(event)
7
+ end
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ module Pay
2
+ module Abacatepay
3
+ module Webhooks
4
+ class CheckoutLost
5
+ # TODO: Fase 5 — lost dispute handling
6
+ def call(event)
7
+ end
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,38 @@
1
+ module Pay
2
+ module Abacatepay
3
+ module Webhooks
4
+ class CheckoutRefunded
5
+ def call(event_hash)
6
+ event = Pay::Abacatepay::Webhooks::Event.new(event_hash)
7
+ result = Pay::Abacatepay::ProcessedWebhook.process!(event_type: event.type, event_id: event.id) do
8
+ handle(event)
9
+ end
10
+ log_already_processed(event) if result == :already_processed
11
+ end
12
+
13
+ private
14
+
15
+ def handle(event)
16
+ charge = Pay::Abacatepay::Charge.find_by(processor_id: event.checkout_id)
17
+ if charge.nil?
18
+ Rails.logger.warn(
19
+ "[pay-abacatepay] checkout.refunded for unknown checkout #{event.checkout_id}; " \
20
+ "no Pay::Abacatepay::Charge to update"
21
+ )
22
+ return
23
+ end
24
+
25
+ refund_amount = event.checkout_paid_amount_cents || charge.amount
26
+ charge.update!(
27
+ amount_refunded: refund_amount,
28
+ status: "refunded"
29
+ )
30
+ end
31
+
32
+ def log_already_processed(event)
33
+ Rails.logger.info("[pay-abacatepay] #{event.type} #{event.id} already processed")
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,95 @@
1
+ module Pay
2
+ module Abacatepay
3
+ module Webhooks
4
+ class Event
5
+ FREQUENCY_TO_INTERVAL = {
6
+ "WEEKLY" => 1.week,
7
+ "MONTHLY" => 1.month,
8
+ "SEMIANNUALLY" => 6.months,
9
+ "ANNUALLY" => 1.year
10
+ }.freeze
11
+
12
+ def initialize(raw)
13
+ @raw = raw.is_a?(Hash) ? raw : {}
14
+ end
15
+
16
+ attr_reader :raw
17
+
18
+ def id = @raw["id"]
19
+
20
+ def type = @raw["event"] || @raw["type"]
21
+
22
+ def data = @raw["data"] || {}
23
+
24
+ def api_version = @raw["apiVersion"]
25
+
26
+ def dev_mode? = @raw["devMode"] == true
27
+
28
+ def subscription_id = data.dig("subscription", "id")
29
+
30
+ def subscription_status = data.dig("subscription", "status")
31
+
32
+ def subscription_amount_cents = data.dig("subscription", "amount")
33
+
34
+ def subscription_currency = data.dig("subscription", "currency") || "BRL"
35
+
36
+ def frequency = data.dig("subscription", "frequency")
37
+
38
+ def subscription_created_at = parse_time(data.dig("subscription", "createdAt"))
39
+
40
+ def subscription_updated_at = parse_time(data.dig("subscription", "updatedAt"))
41
+
42
+ def canceled_at = parse_time(data.dig("subscription", "canceledAt"))
43
+
44
+ def customer_id = data.dig("customer", "id")
45
+
46
+ def customer_email = data.dig("customer", "email")
47
+
48
+ def customer_name = data.dig("customer", "name")
49
+
50
+ def customer_tax_id = data.dig("customer", "taxId")
51
+
52
+ def charge_id = data.dig("payment", "id")
53
+
54
+ def charge_amount_cents = data.dig("payment", "amount")
55
+
56
+ def paid_amount_cents = data.dig("payment", "paidAmount")
57
+
58
+ def platform_fee_cents = data.dig("payment", "platformFee")
59
+
60
+ def charge_status = data.dig("payment", "status")
61
+
62
+ def paid_at = parse_time(data.dig("payment", "updatedAt"))
63
+
64
+ def checkout_id = data.dig("checkout", "id")
65
+
66
+ def checkout_frequency = data.dig("checkout", "frequency")
67
+
68
+ def checkout_status = data.dig("checkout", "status")
69
+
70
+ def checkout_url = data.dig("checkout", "url")
71
+
72
+ def checkout_amount_cents = data.dig("checkout", "amount")
73
+
74
+ def checkout_paid_amount_cents = data.dig("checkout", "paidAmount")
75
+
76
+ def checkout_platform_fee_cents = data.dig("checkout", "platformFee")
77
+
78
+ def checkout_methods = data.dig("checkout", "methods")
79
+
80
+ def product_id = data.dig("checkout", "items", 0, "id")
81
+
82
+ def interval
83
+ FREQUENCY_TO_INTERVAL[frequency]
84
+ end
85
+
86
+ private
87
+
88
+ def parse_time(value)
89
+ return nil if value.nil? || value.to_s.empty?
90
+ Time.zone ? Time.zone.parse(value.to_s) : Time.parse(value.to_s)
91
+ end
92
+ end
93
+ end
94
+ end
95
+ end
@@ -0,0 +1,11 @@
1
+ module Pay
2
+ module Abacatepay
3
+ module Webhooks
4
+ class PayoutCompleted
5
+ # TODO: later — payout tracking (not tied to Pay::Charge/Subscription)
6
+ def call(event)
7
+ end
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ module Pay
2
+ module Abacatepay
3
+ module Webhooks
4
+ class PayoutFailed
5
+ # TODO: later — payout tracking (not tied to Pay::Charge/Subscription)
6
+ def call(event)
7
+ end
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,34 @@
1
+ module Pay
2
+ module Abacatepay
3
+ module Webhooks
4
+ class SubscriptionCancelled
5
+ def call(event_hash)
6
+ event = Pay::Abacatepay::Webhooks::Event.new(event_hash)
7
+ result = Pay::Abacatepay::ProcessedWebhook.process!(event_type: event.type, event_id: event.id) do
8
+ handle(event)
9
+ end
10
+ log_already_processed(event) if result == :already_processed
11
+ end
12
+
13
+ private
14
+
15
+ def handle(event)
16
+ subscription = Pay::Abacatepay::Subscription.find_by(processor_id: event.subscription_id)
17
+
18
+ if subscription.nil?
19
+ Rails.logger.warn(
20
+ "[pay-abacatepay] subscription.cancelled for unknown subscription #{event.subscription_id}; no-op"
21
+ )
22
+ return
23
+ end
24
+
25
+ subscription.update!(status: "canceled", ends_at: event.canceled_at || Time.current)
26
+ end
27
+
28
+ def log_already_processed(event)
29
+ Rails.logger.info("[pay-abacatepay] #{event.type} #{event.id} already processed")
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,53 @@
1
+ module Pay
2
+ module Abacatepay
3
+ module Webhooks
4
+ class SubscriptionCompleted
5
+ def call(event_hash)
6
+ event = Pay::Abacatepay::Webhooks::Event.new(event_hash)
7
+ result = Pay::Abacatepay::ProcessedWebhook.process!(event_type: event.type, event_id: event.id) do
8
+ handle(event)
9
+ end
10
+ log_already_processed(event) if result == :already_processed
11
+ end
12
+
13
+ private
14
+
15
+ def handle(event)
16
+ customer = find_customer(event)
17
+ return if customer.nil?
18
+
19
+ subscription = Pay::Abacatepay::Subscription.sync(event.subscription_id, event: event)
20
+ create_initial_charge(customer, subscription, event) if subscription && event.charge_id
21
+ end
22
+
23
+ def find_customer(event)
24
+ return nil if event.customer_id.blank?
25
+
26
+ customer = Pay::Customer.find_by(processor: "abacatepay", processor_id: event.customer_id)
27
+ if customer.nil?
28
+ Rails.logger.warn(
29
+ "[pay-abacatepay] subscription.completed for unknown customer #{event.customer_id}; " \
30
+ "Pay::Customer must be created via the app signup flow before the webhook arrives"
31
+ )
32
+ end
33
+ customer
34
+ end
35
+
36
+ def create_initial_charge(customer, subscription, event)
37
+ Pay::Abacatepay::Charge.find_or_create_by!(customer: customer, processor_id: event.charge_id) do |charge|
38
+ charge.amount = event.paid_amount_cents || event.charge_amount_cents
39
+ charge.currency = event.subscription_currency
40
+ charge.application_fee_amount = event.platform_fee_cents
41
+ charge.subscription_id = subscription.id
42
+ charge.status = "paid"
43
+ charge.created_at = event.paid_at if event.paid_at
44
+ end
45
+ end
46
+
47
+ def log_already_processed(event)
48
+ Rails.logger.info("[pay-abacatepay] #{event.type} #{event.id} already processed")
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,45 @@
1
+ module Pay
2
+ module Abacatepay
3
+ module Webhooks
4
+ class SubscriptionRenewed
5
+ def call(event_hash)
6
+ event = Pay::Abacatepay::Webhooks::Event.new(event_hash)
7
+ result = Pay::Abacatepay::ProcessedWebhook.process!(event_type: event.type, event_id: event.id) do
8
+ handle(event)
9
+ end
10
+ log_already_processed(event) if result == :already_processed
11
+ end
12
+
13
+ private
14
+
15
+ def handle(event)
16
+ existing = Pay::Abacatepay::Subscription.find_by(processor_id: event.subscription_id)
17
+
18
+ if existing.nil?
19
+ Rails.logger.warn(
20
+ "[pay-abacatepay] subscription.renewed before subscription.completed for #{event.subscription_id}; " \
21
+ "creating subscription on-the-fly"
22
+ )
23
+ end
24
+
25
+ subscription = Pay::Abacatepay::Subscription.sync(event.subscription_id, event: event)
26
+ return if subscription.nil?
27
+ return if event.charge_id.blank?
28
+
29
+ Pay::Abacatepay::Charge.find_or_create_by!(customer: subscription.customer, processor_id: event.charge_id) do |charge|
30
+ charge.amount = event.paid_amount_cents || event.charge_amount_cents
31
+ charge.currency = event.subscription_currency
32
+ charge.application_fee_amount = event.platform_fee_cents
33
+ charge.subscription_id = subscription.id
34
+ charge.status = "paid"
35
+ charge.created_at = event.paid_at if event.paid_at
36
+ end
37
+ end
38
+
39
+ def log_already_processed(event)
40
+ Rails.logger.info("[pay-abacatepay] #{event.type} #{event.id} already processed")
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,13 @@
1
+ module Pay
2
+ module Abacatepay
3
+ module Webhooks
4
+ class SubscriptionTrialStarted
5
+ def call(_event_hash)
6
+ raise NotImplementedError,
7
+ "subscription.trial_started is not listed in AbacatePay::Enums::Webhooks::EventTypes. " \
8
+ "Confirm the event exists in the AbacatePay API before enabling trial support."
9
+ end
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,11 @@
1
+ module Pay
2
+ module Abacatepay
3
+ module Webhooks
4
+ class TransferCompleted
5
+ # TODO: later — transfer tracking (not tied to Pay::Charge/Subscription)
6
+ def call(event)
7
+ end
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ module Pay
2
+ module Abacatepay
3
+ module Webhooks
4
+ class TransferFailed
5
+ # TODO: later — transfer tracking (not tied to Pay::Charge/Subscription)
6
+ def call(event)
7
+ end
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ module Pay
2
+ module Abacatepay
3
+ module Webhooks
4
+ class TransparentCompleted
5
+ # TODO: Fase 4 — transparent checkout lifecycle (charge creation)
6
+ def call(event)
7
+ end
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ module Pay
2
+ module Abacatepay
3
+ module Webhooks
4
+ class TransparentDisputed
5
+ # TODO: Fase 5 — dispute handling
6
+ def call(event)
7
+ end
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ module Pay
2
+ module Abacatepay
3
+ module Webhooks
4
+ class TransparentLost
5
+ # TODO: Fase 5 — lost dispute handling
6
+ def call(event)
7
+ end
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ module Pay
2
+ module Abacatepay
3
+ module Webhooks
4
+ class TransparentRefunded
5
+ # TODO: Fase 4 — transparent checkout refund
6
+ def call(event)
7
+ end
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,23 @@
1
+ module Pay
2
+ module Abacatepay
3
+ module Webhooks
4
+ autoload :Event, "pay/abacatepay/webhooks/event"
5
+ autoload :CheckoutCompleted, "pay/abacatepay/webhooks/checkout_completed"
6
+ autoload :CheckoutRefunded, "pay/abacatepay/webhooks/checkout_refunded"
7
+ autoload :CheckoutDisputed, "pay/abacatepay/webhooks/checkout_disputed"
8
+ autoload :CheckoutLost, "pay/abacatepay/webhooks/checkout_lost"
9
+ autoload :TransparentCompleted, "pay/abacatepay/webhooks/transparent_completed"
10
+ autoload :TransparentRefunded, "pay/abacatepay/webhooks/transparent_refunded"
11
+ autoload :TransparentDisputed, "pay/abacatepay/webhooks/transparent_disputed"
12
+ autoload :TransparentLost, "pay/abacatepay/webhooks/transparent_lost"
13
+ autoload :SubscriptionCompleted, "pay/abacatepay/webhooks/subscription_completed"
14
+ autoload :SubscriptionCancelled, "pay/abacatepay/webhooks/subscription_cancelled"
15
+ autoload :SubscriptionRenewed, "pay/abacatepay/webhooks/subscription_renewed"
16
+ autoload :SubscriptionTrialStarted, "pay/abacatepay/webhooks/subscription_trial_started"
17
+ autoload :PayoutCompleted, "pay/abacatepay/webhooks/payout_completed"
18
+ autoload :PayoutFailed, "pay/abacatepay/webhooks/payout_failed"
19
+ autoload :TransferCompleted, "pay/abacatepay/webhooks/transfer_completed"
20
+ autoload :TransferFailed, "pay/abacatepay/webhooks/transfer_failed"
21
+ end
22
+ end
23
+ end