@@ -4,107 +4,10 @@ defmodule Algora.Payments.Jobs.ExecutePendingTransfers do
44 queue: :transfers ,
55 max_attempts: 1
66
7- import Ecto.Changeset
8- import Ecto.Query
9-
10- alias Algora.MoneyUtils
11- alias Algora.Payments.Account
12- alias Algora.Payments.Transaction
13- alias Algora.Repo
14- alias Algora.Util
15-
16- require Logger
7+ alias Algora.Payments
178
189 @ impl Oban.Worker
19- def perform ( % Oban.Job { args: % { user_id: user_id , group_id: group_id } } ) do
20- pending_amount = get_pending_amount ( user_id )
21-
22- with { :ok , account } <- Repo . fetch_by ( Account , user_id: user_id , provider: :stripe , payouts_enabled: true ) ,
23- true <- Money . positive? ( pending_amount ) do
24- initialize_and_execute_transfer ( user_id , group_id , pending_amount , account )
25- else
26- _ -> :ok
27- end
28- end
29-
30- defp get_pending_amount ( user_id ) do
31- total_credits =
32- Repo . one (
33- from ( t in Transaction ,
34- where: t . user_id == ^ user_id ,
35- where: t . type == :credit ,
36- where: t . status == :succeeded ,
37- select: sum ( t . net_amount )
38- )
39- ) || Money . zero ( :USD )
40-
41- total_transfers =
42- Repo . one (
43- from ( t in Transaction ,
44- where: t . user_id == ^ user_id ,
45- where: t . type == :transfer ,
46- where: t . status == :succeeded or t . status == :processing or t . status == :initialized ,
47- select: sum ( t . net_amount )
48- )
49- ) || Money . zero ( :USD )
50-
51- Money . sub! ( total_credits , total_transfers )
52- end
53-
54- defp initialize_and_execute_transfer ( user_id , group_id , pending_amount , account ) do
55- with { :ok , transaction } <- initialize_transfer ( user_id , group_id , pending_amount ) ,
56- { :ok , transfer } <- execute_transfer ( transaction , account ) do
57- { :ok , transfer }
58- else
59- error ->
60- Logger . error ( "Failed to execute transfer: #{ inspect ( error ) } " )
61- error
62- end
63- end
64-
65- defp initialize_transfer ( user_id , group_id , pending_amount ) do
66- % Transaction { }
67- |> change ( % {
68- provider: "stripe" ,
69- type: :credit ,
70- status: :initialized ,
71- user_id: user_id ,
72- gross_amount: pending_amount ,
73- net_amount: pending_amount ,
74- total_fee: Money . zero ( :USD ) ,
75- group_id: group_id
76- } )
77- |> Algora.Validations . validate_positive ( :gross_amount )
78- |> Algora.Validations . validate_positive ( :net_amount )
79- |> foreign_key_constraint ( :user_id )
80- |> Repo . insert ( )
81- end
82-
83- defp execute_transfer ( transaction , account ) do
84- # TODO: set other params
85- # TODO: provide idempotency key
86- case Stripe.Transfer . create ( % {
87- amount: MoneyUtils . to_minor_units ( transaction . net_amount ) ,
88- currency: to_string ( transaction . net_amount . currency ) ,
89- destination: account . stripe_account_id
90- } ) do
91- { :ok , transfer } ->
92- # it's fine if this fails since we'll receive a webhook
93- _result = try_update_transaction ( transaction , transfer )
94- { :ok , transfer }
95-
96- { :error , error } ->
97- { :error , error }
98- end
99- end
100-
101- defp try_update_transaction ( transaction , transfer ) do
102- transaction
103- |> change ( % {
104- status: if ( transfer . status == :succeeded , do: :succeeded , else: :failed ) ,
105- provider_id: transfer . id ,
106- provider_meta: Util . normalize_struct ( transfer )
107- } )
108- |> Repo . update ( )
10+ def perform ( % Oban.Job { args: % { user_id: user_id } } ) do
11+ Payments . execute_pending_transfers ( user_id )
10912 end
11013end
0 commit comments