stripe_model_callbacks 0.1.7 → 0.1.8

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 (93) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +3 -3
  3. data/Rakefile +1 -1
  4. data/app/models/stripe_model_callbacks/application_record.rb +11 -7
  5. data/app/services/stripe_model_callbacks/account/external_account/updated_service.rb +1 -1
  6. data/app/services/stripe_model_callbacks/base_service.rb +6 -6
  7. data/app/services/stripe_model_callbacks/charge/dispute_updated_service.rb +3 -3
  8. data/app/services/stripe_model_callbacks/charge/updated_service.rb +5 -5
  9. data/app/services/stripe_model_callbacks/configure_service.rb +54 -27
  10. data/app/services/stripe_model_callbacks/customer/bank_account/deleted_service.rb +1 -1
  11. data/app/services/stripe_model_callbacks/customer/discount_updated_service.rb +1 -1
  12. data/app/services/stripe_model_callbacks/customer/source_updated_service.rb +3 -3
  13. data/app/services/stripe_model_callbacks/customer/subscription/updated_service.rb +2 -2
  14. data/app/services/stripe_model_callbacks/customer/updated_service.rb +2 -2
  15. data/app/services/stripe_model_callbacks/event_mocker_service.rb +14 -8
  16. data/app/services/stripe_model_callbacks/invoice/updated_service.rb +4 -4
  17. data/app/services/stripe_model_callbacks/payment_intent/updated_service.rb +19 -0
  18. data/app/services/stripe_model_callbacks/payment_method/updated_service.rb +19 -0
  19. data/app/services/stripe_model_callbacks/payout/updated_service.rb +3 -3
  20. data/app/services/stripe_model_callbacks/plan/updated_service.rb +1 -1
  21. data/app/services/stripe_model_callbacks/price/updated_service.rb +1 -1
  22. data/app/services/stripe_model_callbacks/product/updated_service.rb +1 -1
  23. data/app/services/stripe_model_callbacks/recipient/updated_service.rb +1 -1
  24. data/app/services/stripe_model_callbacks/review/updated_service.rb +1 -1
  25. data/app/services/stripe_model_callbacks/setup_intent/updated_service.rb +8 -0
  26. data/app/services/stripe_model_callbacks/sku/updated_service.rb +1 -1
  27. data/app/services/stripe_model_callbacks/source/updated_service.rb +4 -4
  28. data/app/services/stripe_model_callbacks/subscription/state_checker_service.rb +1 -1
  29. data/app/services/stripe_model_callbacks/subscription_schedule/updated_service.rb +1 -1
  30. data/app/services/stripe_model_callbacks/sync_everything.rb +17 -2
  31. data/app/services/stripe_model_callbacks/sync_from_stripe.rb +1 -1
  32. data/app/services/stripe_model_callbacks/tax_rate/updated_service.rb +3 -3
  33. data/app/services/stripe_model_callbacks/transfer/updated_service.rb +1 -1
  34. data/config/rails_best_practices.yml +1 -0
  35. data/db/migrate/20180206151132_change_activities_trackable_id_to_string.rb +1 -1
  36. data/db/migrate/20180208091647_change_stripe_subscription_items_quantity_to_integer.rb +1 -1
  37. data/db/migrate/20181219121712_add_new_primary_id_and_rename_old.rb +2 -2
  38. data/db/migrate/20230210081405_create_stripe_setup_intents.rb +28 -0
  39. data/db/migrate/20230331182902_add_amount_captured_to_stripe_charges.rb +6 -0
  40. data/db/migrate/20230420092307_create_stripe_payment_methods.rb +15 -0
  41. data/db/migrate/20230421072509_create_stripe_payment_intents.rb +44 -0
  42. data/db/migrate/20230422074329_add_payment_intent_to_stripe_charges.rb +6 -0
  43. data/db/migrate/20230422175529_add_payment_intent_to_stripe_refunds.rb +6 -0
  44. data/db/migrate/20230422180602_change_stripe_refunds_stripe_charge_id_to_nullable.rb +5 -0
  45. data/db/migrate/20230518072538_change_stripe_setup_intents_payment_method_to_string.rb +7 -0
  46. data/lib/stripe_model_callbacks/configuration.rb +1 -1
  47. data/lib/stripe_model_callbacks/event_mocker.rb +1 -1
  48. data/lib/stripe_model_callbacks/factories/stripe_charges.rb +10 -0
  49. data/lib/stripe_model_callbacks/factories/stripe_coupons.rb +9 -9
  50. data/lib/stripe_model_callbacks/factories/stripe_customers.rb +6 -4
  51. data/lib/stripe_model_callbacks/factories/stripe_payment_intents.rb +17 -0
  52. data/lib/stripe_model_callbacks/factories/stripe_payment_methods.rb +15 -0
  53. data/lib/stripe_model_callbacks/factories/stripe_plans.rb +9 -12
  54. data/lib/stripe_model_callbacks/factories/stripe_products.rb +6 -8
  55. data/lib/stripe_model_callbacks/factories/stripe_setup_intents.rb +7 -0
  56. data/lib/stripe_model_callbacks/factories/stripe_subscription_items.rb +6 -7
  57. data/lib/stripe_model_callbacks/factories/stripe_subscriptions.rb +10 -12
  58. data/lib/stripe_model_callbacks/factories/stripe_tax_rates.rb +10 -0
  59. data/lib/stripe_model_callbacks/fixtures/stripe_events/charge/charge.refunded.json +1 -0
  60. data/lib/stripe_model_callbacks/fixtures/stripe_events/payment_intent/payment_intent.amount_capturable_updated.json +66 -0
  61. data/lib/stripe_model_callbacks/fixtures/stripe_events/payment_intent/payment_intent.canceled.json +66 -0
  62. data/lib/stripe_model_callbacks/fixtures/stripe_events/payment_intent/payment_intent.created.json +66 -0
  63. data/lib/stripe_model_callbacks/fixtures/stripe_events/payment_intent/payment_intent.partially_funded.json +66 -0
  64. data/lib/stripe_model_callbacks/fixtures/stripe_events/payment_intent/payment_intent.payment_failed.json +66 -0
  65. data/lib/stripe_model_callbacks/fixtures/stripe_events/payment_intent/payment_intent.processing.json +66 -0
  66. data/lib/stripe_model_callbacks/fixtures/stripe_events/payment_intent/payment_intent.requires_action.json +66 -0
  67. data/lib/stripe_model_callbacks/fixtures/stripe_events/payment_intent/payment_intent.succeeded.json +66 -0
  68. data/lib/stripe_model_callbacks/fixtures/stripe_events/payment_method/payment_method.attached.json +63 -0
  69. data/lib/stripe_model_callbacks/fixtures/stripe_events/payment_method/payment_method.automatically_updated.json +63 -0
  70. data/lib/stripe_model_callbacks/fixtures/stripe_events/payment_method/payment_method.card_automatically_updated.json +63 -0
  71. data/lib/stripe_model_callbacks/fixtures/stripe_events/payment_method/payment_method.detached.json +63 -0
  72. data/lib/stripe_model_callbacks/fixtures/stripe_events/payment_method/payment_method.updated.json +63 -0
  73. data/lib/stripe_model_callbacks/fixtures/stripe_events/setup_intent/setup_intent.created.json +47 -0
  74. data/lib/stripe_model_callbacks/fixtures/stripe_events/setup_intent/setup_intent.updated.json +47 -0
  75. data/lib/stripe_model_callbacks/models/stripe_charge.rb +47 -3
  76. data/lib/stripe_model_callbacks/models/stripe_coupon.rb +11 -0
  77. data/lib/stripe_model_callbacks/models/stripe_customer.rb +12 -0
  78. data/lib/stripe_model_callbacks/models/stripe_invoice.rb +16 -1
  79. data/lib/stripe_model_callbacks/models/stripe_payment_intent.rb +126 -0
  80. data/lib/stripe_model_callbacks/models/stripe_payment_method.rb +32 -0
  81. data/lib/stripe_model_callbacks/models/stripe_plan.rb +13 -0
  82. data/lib/stripe_model_callbacks/models/stripe_product.rb +10 -0
  83. data/lib/stripe_model_callbacks/models/stripe_refund.rb +3 -1
  84. data/lib/stripe_model_callbacks/models/stripe_setup_intent.rb +21 -0
  85. data/lib/stripe_model_callbacks/models/stripe_source.rb +2 -1
  86. data/lib/stripe_model_callbacks/models/stripe_subscription.rb +23 -4
  87. data/lib/stripe_model_callbacks/models/stripe_subscription_item.rb +10 -1
  88. data/lib/stripe_model_callbacks/models/stripe_subscription_schedule.rb +1 -1
  89. data/lib/stripe_model_callbacks/models/stripe_subscription_schedule_phase.rb +1 -1
  90. data/lib/stripe_model_callbacks/models/stripe_tax_rate.rb +6 -0
  91. data/lib/stripe_model_callbacks/version.rb +1 -1
  92. data/lib/stripe_model_callbacks.rb +1 -1
  93. metadata +45 -13
