@@ -7,6 +7,7 @@ module Admin
77 #
88 class StratifiedSortitionsController < Decidim ::StratifiedSortitions ::Admin ::ApplicationController
99 include Decidim ::ApplicationHelper
10+ include StrataChartsData
1011
1112 helper StratifiedSortitions ::ApplicationHelper
1213 helper Decidim ::PaginateHelper
@@ -33,9 +34,9 @@ def create
3334 @form = form ( Decidim ::StratifiedSortitions ::Admin ::StratifiedSortitionsForm ) . from_params ( params )
3435
3536 Decidim ::StratifiedSortitions ::Admin ::CreateStratifiedSortition . call ( @form ) do
36- on ( :ok ) do
37+ on ( :ok ) do | created_sortition |
3738 flash [ :notice ] = I18n . t ( "stratified_sortitions.create.success" , scope : "decidim.stratified_sortitions.admin" )
38- redirect_to stratified_sortitions_path ( assembly_slug : - 1 , component_id : - 1 )
39+ redirect_to edit_stratified_sortition_path ( created_sortition )
3940 end
4041
4142 on ( :invalid ) do
@@ -116,22 +117,75 @@ def execute
116117 unless stratified_sortition . can_execute?
117118 redirect_to edit_stratified_sortition_path ( stratified_sortition ) ,
118119 flash : { warning : t ( "stratified_sortitions.execute.empty_sample_participants" , scope : "decidim.stratified_sortitions.admin" ) }
120+ return
119121 end
122+
123+ @stratified_sortition = stratified_sortition
124+ @portfolio = @stratified_sortition . panel_portfolio
125+ @strata = @stratified_sortition . strata . order ( :position )
126+ @selected_participants = if @portfolio &.sampled?
127+ SampleParticipant
128+ . where ( id : @portfolio . selected_panel )
129+ . includes ( sample_participant_strata : [ :decidim_stratified_sortitions_stratum , :decidim_stratified_sortitions_substratum ] )
130+ . order ( :id )
131+ . to_a
132+ else
133+ [ ]
134+ end
135+ @strata_data = strata_data ( @stratified_sortition )
136+ @candidates_data = candidates_data ( @stratified_sortition )
137+ @results_data = results_data ( @stratified_sortition )
120138 end
121139
122140 def execute_stratified_sortition
123141 @result = FairSortitionService . new ( stratified_sortition ) . call
124142 if @result . success?
125143 stratified_sortition . update! ( status : "executed" )
126- csv_data = generate_sortition_csv ( @result )
127- send_data csv_data ,
128- filename : "sortition_results_#{ stratified_sortition . id } _#{ Time . current . strftime ( "%Y%m%d_%H%M%S" ) } .csv" ,
129- type : "text/csv" ,
130- disposition : "attachment"
144+ flash [ :notice ] = I18n . t ( "stratified_sortitions.execute.success" , scope : "decidim.stratified_sortitions.admin" )
131145 else
132146 flash [ :error ] = @result . error
147+ end
148+ redirect_to execute_stratified_sortition_path ( stratified_sortition )
149+ end
150+
151+ def export_charts_pdf
152+ portfolio = stratified_sortition . panel_portfolio
153+
154+ unless portfolio &.sampled?
155+ flash [ :error ] = I18n . t ( "stratified_sortitions.export_results.no_results" , scope : "decidim.stratified_sortitions.admin" )
133156 redirect_to execute_stratified_sortition_path ( stratified_sortition )
157+ return
134158 end
159+
160+ generator = ChartsPdfGenerator . new (
161+ stratified_sortition ,
162+ strata_data ( stratified_sortition ) ,
163+ candidates_data ( stratified_sortition ) ,
164+ results_data ( stratified_sortition ) ,
165+ locale : I18n . locale
166+ )
167+
168+ filename = "sortition_charts_#{ stratified_sortition . id } _#{ Time . current . strftime ( "%Y%m%d_%H%M%S" ) } .pdf"
169+ send_data generator . generate ,
170+ filename :,
171+ type : "application/pdf" ,
172+ disposition : "attachment"
173+ end
174+
175+ def export_results
176+ format = params [ :format ] &.downcase || "csv"
177+ portfolio = stratified_sortition . panel_portfolio
178+
179+ unless portfolio &.sampled?
180+ flash [ :error ] = I18n . t ( "stratified_sortitions.export_results.no_results" , scope : "decidim.stratified_sortitions.admin" )
181+ redirect_to execute_stratified_sortition_path ( stratified_sortition )
182+ return
183+ end
184+
185+ SortitionResultsExportJob . perform_later ( current_user , stratified_sortition , format )
186+
187+ flash [ :notice ] = I18n . t ( "decidim.admin.exports.notice" )
188+ redirect_to execute_stratified_sortition_path ( stratified_sortition )
135189 end
136190
137191 private
@@ -145,7 +199,7 @@ def stratified_sortitions
145199 end
146200
147201 def stratified_sortition
148- @stratified_sortition ||= collection . find ( params [ :id ] )
202+ @stratified_sortition ||= collection . find_by ( id : params [ :id ] )
149203 end
150204
151205 def form_presenter
@@ -159,115 +213,6 @@ def blank_stratum
159213 def blank_substratum ( stratum_form )
160214 Decidim ::StratifiedSortitions ::Admin ::SubstratumForm . new ( stratum : stratum_form . model )
161215 end
162-
163- def strata_data ( stratified_sortition )
164- stratified_sortition . strata . map do |stratum |
165- chart_data = stratum . substrata . map do |substratum |
166- quota_value = substratum . max_quota_percentage . present? ? substratum . max_quota_percentage . to_f : 0.0
167- label_with_percentage = "#{ translated_attribute ( substratum . name ) } (#{ quota_value } %)"
168- [ label_with_percentage , quota_value ]
169- end
170- chart_data = chart_data . reject { |_name , value | value . zero? }
171- {
172- stratum :,
173- chart_data :,
174- }
175- end
176- end
177-
178- def candidates_data ( stratified_sortition )
179- sample_candidates_ids = stratified_sortition . sample_participants . pluck ( :id )
180- sample_candidates_stratum = fetch_sample_candidates_stratum ( sample_candidates_ids )
181- by_stratum = group_by_stratum ( sample_candidates_stratum )
182- by_stratum_and_substratum = group_by_stratum_and_substratum ( sample_candidates_stratum )
183-
184- stratified_sortition . strata . map do |stratum |
185- build_stratum_chart ( stratum , by_stratum , by_stratum_and_substratum )
186- end
187- end
188-
189- def fetch_sample_candidates_stratum ( sample_candidates_ids )
190- Decidim ::StratifiedSortitions ::SampleParticipantStratum
191- . where ( decidim_stratified_sortitions_sample_participant_id : sample_candidates_ids )
192- . select ( :decidim_stratified_sortitions_sample_participant_id ,
193- :decidim_stratified_sortitions_stratum_id ,
194- :decidim_stratified_sortitions_substratum_id )
195- . distinct
196- . to_a
197- end
198-
199- def group_by_stratum ( sample_candidates_stratum )
200- sample_candidates_stratum . group_by ( &:decidim_stratified_sortitions_stratum_id )
201- end
202-
203- def group_by_stratum_and_substratum ( sample_candidates_stratum )
204- sample_candidates_stratum . group_by do |s |
205- [ s . decidim_stratified_sortitions_stratum_id , s . decidim_stratified_sortitions_substratum_id ]
206- end
207- end
208-
209- def build_stratum_chart ( stratum , by_stratum , by_stratum_and_substratum )
210- substrata = stratum . substrata
211- total = by_stratum [ stratum . id ] &.map ( &:decidim_stratified_sortitions_sample_participant_id ) &.uniq &.count || 0
212- chart_data = substrata . map do |substratum |
213- build_substratum_chart_row ( stratum , substratum , by_stratum_and_substratum , total )
214- end
215- chart_data = chart_data . reject { |_name , value | value . zero? }
216- { stratum :, chart_data : }
217- end
218-
219- def build_substratum_chart_row ( stratum , substratum , by_stratum_and_substratum , total )
220- ids = ( by_stratum_and_substratum [ [ stratum . id , substratum . id ] ] || [ ] )
221- . map ( &:decidim_stratified_sortitions_sample_participant_id ) . uniq
222- count = ids . count
223- percentage = total . positive? ? ( ( count . to_f / total ) * 100 ) . round ( 1 ) : 0.0
224- label = "#{ translated_attribute ( substratum . name ) } (#{ percentage } %)"
225- [ label , count ]
226- end
227-
228- # NOTE: This is a temporary export for see sortition results
229- def generate_sortition_csv ( result )
230- require "csv"
231-
232- CSV . generate ( headers : true , col_sep : ";" ) do |csv |
233- csv << [ "# INFORMACIÓ DEL SORTEIG" ]
234- csv << [ "Algorisme" , result . selection_log [ :algorithm ] ]
235- csv << [ "Versió" , result . selection_log [ :version ] ]
236- csv << [ "ID Sorteig" , result . selection_log [ :stratified_sortition_id ] ]
237- csv << [ "Generat el" , result . selection_log [ :generated_at ] ]
238- csv << [ "Temps de generació (s)" , result . selection_log [ :generation_time_seconds ] ]
239- csv << [ "Nombre de panels" , result . selection_log [ :num_panels ] ]
240- csv << [ "Iteracions" , result . selection_log [ :num_iterations ] ]
241- csv << [ "Convergència" , result . selection_log [ :convergence_achieved ] ]
242- csv << [ "Seleccionat el" , result . selection_log [ :selected_at ] ]
243- csv << [ "Índex panel seleccionat" , result . selection_log [ :selected_panel_index ] ]
244- csv << [ "Seed de verificació" , result . selection_log [ :verification_seed ] ]
245- csv << [ "Valor aleatori" , result . selection_log [ :random_value_used ] ]
246- csv << [ "Probabilitat panel seleccionat" , result . selection_log [ :selected_panel_probability ] ]
247-
248- if result . selection_log [ :fairness_metrics ] . present?
249- csv << [ "" ]
250- csv << [ "# MÈTRIQUES D'EQUITAT" ]
251- result . selection_log [ :fairness_metrics ] . each do |key , value |
252- csv << [ key . to_s . humanize , value ]
253- end
254- end
255-
256- csv << [ "" ]
257- csv << [ "# PARTICIPANTS SELECCIONATS" ]
258- csv << %w[ ID Dada_Personal_1(Identificador únic) Dada_Personal_2 Dada_Personal_3 Dada_Personal_4 ]
259-
260- result . selected_participants . each do |participant |
261- csv << [
262- participant . id ,
263- participant . personal_data_1 ,
264- participant . personal_data_2 ,
265- participant . personal_data_3 ,
266- participant . personal_data_4 ,
267- ]
268- end
269- end
270- end
271216 end
272217 end
273218 end
0 commit comments