stripe_model_callbacks 0.1.6 → 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 (98) 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 -12
  9. data/app/services/stripe_model_callbacks/configure_service.rb +62 -26
  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/20230129142139_add_tax_rate_to_stripe_tax_rates.rb +5 -0
  39. data/db/migrate/20230129145312_add_country_to_stripe_tax_rates.rb +5 -0
  40. data/db/migrate/20230210081405_create_stripe_setup_intents.rb +28 -0
  41. data/db/migrate/20230331182902_add_amount_captured_to_stripe_charges.rb +6 -0
  42. data/db/migrate/20230420092307_create_stripe_payment_methods.rb +15 -0
  43. data/db/migrate/20230421072509_create_stripe_payment_intents.rb +44 -0
  44. data/db/migrate/20230422074329_add_payment_intent_to_stripe_charges.rb +6 -0
  45. data/db/migrate/20230422175529_add_payment_intent_to_stripe_refunds.rb +6 -0
  46. data/db/migrate/20230422180602_change_stripe_refunds_stripe_charge_id_to_nullable.rb +5 -0
  47. data/db/migrate/20230518072538_change_stripe_setup_intents_payment_method_to_string.rb +7 -0
  48. data/lib/stripe_model_callbacks/configuration.rb +1 -1
  49. data/lib/stripe_model_callbacks/event_mocker.rb +1 -1
  50. data/lib/stripe_model_callbacks/factories/stripe_charges.rb +10 -0
  51. data/lib/stripe_model_callbacks/factories/stripe_coupons.rb +9 -9
  52. data/lib/stripe_model_callbacks/factories/stripe_customers.rb +6 -4
  53. data/lib/stripe_model_callbacks/factories/stripe_payment_intents.rb +17 -0
  54. data/lib/stripe_model_callbacks/factories/stripe_payment_methods.rb +15 -0
  55. data/lib/stripe_model_callbacks/factories/stripe_plans.rb +9 -12
  56. data/lib/stripe_model_callbacks/factories/stripe_products.rb +6 -8
  57. data/lib/stripe_model_callbacks/factories/stripe_setup_intents.rb +7 -0
  58. data/lib/stripe_model_callbacks/factories/stripe_subscription_items.rb +6 -7
  59. data/lib/stripe_model_callbacks/factories/stripe_subscriptions.rb +10 -12
  60. data/lib/stripe_model_callbacks/factories/stripe_tax_rates.rb +10 -0
  61. data/lib/stripe_model_callbacks/fixtures/stripe_events/charge/charge.refunded.json +1 -22
  62. data/lib/stripe_model_callbacks/fixtures/stripe_events/payment_intent/payment_intent.amount_capturable_updated.json +66 -0
  63. data/lib/stripe_model_callbacks/fixtures/stripe_events/payment_intent/payment_intent.canceled.json +66 -0
  64. data/lib/stripe_model_callbacks/fixtures/stripe_events/payment_intent/payment_intent.created.json +66 -0
  65. data/lib/stripe_model_callbacks/fixtures/stripe_events/payment_intent/payment_intent.partially_funded.json +66 -0
  66. data/lib/stripe_model_callbacks/fixtures/stripe_events/payment_intent/payment_intent.payment_failed.json +66 -0
  67. data/lib/stripe_model_callbacks/fixtures/stripe_events/payment_intent/payment_intent.processing.json +66 -0
  68. data/lib/stripe_model_callbacks/fixtures/stripe_events/payment_intent/payment_intent.requires_action.json +66 -0
  69. data/lib/stripe_model_callbacks/fixtures/stripe_events/payment_intent/payment_intent.succeeded.json +66 -0
  70. data/lib/stripe_model_callbacks/fixtures/stripe_events/payment_method/payment_method.attached.json +63 -0
  71. data/lib/stripe_model_callbacks/fixtures/stripe_events/payment_method/payment_method.automatically_updated.json +63 -0
  72. data/lib/stripe_model_callbacks/fixtures/stripe_events/payment_method/payment_method.card_automatically_updated.json +63 -0
  73. data/lib/stripe_model_callbacks/fixtures/stripe_events/payment_method/payment_method.detached.json +63 -0
  74. data/lib/stripe_model_callbacks/fixtures/stripe_events/payment_method/payment_method.updated.json +63 -0
  75. data/lib/stripe_model_callbacks/fixtures/stripe_events/refund/refund.created.json +28 -0
  76. data/lib/stripe_model_callbacks/fixtures/stripe_events/setup_intent/setup_intent.created.json +47 -0
  77. data/lib/stripe_model_callbacks/fixtures/stripe_events/setup_intent/setup_intent.updated.json +47 -0
  78. data/lib/stripe_model_callbacks/fixtures/stripe_events/tax_rate/tax_rate.created.json +3 -1
  79. data/lib/stripe_model_callbacks/fixtures/stripe_events/tax_rate/tax_rate.updated.json +3 -1
  80. data/lib/stripe_model_callbacks/models/stripe_charge.rb +47 -3
  81. data/lib/stripe_model_callbacks/models/stripe_coupon.rb +11 -0
  82. data/lib/stripe_model_callbacks/models/stripe_customer.rb +12 -0
  83. data/lib/stripe_model_callbacks/models/stripe_invoice.rb +16 -1
  84. data/lib/stripe_model_callbacks/models/stripe_payment_intent.rb +126 -0
  85. data/lib/stripe_model_callbacks/models/stripe_payment_method.rb +32 -0
  86. data/lib/stripe_model_callbacks/models/stripe_plan.rb +13 -0
  87. data/lib/stripe_model_callbacks/models/stripe_product.rb +10 -0
  88. data/lib/stripe_model_callbacks/models/stripe_refund.rb +3 -1
  89. data/lib/stripe_model_callbacks/models/stripe_setup_intent.rb +21 -0
  90. data/lib/stripe_model_callbacks/models/stripe_source.rb +2 -1
  91. data/lib/stripe_model_callbacks/models/stripe_subscription.rb +23 -4
  92. data/lib/stripe_model_callbacks/models/stripe_subscription_item.rb +10 -1
  93. data/lib/stripe_model_callbacks/models/stripe_subscription_schedule.rb +1 -1
  94. data/lib/stripe_model_callbacks/models/stripe_subscription_schedule_phase.rb +1 -1
  95. data/lib/stripe_model_callbacks/models/stripe_tax_rate.rb +7 -1
  96. data/lib/stripe_model_callbacks/version.rb +1 -1
  97. data/lib/stripe_model_callbacks.rb +1 -1
  98. metadata +48 -41
