11use ariadne:: ids:: UserId ;
2+ use chrono:: Utc ;
23use eyre:: { Result , eyre} ;
34use muralpay:: { MuralError , TokenFeeRequest } ;
4- use rust_decimal:: Decimal ;
5+ use rust_decimal:: { Decimal , prelude :: ToPrimitive } ;
56use serde:: { Deserialize , Serialize } ;
67
78use crate :: {
8- queue:: payouts:: { AccountBalance , PayoutsQueue } ,
9+ database:: models:: DBPayoutId ,
10+ queue:: payouts:: { AccountBalance , PayoutFees , PayoutsQueue } ,
911 routes:: ApiError ,
10- util:: error:: Context ,
12+ util:: {
13+ error:: Context ,
14+ gotenberg:: { GotenbergClient , PaymentStatement } ,
15+ } ,
1116} ;
1217
1318#[ derive( Debug , Clone , Serialize , Deserialize , utoipa:: ToSchema ) ]
@@ -54,10 +59,13 @@ impl PayoutsQueue {
5459
5560 pub async fn create_muralpay_payout_request (
5661 & self ,
62+ payout_id : DBPayoutId ,
5763 user_id : UserId ,
58- amount : muralpay:: TokenAmount ,
64+ gross_amount : Decimal ,
65+ fees : PayoutFees ,
5966 payout_details : MuralPayoutRequest ,
6067 recipient_info : muralpay:: PayoutRecipientInfo ,
68+ gotenberg : & GotenbergClient ,
6169 ) -> Result < muralpay:: PayoutRequest , ApiError > {
6270 let muralpay = self . muralpay . load ( ) ;
6371 let muralpay = muralpay
@@ -86,11 +94,71 @@ impl PayoutsQueue {
8694 }
8795 } ;
8896
97+ // Mural takes `fees.method_fee` off the top of the amount we tell them to send
98+ let sent_to_method = gross_amount - fees. platform_fee ;
99+ // ..so the net is `gross - platform_fee - method_fee`
100+ let net_amount = gross_amount - fees. total_fee ( ) ;
101+
102+ let recipient_address = recipient_info. physical_address ( ) ;
103+ let recipient_email = recipient_info. email ( ) . to_string ( ) ;
104+ let gross_amount_cents = gross_amount * Decimal :: from ( 100 ) ;
105+ let net_amount_cents = net_amount * Decimal :: from ( 100 ) ;
106+ let fees_cents = fees. total_fee ( ) * Decimal :: from ( 100 ) ;
107+ let address_line_3 = format ! (
108+ "{}, {}, {}" ,
109+ recipient_address. city,
110+ recipient_address. state,
111+ recipient_address. zip
112+ ) ;
113+
114+ let payment_statement = PaymentStatement {
115+ payment_id : payout_id. into ( ) ,
116+ recipient_address_line_1 : Some ( recipient_address. address1 . clone ( ) ) ,
117+ recipient_address_line_2 : recipient_address. address2 . clone ( ) ,
118+ recipient_address_line_3 : Some ( address_line_3) ,
119+ recipient_email,
120+ payment_date : Utc :: now ( ) ,
121+ gross_amount_cents : gross_amount_cents
122+ . to_i64 ( )
123+ . wrap_internal_err_with ( || eyre ! ( "gross amount of cents `{gross_amount_cents}` cannot be expressed as an `i64`" ) ) ?,
124+ net_amount_cents : net_amount_cents
125+ . to_i64 ( )
126+ . wrap_internal_err_with ( || eyre ! ( "net amount of cents `{net_amount_cents}` cannot be expressed as an `i64`" ) ) ?,
127+ fees_cents : fees_cents
128+ . to_i64 ( )
129+ . wrap_internal_err_with ( || eyre ! ( "fees amount of cents `{fees_cents}` cannot be expressed as an `i64`" ) ) ?,
130+ currency_code : "USD" . into ( ) ,
131+ } ;
132+ let payment_statement_doc = gotenberg
133+ . wait_for_payment_statement ( & payment_statement)
134+ . await
135+ . wrap_internal_err ( "failed to generate payment statement" ) ?;
136+
137+ // TODO
138+ // std::fs::write(
139+ // "/tmp/modrinth-payout-statement.pdf",
140+ // base64::Engine::decode(
141+ // &base64::engine::general_purpose::STANDARD,
142+ // &payment_statement_doc.body,
143+ // )
144+ // .unwrap(),
145+ // )
146+ // .unwrap();
147+
89148 let payout = muralpay:: CreatePayout {
90- amount,
149+ amount : muralpay:: TokenAmount {
150+ token_amount : sent_to_method,
151+ token_symbol : muralpay:: USDC . into ( ) ,
152+ } ,
91153 payout_details,
92154 recipient_info,
93- supporting_details : None ,
155+ supporting_details : Some ( muralpay:: SupportingDetails {
156+ supporting_document : Some ( format ! (
157+ "data:application/pdf;base64,{}" ,
158+ payment_statement_doc. body
159+ ) ) ,
160+ payout_purpose : Some ( muralpay:: PayoutPurpose :: VendorPayment ) ,
161+ } ) ,
94162 } ;
95163
96164 let payout_request = muralpay
@@ -103,7 +171,9 @@ impl PayoutsQueue {
103171 . await
104172 . map_err ( |err| match err {
105173 MuralError :: Api ( err) => ApiError :: Request ( err. into ( ) ) ,
106- err => ApiError :: Internal ( err. into ( ) ) ,
174+ err => ApiError :: Internal (
175+ eyre ! ( err) . wrap_err ( "failed to create payout request" ) ,
176+ ) ,
107177 } ) ?;
108178
109179 // try to immediately execute the payout request...
0 commit comments