@@ -5,6 +5,11 @@ defmodule Algora.Payments do
5
5
6
6
alias Algora.Accounts
7
7
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
8
13
alias Algora.MoneyUtils
9
14
alias Algora.Payments.Account
10
15
alias Algora.Payments.Customer
@@ -31,18 +36,19 @@ defmodule Algora.Payments do
31
36
@ spec create_stripe_session (
32
37
user :: User . t ( ) ,
33
38
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 ( )
35
41
) ::
36
42
{ :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
38
44
with { :ok , customer } <- fetch_or_create_customer ( user ) do
39
45
opts = % {
40
46
mode: "payment" ,
41
47
customer: customer . provider_id ,
42
48
billing_address_collection: "required" ,
43
49
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" ,
46
52
payment_intent_data: payment_intent_data
47
53
}
48
54
@@ -544,4 +550,140 @@ defmodule Algora.Payments do
544
550
{ :error , error }
545
551
end
546
552
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
547
689
end
0 commit comments