@@ -0,0 +1,63 @@
1
+ {
2
+ "id": "evt_1MxwhGIICJxvfdbRjLpH5qNb",
3
+ "object": "event",
4
+ "api_version": "2022-11-15",
5
+ "created": 1681755758,
6
+ "data": {
7
+ "object": {
8
+ "id": "pm_1MxwglIICJxvfdbRkDNKMCwZ",
9
+ "object": "payment_method",
10
+ "billing_details": {
11
+ "address": {
12
+ "city": null,
13
+ "country": "DK",
14
+ "line1": null,
15
+ "line2": null,
16
+ "postal_code": null,
17
+ "state": null
18
+ },
19
+ "email": null,
20
+ "name": null,
21
+ "phone": null
22
+ },
23
+ "card": {
24
+ "brand": "mastercard",
25
+ "checks": {
26
+ "address_line1_check": null,
27
+ "address_postal_code_check": null,
28
+ "cvc_check": "pass"
29
+ },
30
+ "country": "DK",
31
+ "exp_month": 6,
32
+ "exp_year": 2023,
33
+ "fingerprint": "QJ3sKGzehiISoOQ3",
34
+ "funding": "debit",
35
+ "generated_from": null,
36
+ "last4": "7080",
37
+ "networks": {
38
+ "available": [
39
+ "mastercard"
40
+ ],
41
+ "preferred": null
42
+ },
43
+ "three_d_secure_usage": {
44
+ "supported": true
45
+ },
46
+ "wallet": null
47
+ },
48
+ "created": 1681755727,
49
+ "customer": "cus_NiCY7UI5u0pbJH",
50
+ "livemode": true,
51
+ "metadata": {
52
+ },
53
+ "type": "card"
54
+ }
55
+ },
56
+ "livemode": true,
57
+ "pending_webhooks": 1,
58
+ "request": {
59
+ "id": null,
60
+ "idempotency_key": "setatt_1MxwglIICJxvfdbR7jPCO6O3-src_1MxwgmIICJxvfdbRoaqKyWHH"
61
+ },
62
+ "type": "payment_method.detached"
63
+ }
@@ -0,0 +1,63 @@
1
+ {
2
+ "id": "evt_1MxwhGIICJxvfdbRjLpH5qNb",
3
+ "object": "event",
4
+ "api_version": "2022-11-15",
5
+ "created": 1681755758,
6
+ "data": {
7
+ "object": {
8
+ "id": "pm_1MxwglIICJxvfdbRkDNKMCwZ",
9
+ "object": "payment_method",
10
+ "billing_details": {
11
+ "address": {
12
+ "city": null,
13
+ "country": "DK",
14
+ "line1": null,
15
+ "line2": null,
16
+ "postal_code": null,
17
+ "state": null
18
+ },
19
+ "email": null,
20
+ "name": null,
21
+ "phone": null
22
+ },
23
+ "card": {
24
+ "brand": "mastercard",
25
+ "checks": {
26
+ "address_line1_check": null,
27
+ "address_postal_code_check": null,
28
+ "cvc_check": "pass"
29
+ },
30
+ "country": "DK",
31
+ "exp_month": 6,
32
+ "exp_year": 2023,
33
+ "fingerprint": "QJ3sKGzehiISoOQ3",
34
+ "funding": "debit",
35
+ "generated_from": null,
36
+ "last4": "7080",
37
+ "networks": {
38
+ "available": [
39
+ "mastercard"
40
+ ],
41
+ "preferred": null
42
+ },
43
+ "three_d_secure_usage": {
44
+ "supported": true
45
+ },
46
+ "wallet": null
47
+ },
48
+ "created": 1681755727,
49
+ "customer": "cus_NiCY7UI5u0pbJH",
50
+ "livemode": true,
51
+ "metadata": {
52
+ },
53
+ "type": "card"
54
+ }
55
+ },
56
+ "livemode": true,
57
+ "pending_webhooks": 1,
58
+ "request": {
59
+ "id": null,
60
+ "idempotency_key": "setatt_1MxwglIICJxvfdbR7jPCO6O3-src_1MxwgmIICJxvfdbRoaqKyWHH"
61
+ },
62
+ "type": "payment_method.updated"
63
+ }
@@ -0,0 +1,47 @@
1
+ {
2
+ "id": "evt_1MZYBJIICJxvfdbR1IBR1zYM",
3
+ "object": "event",
4
+ "api_version": "2022-11-15",
5
+ "created": 1675941649,
6
+ "data": {
7
+ "object": {
8
+ "id": "seti_1MZYBJIICJxvfdbRFtP2AeIi",
9
+ "object": "setup_intent",
10
+ "application": null,
11
+ "cancellation_reason": null,
12
+ "client_secret": "seti_1MZYBJIICJxvfdbRFtP2AeIi_secret_NKCapEVr1rCGRLrEjdHGercMNLWCKkH",
13
+ "created": 1675941649,
14
+ "customer": "cus_NKCaPfiHnRAtaq",
15
+ "description": null,
16
+ "flow_directions": null,
17
+ "last_setup_error": null,
18
+ "latest_attempt": null,
19
+ "livemode": false,
20
+ "mandate": null,
21
+ "metadata": {},
22
+ "next_action": null,
23
+ "on_behalf_of": null,
24
+ "payment_method": null,
25
+ "payment_method_options": {
26
+ "card": {
27
+ "mandate_options": null,
28
+ "network": null,
29
+ "request_three_d_secure": "automatic"
30
+ }
31
+ },
32
+ "payment_method_types": [
33
+ "card"
34
+ ],
35
+ "single_use_mandate": null,
36
+ "status": "requires_payment_method",
37
+ "usage": "off_session"
38
+ }
39
+ },
40
+ "livemode": false,
41
+ "pending_webhooks": 1,
42
+ "request": {
43
+ "id": "req_8TabPJe0whYnAR",
44
+ "idempotency_key": "853d4eff-b952-431c-b204-b0ee45895c1a"
45
+ },
46
+ "type": "setup_intent.created"
47
+ }
@@ -0,0 +1,47 @@
1
+ {
2
+ "id": "evt_1MZYBJIICJxvfdbR1IBR1zYM",
3
+ "object": "event",
4
+ "api_version": "2022-11-15",
5
+ "created": 1675941649,
6
+ "data": {
7
+ "object": {
8
+ "id": "seti_1MZYBJIICJxvfdbRFtP2AeIi",
9
+ "object": "setup_intent",
10
+ "application": null,
11
+ "cancellation_reason": null,
12
+ "client_secret": "seti_1MZYBJIICJxvfdbRFtP2AeIi_secret_NKCapEVr1rCGRLrEjdHGercMNLWCKkH",
13
+ "created": 1675941649,
14
+ "customer": "cus_NKCaPfiHnRAtaq",
15
+ "description": null,
16
+ "flow_directions": null,
17
+ "last_setup_error": null,
18
+ "latest_attempt": null,
19
+ "livemode": false,
20
+ "mandate": null,
21
+ "metadata": {},
22
+ "next_action": null,
23
+ "on_behalf_of": null,
24
+ "payment_method": null,
25
+ "payment_method_options": {
26
+ "card": {
27
+ "mandate_options": null,
28
+ "network": null,
29
+ "request_three_d_secure": "automatic"
30
+ }
31
+ },
32
+ "payment_method_types": [
33
+ "card"
34
+ ],
35
+ "single_use_mandate": null,
36
+ "status": "requires_payment_method",
37
+ "usage": "off_session"
38
+ }
39
+ },
40
+ "livemode": false,
41
+ "pending_webhooks": 1,
42
+ "request": {
43
+ "id": "req_8TabPJe0whYnAR",
44
+ "idempotency_key": "853d4eff-b952-431c-b204-b0ee45895c1a"
45
+ },
46
+ "type": "setup_intent.updated"
47
+ }
@@ -1,11 +1,20 @@
1
1
  class StripeCharge < StripeModelCallbacks::ApplicationRecord
