1
1
defmodule AlgoraWeb.Webhooks.StripeController do
2
2
@ behaviour Stripe.WebhookHandler
3
3
4
+ import Ecto.Changeset
4
5
import Ecto.Query
5
6
6
7
alias Algora.Payments
8
+ alias Algora.Payments.Jobs.ExecutePendingTransfers
7
9
alias Algora.Payments.Transaction
8
10
alias Algora.Repo
11
+ alias Algora.Util
9
12
10
13
require Logger
11
14
15
+ @ metadata_version Payments . metadata_version ( )
16
+
12
17
@ impl true
13
18
def handle_event ( % Stripe.Event {
14
19
type: "charge.succeeded" ,
15
- data: % { object: % { metadata: % { "version" => "2" , "group_id" => group_id } } }
20
+ data: % { object: % Stripe.Charge { metadata: % { "version" => @ metadata_version , "group_id" => group_id } } }
16
21
} )
17
22
when is_binary ( group_id ) do
18
- { :ok , count } =
19
- Repo . transact ( fn ->
20
- { count , _ } =
21
- Repo . update_all ( from ( t in Transaction , where: t . group_id == ^ group_id ) ,
22
- set: [ status: :succeeded , succeeded_at: DateTime . utc_now ( ) ]
23
- )
24
-
25
- # TODO: initiate pending transfers if any recipient has a payout account
26
- # %{transfer_id: transfer_id, user_id: user_id}
27
- # |> Algora.Workers.InitiateTransfer.new()
28
- # |> Oban.insert()
29
-
30
- { :ok , count }
31
- end )
32
-
33
- if count == 0 do
34
- { :error , :no_transactions_found }
35
- else
36
- Payments . broadcast ( )
37
- { :ok , nil }
38
- end
23
+ Repo . transact ( fn ->
24
+ update_result =
25
+ Repo . update_all ( from ( t in Transaction , where: t . group_id == ^ group_id ) ,
26
+ set: [ status: :succeeded , succeeded_at: DateTime . utc_now ( ) ]
27
+ )
28
+
29
+ # TODO: split into two groups:
30
+ # - has active payout account -> execute pending transfers
31
+ # - has no active payout account -> notify user to connect payout account
32
+ jobs_result =
33
+ from ( t in Transaction ,
34
+ where: t . group_id == ^ group_id ,
35
+ where: t . type == :credit ,
36
+ where: t . status == :succeeded
37
+ )
38
+ |> Repo . all ( )
39
+ |> Enum . map ( fn % { user_id: user_id } -> user_id end )
40
+ |> Enum . uniq ( )
41
+ |> Enum . reduce_while ( :ok , fn user_id , :ok ->
42
+ case % { user_id: user_id }
43
+ |> ExecutePendingTransfers . new ( )
44
+ |> Oban . insert ( ) do
45
+ { :ok , _job } -> { :cont , :ok }
46
+ error -> { :halt , error }
47
+ end
48
+ end )
49
+
50
+ with { count , _ } when count > 0 <- update_result ,
51
+ :ok <- jobs_result do
52
+ Payments . broadcast ( )
53
+ { :ok , nil }
54
+ else
55
+ { :error , reason } ->
56
+ Logger . error ( "Failed to update transactions: #{ inspect ( reason ) } " )
57
+ { :error , :failed_to_update_transactions }
58
+
59
+ _error ->
60
+ Logger . error ( "Failed to update transactions" )
61
+ { :error , :failed_to_update_transactions }
62
+ end
63
+ end )
39
64
end
40
65
41
66
@ impl true
42
- def handle_event ( % Stripe.Event { type: "transfer.created" } = event ) do
43
- Logger . info ( "Stripe #{ event . type } event: #{ event . id } " )
67
+ def handle_event ( % Stripe.Event {
68
+ type: "transfer.created" ,
69
+ data: % { object: % Stripe.Transfer { metadata: % { "version" => @ metadata_version } } = transfer }
70
+ } ) do
71
+ with { :ok , transaction } <- Repo . fetch_by ( Transaction , provider: "stripe" , provider_id: transfer . id ) ,
72
+ { :ok , _transaction } <- maybe_update_transaction ( transaction , transfer ) do
73
+ # TODO: notify user
74
+ Payments . broadcast ( )
75
+ { :ok , nil }
76
+ else
77
+ error ->
78
+ Logger . error ( "Failed to update transaction: #{ inspect ( error ) } " )
79
+ { :error , :failed_to_update_transaction }
80
+ end
44
81
end
45
82
46
83
@ impl true
@@ -50,4 +87,18 @@ defmodule AlgoraWeb.Webhooks.StripeController do
50
87
51
88
@ impl true
52
89
def handle_event ( _event ) , do: :ok
90
+
91
+ defp maybe_update_transaction ( transaction , transfer ) do
92
+ if transaction . status == :succeeded do
93
+ { :ok , transaction }
94
+ else
95
+ transaction
96
+ |> change ( % {
97
+ status: :succeeded ,
98
+ succeeded_at: DateTime . utc_now ( ) ,
99
+ provider_meta: Util . normalize_struct ( transfer )
100
+ } )
101
+ |> Repo . update ( )
102
+ end
103
+ end
53
104
end
0 commit comments