@@ -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.card_automatically_updated"
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.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,28 @@
1
+ {
2
+ "created": 1326853478,
3
+ "livemode": false,
4
+ "id": "evt_00000000000000",
5
+ "type": "refund.created",
6
+ "object": "event",
7
+ "request": null,
8
+ "pending_webhooks": 1,
9
+ "api_version": "2018-01-23",
10
+ "data": {
11
+ "object": {
12
+ "id": "re_CGQ7INZZQPOC8U",
13
+ "object": "refund",
14
+ "amount": 100,
15
+ "balance_transaction": "txn_CGQ7Sq2yeAIYK4",
16
+ "charge": "ch_3MI7uIIICJxvfdbR0gVMAA5h",
17
+ "created": 1675958030,
18
+ "currency": "dkk",
19
+ "metadata": {},
20
+ "payment_intent": null,
21
+ "reason": null,
22
+ "receipt_number": "1527-1121",
23
+ "source_transfer_reversal": null,
24
+ "status": "succeeded",
25
+ "transfer_reversal": null
26
+ }
27
+ }
28
+ }
@@ -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
+ }
@@ -12,6 +12,7 @@
12
12
  "id": "txr_00000000000000",
13
13
  "object": "tax_rate",
14
14
  "active": true,
15
+ "country": "DE",
15
16
  "created": 1608755171,
16
17
  "description": "VAT Germany",
17
18
  "display_name": "VAT",
@@ -20,7 +21,8 @@
20
21
  "livemode": false,
21
22
  "metadata": {
22
23
  },
23
- "percentage": 16
24
+ "percentage": 16,
25
+ "tax_type": "vat"
24
26
  }
25
27
  }
26
28
  }
@@ -12,6 +12,7 @@
12
12
  "id": "txr_00000000000000",
13
13
  "object": "tax_rate",
14
14
  "active": true,
15
+ "country": "DE",
15
16
  "created": 1608755201,
16
17
  "description": "VAT Germany",
17
18
  "display_name": "VAT",
@@ -20,7 +21,8 @@
20
21
  "livemode": false,
21
22
  "metadata": {
22
23
  },
23
- "percentage": 16
24
+ "percentage": 16,
25
+ "tax_type": "vat"
24
26
  },
25
27
  "previous_attributes": {
26
28
  "display_name": "Old name"
@@ -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