2
2
  belongs_to :stripe_customer, optional: true, primary_key: "stripe_id"
3
3
  belongs_to :stripe_invoice, optional: true, primary_key: "stripe_id"
4
+ belongs_to :stripe_payment_intent, foreign_key: "payment_intent", optional: true, primary_key: "stripe_id"
4
5
  belongs_to :stripe_source, optional: true, primary_key: "stripe_id"
6
+ has_many :stripe_invoices, primary_key: "stripe_id"
5
7
  has_many :stripe_orders, primary_key: "stripe_id"
6
8
  has_many :stripe_refunds, primary_key: "stripe_id"
7
9
  has_many :stripe_reviews, primary_key: "stripe_id"
8
10
 
11
+ has_one :latest_charge_on_stripe_payment_intent,
12
+ class_name: "StripePaymentIntent",
13
+ foreign_key: "latest_charge",
14
+ inverse_of: :stripe_latest_charge,
15
+ primary_key: "stripe_id"
16
+
17
+ monetize :amount_captured_cents, allow_nil: true
9
18
  monetize :amount_cents
10
19
  monetize :amount_refunded_cents, allow_nil: true
11
20
  monetize :application_cents, allow_nil: true
@@ -22,29 +31,64 @@ class StripeCharge < StripeModelCallbacks::ApplicationRecord
22
31
  livemode: object.livemode,
