@@ -5,6 +5,11 @@ defmodule Algora.Payments do
55
66  alias  Algora.Accounts 
77  alias  Algora.Accounts.User 
8+   alias  Algora.Bounties 
9+   alias  Algora.Bounties.Bounty 
10+   alias  Algora.Bounties.Claim 
11+   alias  Algora.Bounties.Tip 
12+   alias  Algora.Contracts.Contract 
813  alias  Algora.MoneyUtils 
914  alias  Algora.Payments.Account 
1015  alias  Algora.Payments.Customer 
@@ -31,18 +36,19 @@ defmodule Algora.Payments do
3136  @ spec  create_stripe_session ( 
3237          user  ::  User . t ( ) , 
3338          line_items  ::  [ PSP.Session . line_item_data ( ) ] , 
34-           payment_intent_data  ::  PSP.Session . payment_intent_data ( ) 
39+           payment_intent_data  ::  PSP.Session . payment_intent_data ( ) , 
40+           opts  ::  Keyword . t ( ) 
3541        )  :: 
3642          { :ok ,  PSP . session ( ) }  |  { :error ,  PSP . error ( ) } 
37-   def  create_stripe_session ( user ,  line_items ,  payment_intent_data )  do 
43+   def  create_stripe_session ( user ,  line_items ,  payment_intent_data ,   opts   \\   [ ] )  do 
3844    with  { :ok ,  customer }  <-  fetch_or_create_customer ( user )  do 
3945      opts  =  % { 
4046        mode:  "payment" , 
4147        customer:  customer . provider_id , 
4248        billing_address_collection:  "required" , 
4349        line_items:  line_items , 
44-         success_url:  "#{ AlgoraWeb.Endpoint . url ( ) }  , 
45-         cancel_url:  "#{ AlgoraWeb.Endpoint . url ( ) }  , 
50+         success_url:  opts [ :success_url ]   ||   "#{ AlgoraWeb.Endpoint . url ( ) }  , 
51+         cancel_url:  opts [ :cancel_url ]   ||   "#{ AlgoraWeb.Endpoint . url ( ) }  , 
4652        payment_intent_data:  payment_intent_data 
4753      } 
4854
@@ -544,4 +550,140 @@ defmodule Algora.Payments do
544550        { :error ,  error } 
545551    end 
546552  end 
553+ 
554+   def  process_charge ( % Stripe.Event { type:  "charge.succeeded" ,  data:  % { object:  % Stripe.Charge { } } } ,  group_id ) 
555+       when  not  is_binary ( group_id )  do 
556+     { :error ,  :invalid_group_id } 
557+   end 
558+ 
559+   def  process_charge ( 
560+         "charge.succeeded" , 
561+         % Stripe.Charge { id:  charge_id ,  captured:  false ,  payment_intent:  payment_intent_id } , 
562+         group_id 
563+       )  do 
564+     Repo . transact ( fn  -> 
565+       Repo . update_all ( from ( t  in  Transaction ,  where:  t . group_id  ==  ^ group_id ,  where:  t . type  ==  :charge ) , 
566+         set:  [ 
567+           status:  :requires_capture , 
568+           provider:  "stripe" , 
569+           provider_id:  charge_id , 
570+           provider_charge_id:  charge_id , 
571+           provider_payment_intent_id:  payment_intent_id 
572+         ] 
573+       ) 
574+ 
575+       broadcast ( ) 
576+       { :ok ,  nil } 
577+     end ) 
578+   end 
579+ 
580+   def  process_charge ( 
581+         "charge.captured" , 
582+         % Stripe.Charge { id:  charge_id ,  captured:  true ,  payment_intent:  payment_intent_id } , 
583+         group_id 
584+       )  do 
585+     Repo . transact ( fn  -> 
586+       Repo . update_all ( from ( t  in  Transaction ,  where:  t . group_id  ==  ^ group_id ,  where:  t . type  ==  :charge ) , 
587+         set:  [ 
588+           status:  :succeeded , 
589+           provider:  "stripe" , 
590+           provider_id:  charge_id , 
591+           provider_charge_id:  charge_id , 
592+           provider_payment_intent_id:  payment_intent_id 
593+         ] 
594+       ) 
595+ 
596+       Repo . update_all ( from ( t  in  Transaction ,  where:  t . group_id  ==  ^ group_id ,  where:  t . type  !=  :charge ) , 
597+         set:  [ 
598+           status:  :requires_release , 
599+           provider:  "stripe" , 
600+           provider_id:  charge_id , 
601+           provider_charge_id:  charge_id , 
602+           provider_payment_intent_id:  payment_intent_id 
603+         ] 
604+       ) 
605+ 
606+       broadcast ( ) 
607+       { :ok ,  nil } 
608+     end ) 
609+   end 
610+ 
611+   def  process_charge ( 
612+         "charge.succeeded" , 
613+         % Stripe.Charge { id:  charge_id ,  captured:  true ,  payment_intent:  payment_intent_id } , 
614+         group_id 
615+       )  do 
616+     Repo . transact ( fn  -> 
617+       { _ ,  txs }  = 
618+         Repo . update_all ( from ( t  in  Transaction ,  where:  t . group_id  ==  ^ group_id ,  select:  t ) , 
619+           set:  [ 
620+             status:  :succeeded , 
621+             succeeded_at:  DateTime . utc_now ( ) , 
622+             provider:  "stripe" , 
623+             provider_id:  charge_id , 
624+             provider_charge_id:  charge_id , 
625+             provider_payment_intent_id:  payment_intent_id 
626+           ] 
627+         ) 
628+ 
629+       bounty_ids  =  txs  |>  Enum . map ( &  & 1 . bounty_id )  |>  Enum . reject ( & is_nil / 1 )  |>  Enum . uniq ( ) 
630+       tip_ids  =  txs  |>  Enum . map ( &  & 1 . tip_id )  |>  Enum . reject ( & is_nil / 1 )  |>  Enum . uniq ( ) 
631+       contract_ids  =  txs  |>  Enum . map ( &  & 1 . contract_id )  |>  Enum . reject ( & is_nil / 1 )  |>  Enum . uniq ( ) 
632+       claim_ids  =  txs  |>  Enum . map ( &  & 1 . claim_id )  |>  Enum . reject ( & is_nil / 1 )  |>  Enum . uniq ( ) 
633+ 
634+       Repo . update_all ( from ( b  in  Bounty ,  where:  b . id  in  ^ bounty_ids ) ,  set:  [ status:  :paid ] ) 
635+       Repo . update_all ( from ( t  in  Tip ,  where:  t . id  in  ^ tip_ids ) ,  set:  [ status:  :paid ] ) 
636+       Repo . update_all ( from ( c  in  Contract ,  where:  c . id  in  ^ contract_ids ) ,  set:  [ status:  :paid ] ) 
637+       # TODO: add and use a new "paid" status for claims 
638+       Repo . update_all ( from ( c  in  Claim ,  where:  c . id  in  ^ claim_ids ) ,  set:  [ status:  :approved ] ) 
639+ 
640+       activities_result  = 
641+         txs 
642+         |>  Enum . filter ( & ( & 1 . type  ==  :credit ) ) 
643+         |>  Enum . reduce_while ( :ok ,  fn  tx ,  :ok  -> 
644+           case  Repo . insert_activity ( tx ,  % { type:  :transaction_succeeded ,  notify_users:  [ tx . user_id ] } )  do 
645+             { :ok ,  _ }  ->  { :cont ,  :ok } 
646+             error  ->  { :halt ,  error } 
647+           end 
648+         end ) 
649+ 
650+       jobs_result  = 
651+         txs 
652+         |>  Enum . filter ( & ( & 1 . type  ==  :credit ) ) 
653+         |>  Enum . reduce_while ( :ok ,  fn  credit ,  :ok  -> 
654+           case  fetch_active_account ( credit . user_id )  do 
655+             { :ok ,  _account }  -> 
656+               case  % { credit_id:  credit . id } 
657+                    |>  Jobs.ExecutePendingTransfer . new ( ) 
658+                    |>  Oban . insert ( )  do 
659+                 { :ok ,  _job }  ->  { :cont ,  :ok } 
660+                 error  ->  { :halt ,  error } 
661+               end 
662+ 
663+             { :error ,  :no_active_account }  -> 
664+               case  % { credit_id:  credit . id } 
665+                    |>  Bounties.Jobs.PromptPayoutConnect . new ( ) 
666+                    |>  Oban . insert ( )  do 
667+                 { :ok ,  _job }  ->  { :cont ,  :ok } 
668+                 error  ->  { :halt ,  error } 
669+               end 
670+           end 
671+         end ) 
672+ 
673+       with  txs  when  txs  !=  [ ]  <-  txs , 
674+            :ok  <-  activities_result , 
675+            :ok  <-  jobs_result  do 
676+         broadcast ( ) 
677+         { :ok ,  nil } 
678+       else 
679+         { :error ,  reason }  -> 
680+           Logger . error ( "Failed to update transactions: #{ inspect ( reason ) }  ) 
681+           { :error ,  :failed_to_update_transactions } 
682+ 
683+         error  -> 
684+           Logger . error ( "Failed to update transactions: #{ inspect ( error ) }  ) 
685+           { :error ,  :failed_to_update_transactions } 
686+       end 
687+     end ) 
688+   end 
547689end 
0 commit comments