@@ -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 ( ) } /payment/success" ,
45- cancel_url: "#{ AlgoraWeb.Endpoint . url ( ) } /payment/canceled" ,
50+ success_url: opts [ :success_url ] || "#{ AlgoraWeb.Endpoint . url ( ) } /payment/success" ,
51+ cancel_url: opts [ :cancel_url ] || "#{ AlgoraWeb.Endpoint . url ( ) } /payment/canceled" ,
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