23
32
  stripe_invoice_id: object.invoice,
24
33
  metadata: JSON.generate(object.metadata),
25
- stripe_order_id: object.order,
34
+ stripe_id: object.id,
35
+ stripe_order_id: object.try(:order),
26
36
  stripe_source_id: object.source
27
37
  )
28
38
 
39
+ if object.source.is_a?(String)
40
+ self.stripe_source_id = object.source
41
+ elsif object.source
42
+ self.stripe_source_id = object.source.id
43
+ end
44
+
29
45
  assign_amounts_from_stripe(object)
30
46
 
31
47
  StripeModelCallbacks::AttributesAssignerService.execute!(
32
48
  model: self,
33
49
  stripe_model: object,
34
50
  attributes: %w[
35
- captured currency description dispute outcome refunded fraud_details failure_message failure_code on_behalf_of paid
51
+ captured currency description dispute outcome refunded fraud_details failure_message failure_code on_behalf_of paid payment_intent
36
52
  receipt_email receipt_number review shipping source_transfer statement_descriptor status transfer_group
37
53
  ]
38
54
  )
39
55
  end
40
56
 
57
+ def capture(**)
58
+ updated_charge = Stripe::Charge.capture(stripe_id, **)
59
+ assign_from_stripe(updated_charge)
60
+ save!
61
+ end
62
+
63
+ def create_stripe_mock!
64
+ mock_charge = Stripe::Charge.create(
65
+ amount: amount_cents,
66
+ captured:,
67
+ currency:,
68
+ customer: stripe_customer_id,
69
+ id: stripe_id,
70
+ paid:,
71
+ refunded:
72
+ )
73
+ assign_from_stripe(mock_charge)
74
+ save!
75
+ end
76
+
77
+ def refund(**)
78
+ StripeRefund.create_on_stripe!(charge: stripe_id)
79
+ updated_charge = Stripe::Charge.retrieve(stripe_id, **)
80
+ assign_from_stripe(updated_charge)
81
+ save!
82
+ end
83
+
41
84
  private
