@@ -107,7 +107,84 @@ def setup
107107 assert_equal 40_000 , ProjectAllocation . find_by ( project_id : @project1 . id ) . amount_cents
108108 end
109109
110- test 'payout_proxy_collectives_aggregated groups allocations by funding source' do
110+ test 'payout creates one expense per funding source for proxy collectives, not one per project' do
111+ funding_source = FundingSource . create! (
112+ url : 'https://github.com/sponsors/dtolnay' ,
113+ platform : 'github.com'
114+ )
115+
116+ project1 = Project . create! (
117+ url : 'https://github.com/dtolnay/syn' ,
118+ name : 'syn' ,
119+ licenses : [ 'mit' ] ,
120+ registry_names : [ 'crates.io' ] ,
121+ repository : { 'archived' => false } ,
122+ funding_source : funding_source ,
123+ owner : { 'email' => 'dtolnay@example.com' }
124+ )
125+
126+ project2 = Project . create! (
127+ url : 'https://github.com/dtolnay/serde' ,
128+ name : 'serde' ,
129+ licenses : [ 'mit' ] ,
130+ registry_names : [ 'crates.io' ] ,
131+ repository : { 'archived' => false } ,
132+ funding_source : funding_source ,
133+ owner : { 'email' => 'dtolnay@example.com' }
134+ )
135+
136+ project3 = Project . create! (
137+ url : 'https://github.com/dtolnay/anyhow' ,
138+ name : 'anyhow' ,
139+ licenses : [ 'mit' ] ,
140+ registry_names : [ 'crates.io' ] ,
141+ repository : { 'archived' => false } ,
142+ funding_source : funding_source ,
143+ owner : { 'email' => 'dtolnay@example.com' }
144+ )
145+
146+ pa1 = ProjectAllocation . create! ( allocation : @allocation , project : project1 , fund : @fund , funding_source : funding_source , amount_cents : 20000 , score : 0.3 )
147+ pa2 = ProjectAllocation . create! ( allocation : @allocation , project : project2 , fund : @fund , funding_source : funding_source , amount_cents : 20000 , score : 0.3 )
148+ pa3 = ProjectAllocation . create! ( allocation : @allocation , project : project3 , fund : @fund , funding_source : funding_source , amount_cents : 19900 , score : 0.3 )
149+
150+ proxy_collective = ProxyCollective . create! (
151+ slug : 'esf-github-sponsors-dtolnay' ,
152+ name : 'https://github.com/sponsors/dtolnay' ,
153+ website : 'https://github.com/sponsors/dtolnay'
154+ )
155+
156+ ProxyCollective . stubs ( :find_or_create_by_website ) . returns ( proxy_collective )
157+ proxy_collective . stubs ( :set_payout_method ) . returns ( true )
158+
159+ expense_requests = [ ]
160+ stub_request ( :post , /opencollective/ ) . to_return do |request |
161+ body = JSON . parse ( request . body )
162+ expense_requests << body
163+ if body [ 'query' ] . include? ( 'createExpense' )
164+ {
165+ status : 200 ,
166+ body : { data : { createExpense : { id : '1' , legacyId : 789 , status : 'APPROVED' , amount : 59900 , currency : 'USD' , description : 'test' , draftKey : 'abc' , payee : { slug : proxy_collective . slug } } } } . to_json ,
167+ headers : { 'Content-Type' => 'application/json' }
168+ }
169+ else
170+ {
171+ status : 200 ,
172+ body : { data : { processExpense : { id : '1' , status : 'APPROVED' } } } . to_json ,
173+ headers : { 'Content-Type' => 'application/json' }
174+ }
175+ end
176+ end
177+
178+ @allocation . payout
179+
180+ create_expense_calls = expense_requests . select { |r | r [ 'query' ] . include? ( 'createExpense' ) }
181+ assert_equal 1 , create_expense_calls . length , "Expected 1 aggregated expense but got #{ create_expense_calls . length } individual ones"
182+
183+ total_amount = create_expense_calls . first [ 'variables' ] [ 'expense' ] [ 'items' ] . sum { |i | i [ 'amount' ] }
184+ assert_equal 59900 , total_amount , "Expected aggregated amount of 59900 cents"
185+ end
186+
187+ test 'payout_proxy_collectives groups allocations by funding source' do
111188 funding_source = FundingSource . create! (
112189 url : 'https://github.com/sponsors/testuser' ,
113190 platform : 'github.com' ,
@@ -164,7 +241,7 @@ def setup
164241 assert_equal 10000 , grouped [ funding_source . id ] . sum ( &:amount_cents )
165242 end
166243
167- test 'payout_proxy_collectives_aggregated falls back to email when aggregated total still below minimum' do
244+ test 'payout_proxy_collectives falls back to email when aggregated total still below minimum' do
168245 funding_source = FundingSource . create! (
169246 url : 'https://github.com/sponsors/testuser' ,
170247 platform : 'github.com' ,
@@ -215,7 +292,7 @@ def setup
215292 headers : { 'Content-Type' => 'application/json' }
216293 )
217294
218- @allocation . payout_proxy_collectives_aggregated
295+ @allocation . payout_proxy_collectives
219296
220297 # Should have logged payout_skipped events with fallback message for each allocation
221298 pa1 . reload
0 commit comments