42
85
 
43
86
  def assign_amounts_from_stripe(object)
44
87
  assign_attributes(
45
88
  amount: Money.new(object.amount, object.currency),
89
+ amount_captured: object.try(:amount_captured) ? Money.new(object.amount_captured, object.currency) : nil,
46
90
  amount_refunded: object.amount_refunded ? Money.new(object.amount_refunded, object.currency) : nil,
47
- application: object.application ? Money.new(object.application, object.currency) : nil
91
+ application: object.try(:application) ? Money.new(object.application, object.currency) : nil
48
92
  )
49
93
  end
50
94
  end
@@ -22,4 +22,15 @@ class StripeCoupon < StripeModelCallbacks::ApplicationRecord
22
22
  ]
23
23
  )
24
24
  end
25
+
26
+ def create_stripe_mock!
27
+ mock_coupon = Stripe::Coupon.create(
28
+ duration:,
29
+ duration_in_months:,
30
+ id: stripe_id,
31
+ percent_off:
32
+ )
33
+ assign_from_stripe(mock_coupon)
34
+ save!
35
+ end
25
36
  end
@@ -5,6 +5,9 @@ class StripeCustomer < StripeModelCallbacks::ApplicationRecord
5
5
  has_many :stripe_invoices, primary_key: "stripe_id"
6
6
  has_many :stripe_invoice_items, primary_key: "stripe_id"
7
7
  has_many :stripe_orders, primary_key: "stripe_id"
8
+ has_many :stripe_payment_intents, foreign_key: "customer", primary_key: "stripe_id"
9
+ has_many :stripe_payment_methods, foreign_key: "customer", primary_key: "stripe_id"
10
+ has_many :stripe_setup_intents, foreign_key: "customer", primary_key: "stripe_id"
8
11
  has_many :stripe_subscriptions, primary_key: "stripe_id"
9
12
  has_many :stripe_subscription_schedules, primary_key: "stripe_id"
10
13
 
@@ -31,4 +34,13 @@ class StripeCustomer < StripeModelCallbacks::ApplicationRecord
31
34
  ]
32
35
  )
33
36
  end
37
+
38
+ def create_stripe_mock!
39
+ mock_customer = Stripe::Customer.create(
40
+ id: stripe_id,
41
+ source: StripeMock.create_test_helper.generate_card_token
42
+ )
43
+ assign_from_stripe(mock_customer)
44
+ save!
45
+ end
34
46
  end
@@ -4,6 +4,7 @@ class StripeInvoice < StripeModelCallbacks::ApplicationRecord
4
4
  belongs_to :stripe_discount, optional: true
5
5
  belongs_to :stripe_subscription, optional: true, primary_key: "stripe_id"
6
6
 
7
+ has_many :stripe_charges, primary_key: "stripe_id"
7
8
  has_many :stripe_invoice_items, autosave: true, primary_key: "stripe_id"
8
9
 
9
10
  validates :stripe_id, uniqueness: true
@@ -16,11 +17,13 @@ class StripeInvoice < StripeModelCallbacks::ApplicationRecord
16
17
  monetize :tax_cents, allow_nil: true
17
18
  monetize :total_cents, allow_nil: true
18
19
 
20
+ has_one_attached :invoice_pdf_file
21
+
19
22
  def self.stripe_class
20
23
  Stripe::Invoice
21
24
  end
22
25
 
23
- def assign_from_stripe(object)
26
+ def assign_from_stripe(object) # rubocop:disable Metrics/AbcSize
24
27
  check_object_is_stripe_class(object)
25
28
  assign_attributes(
26
29
  stripe_charge_id: object.charge,
@@ -36,6 +39,7 @@ class StripeInvoice < StripeModelCallbacks::ApplicationRecord
36
39
 
37
40
  assign_amounts(object)
38
41
  assign_discount_item(object)
42
+ attach_invoice_pdf(object)
39
43
  assign_tax(object)
40
44
 
41
45
  assign_forgiven(object)
@@ -114,6 +118,17 @@ private
114
118
  end
115
119
  end
116
120
 
121
+ def attach_invoice_pdf(object)
122
+ if object.respond_to?(:invoice_pdf) && object.invoice_pdf && !invoice_pdf_file.attached?
123
+ require "open-uri"
124
+
125
+ url = URI.parse(object.invoice_pdf)
126
+ filename = File.basename(url.path)
127
+ file = url.open
128
+ invoice_pdf_file.attach(io: file, filename: filename)
129
+ end
130
+ end
131
+
117
132
  def assign_status_transitions(object)
118
133
  return unless object.respond_to?(:status_transitions)
119
134
 
@@ -0,0 +1,126 @@
1
+ class StripePaymentIntent < StripeModelCallbacks::ApplicationRecord
2
+ CANCELLABLE_STATUSES = %w[requires_payment_method requires_capture requires_confirmation requires_action].freeze
3
+
4
+ belongs_to :stripe_customer, foreign_key: "customer", optional: true, primary_key: "stripe_id"
5
+ belongs_to :stripe_latest_charge,
6
+ class_name: "StripeCharge",
7
+ foreign_key: "latest_charge",
8
+ inverse_of: :latest_charge_on_stripe_payment_intent,
9
+ optional: true,
10
+ primary_key: "stripe_id"
11
+ belongs_to :stripe_payment_method, foreign_key: "payment_method", optional: true, primary_key: "stripe_id"
12
+
13
+ has_many :stripe_charges, foreign_key: "payment_intent", primary_key: "stripe_id"
14
+ has_many :stripe_refunds, foreign_key: "payment_intent", primary_key: "stripe_id"
15
+
16
+ scope :cancellable, -> { where(status: CANCELLABLE_STATUSES) }
17
+
18
+ def self.stripe_class
19
+ Stripe::PaymentIntent
20
+ end
21
+
22
+ def assign_from_stripe(object)
23
+ check_object_is_stripe_class(object)
24
+
25
+ self.metadata = object.metadata
26
+
27
+ StripeModelCallbacks::AttributesAssignerService.execute!(
28
+ model: self,
29
+ stripe_model: object,
30
+ attributes: %w[
31
+ amount
32
+ amount_capturable
33
+ amount_details
34
+ amount_received
35
+ application
36
+ application_fee_amount
37
+ automatic_payment_methods
38
+ canceled_at
39
+ cancellation_reason
40
+ capture_method
41
+ client_secret
42
+ confirmation_method
43
+ created
44
+ currency
45
+ customer
46
+ description
47
+ id
48
+ invoice
49
+ last_payment_error
50
+ latest_charge
51
+ livemode
52
+ next_action
53
+ on_behalf_of
54
+ payment_method
55
+ payment_method_options
56
+ payment_method_types
57
+ processing
58
+ receipt_email
59
+ review
60
+ setup_future_usage
61
+ shipping
62
+ statement_descriptor
63
+ statement_descriptor_suffix
64
+ status
65
+ transfer_data
66
+ transfer_group
67
+ ]
68
+ )
69
+ end
70
+
71
+ def amount_money
72
+ Money.new(amount, currency)
73
+ end
74
+
75
+ def amount_capturable_money
76
+ Money.new(amount_capturable, currency)
77
+ end
78
+
79
+ def amount_received_money
80
+ Money.new(amount_received, currency)
81
+ end
82
+
83
+ def cancel(**args)
84
+ updated_payment_intent = Stripe::PaymentIntent.cancel(stripe_id, **args)
85
+ assign_from_stripe(updated_payment_intent)
86
+ save!
87
+ end
88
+
89
+ def cancellable?
90
+ CANCELLABLE_STATUSES.include?(status)
91
+ end
92
+
93
+ def capture(**args)
94
+ updated_payment_intent = Stripe::PaymentIntent.capture(stripe_id, **args)
95
+ assign_from_stripe(updated_payment_intent)
96
+ save!
97
+ end
98
+
99
+ def confirm(**args)
100
+ updated_payment_intent = Stripe::PaymentIntent.confirm(stripe_id, **args)
101
+ assign_from_stripe(updated_payment_intent)
102
+ save!
103
+ end
104
+
105
+ def create_stripe_mock!
106
+ mock_payment_intent = Stripe::PaymentIntent.create(
107
+ amount:,
108
+ amount_capturable:,
109
+ amount_details:,
110
+ amount_received:,
111
+ application:,
112
+ application_fee_amount:,
113
+ automatic_payment_methods:,
114
+ canceled_at:,
115
+ cancellation_reason:,
116
+ capture_method:,
117
+ client_secret:,
118
+ currency:,
119
+ customer:,
120
+ id: stripe_id,
121
+ status:
122
+ )
123
+ assign_from_stripe(mock_payment_intent)
124
+ save!
125
+ end
126
+ end
@@ -0,0 +1,32 @@
1
+ class StripePaymentMethod < StripeModelCallbacks::ApplicationRecord
2
+ belongs_to :stripe_customer, foreign_key: "customer", optional: true, primary_key: "stripe_id"
3
+
4
+ has_many :stripe_payment_intents, foreign_key: "payment_method", primary_key: "stripe_id"
5
+ has_many :stripe_setup_intents, foreign_key: "payment_method", primary_key: "stripe_id"
6
+
7
+ def self.stripe_class
8
+ Stripe::PaymentMethod
9
+ end
10
+
11
+ def assign_from_stripe(object)
12
+ check_object_is_stripe_class(object)
13
+
14
+ self.metadata = object.metadata
15
+ self.stripe_id = object.id
16
+ self.stripe_type = object.type
17
+
18
+ StripeModelCallbacks::AttributesAssignerService.execute!(
19
+ model: self,
20
+ stripe_model: object,
21
+ attributes: %w[
22
+ billing_details card created customer livemode
23
+ ]
24
+ )
25
+ end
26
+
27
+ def create_stripe_mock!
28
+ mock_payment_method = Stripe::PaymentMethod.create(customer:, id: stripe_id, type: "card")
29
+ assign_from_stripe(mock_payment_method)
30
+ save!
31
+ end
32
+ end
@@ -30,6 +30,19 @@ class StripePlan < StripeModelCallbacks::ApplicationRecord
30
30
  )
31
31
  end
32
32
 
33
+ def create_stripe_mock!
34
+ mock_plan = Stripe::Plan.create(
35
+ id: stripe_id,
36
+ amount: amount_cents,
37
+ currency:,
38
+ interval:,
39
+ interval_count:,
40
+ product: stripe_product.stripe_id
41
+ )
42
+ assign_from_stripe(mock_plan)
43
+ save!
44
+ end
45
+
33
46
  def name
34
47
  nickname.presence || stripe_product&.name
35
48
  end
@@ -34,4 +34,14 @@ class StripeProduct < StripeModelCallbacks::ApplicationRecord
34
34
  ]
35
35
  )
36
36
  end
37
+
38
+ def create_stripe_mock!
39
+ mock_product = Stripe::Product.create(
40
+ id: stripe_id,
41
+ name:,
42
+ type: "service"
43
+ )
44
+ assign_from_stripe(mock_product)
45
+ save!
46
+ end
37
47
  end
@@ -1,5 +1,6 @@
1
1
  class StripeRefund < StripeModelCallbacks::ApplicationRecord
2
2
  belongs_to :stripe_charge, optional: true, primary_key: "stripe_id"
3
+ belongs_to :stripe_payment_intent, foreign_key: "payment_intent", optional: true, primary_key: "stripe_id"
3
4
 
4
5
  monetize :amount_cents, allow_nil: true
5
6
 
@@ -12,6 +13,7 @@ class StripeRefund < StripeModelCallbacks::ApplicationRecord
12
13
  assign_attributes(
13
14
  amount: Money.new(object.amount, object.currency),
14
15
  stripe_charge_id: object.charge,
16
+ stripe_id: object.id,
15
17
  created: Time.zone.at(object.created),
16
18
  livemode: object.try(:livemode) == true,
17
19
  metadata: JSON.generate(object.metadata)
@@ -20,7 +22,7 @@ class StripeRefund < StripeModelCallbacks::ApplicationRecord
20
22
  StripeModelCallbacks::AttributesAssignerService.execute!(
21
23
  model: self,
22
24
  stripe_model: object,
23
- attributes: %w[balance_transaction currency reason receipt_number status]
25
+ attributes: %w[balance_transaction currency payment_intent reason receipt_number status]
24
26
  )
25
27
 
26
28
  self.failure_reason = object.failure_reason if object.respond_to?(:failure_reason)
@@ -0,0 +1,21 @@
1
+ class StripeSetupIntent < StripeModelCallbacks::ApplicationRecord
2
+ belongs_to :stripe_customer, foreign_key: "customer", optional: true, primary_key: "stripe_id"
3
+ belongs_to :stripe_payment_method, foreign_key: "payment_method", optional: true, primary_key: "stripe_id"
4
+
5
+ def self.stripe_class
6
+ Stripe::SetupIntent
7
+ end
8
+
9
+ def assign_from_stripe(object)
10
+ check_object_is_stripe_class(object)
11
+
12
+ StripeModelCallbacks::AttributesAssignerService.execute!(
13
+ model: self,
14
+ stripe_model: object,
15
+ attributes: %w[
16
+ application cancellation_reason client_secret created customer description flow_directions last_setup_error latest_attempt livemode mandate metadata
17
+ next_action on_behalf_of payment_method payment_method_options payment_method_types single_use_mandate status usage
18
+ ]
19
+ )
20
+ end
21
+ end
@@ -22,7 +22,8 @@ class StripeSource < StripeModelCallbacks::ApplicationRecord
22
22
  assign_ach_credit_transfer(object)
23
23
 
24
24
  StripeModelCallbacks::AttributesAssignerService.execute!(
25
- model: self, stripe_model: object,
25
+ model: self,
26
+ stripe_model: object,
26
27
  attributes: %w[
27
28
  client_secret created currency flow livemode metadata statement_descriptor
28
29
  status usage