diff --git a/app/controllers/decidim/stratified_sortitions/admin/stratified_sortitions_controller.rb b/app/controllers/decidim/stratified_sortitions/admin/stratified_sortitions_controller.rb index 90cea65..fff9472 100644 --- a/app/controllers/decidim/stratified_sortitions/admin/stratified_sortitions_controller.rb +++ b/app/controllers/decidim/stratified_sortitions/admin/stratified_sortitions_controller.rb @@ -104,19 +104,8 @@ def upload_sample @sample_participants_count = @stratified_sortition.sample_participants.count @last_sample = SampleImport.where(stratified_sortition: @stratified_sortition).order(created_at: :desc).first @samples = SampleImport.where(stratified_sortition: @stratified_sortition).order(created_at: :asc) - - @strata_data = @stratified_sortition.strata.map do |stratum| - chart_data = stratum.substrata.map do |substratum| - weighing_value = substratum.weighing.present? ? substratum.weighing.to_f : 0.0 - label_with_percentage = "#{translated_attribute(substratum.name)} (#{weighing_value}%)" - [label_with_percentage, weighing_value] - end - chart_data = chart_data.reject { |_name, value| value.zero? } - { - stratum:, - chart_data:, - } - end + @strata_data = strata_data(@stratified_sortition) + @candidates_data = candidates_data(@stratified_sortition) end private @@ -144,6 +133,71 @@ def blank_stratum def blank_substratum(stratum_form) Decidim::StratifiedSortitions::Admin::SubstratumForm.new(stratum: stratum_form.model) end + + def strata_data(stratified_sortition) + stratified_sortition.strata.map do |stratum| + chart_data = stratum.substrata.map do |substratum| + weighing_value = substratum.weighing.present? ? substratum.weighing.to_f : 0.0 + label_with_percentage = "#{translated_attribute(substratum.name)} (#{weighing_value}%)" + [label_with_percentage, weighing_value] + end + chart_data = chart_data.reject { |_name, value| value.zero? } + { + stratum:, + chart_data:, + } + end + end + + def candidates_data(stratified_sortition) + sample_candidates_ids = stratified_sortition.sample_participants.pluck(:id) + sample_candidates_stratum = fetch_sample_candidates_stratum(sample_candidates_ids) + by_stratum = group_by_stratum(sample_candidates_stratum) + by_stratum_and_substratum = group_by_stratum_and_substratum(sample_candidates_stratum) + + stratified_sortition.strata.map do |stratum| + build_stratum_chart(stratum, by_stratum, by_stratum_and_substratum) + end + end + + def fetch_sample_candidates_stratum(sample_candidates_ids) + Decidim::StratifiedSortitions::SampleParticipantStratum + .where(decidim_stratified_sortitions_sample_participant_id: sample_candidates_ids) + .select(:decidim_stratified_sortitions_sample_participant_id, + :decidim_stratified_sortitions_stratum_id, + :decidim_stratified_sortitions_substratum_id) + .distinct + .to_a + end + + def group_by_stratum(sample_candidates_stratum) + sample_candidates_stratum.group_by(&:decidim_stratified_sortitions_stratum_id) + end + + def group_by_stratum_and_substratum(sample_candidates_stratum) + sample_candidates_stratum.group_by do |s| + [s.decidim_stratified_sortitions_stratum_id, s.decidim_stratified_sortitions_substratum_id] + end + end + + def build_stratum_chart(stratum, by_stratum, by_stratum_and_substratum) + substrata = stratum.substrata + total = by_stratum[stratum.id]&.map(&:decidim_stratified_sortitions_sample_participant_id)&.uniq&.count || 0 + chart_data = substrata.map do |substratum| + build_substratum_chart_row(stratum, substratum, by_stratum_and_substratum, total) + end + chart_data = chart_data.reject { |_name, value| value.zero? } + { stratum:, chart_data: } + end + + def build_substratum_chart_row(stratum, substratum, by_stratum_and_substratum, total) + ids = (by_stratum_and_substratum[[stratum.id, substratum.id]] || []) + .map(&:decidim_stratified_sortitions_sample_participant_id).uniq + count = ids.count + percentage = total.positive? ? ((count.to_f / total) * 100).round(1) : 0.0 + label = "#{translated_attribute(substratum.name)} (#{percentage}%)" + [label, count] + end end end end diff --git a/app/packs/stylesheets/decidim/stratified_sortitions/admin/stratified_sortitions.scss b/app/packs/stylesheets/decidim/stratified_sortitions/admin/stratified_sortitions.scss index eb5b94c..481cc96 100644 --- a/app/packs/stylesheets/decidim/stratified_sortitions/admin/stratified_sortitions.scss +++ b/app/packs/stylesheets/decidim/stratified_sortitions/admin/stratified_sortitions.scss @@ -30,10 +30,8 @@ .chart-row { display: flex; - gap: 4em; margin-top: 1em; - flex-wrap: wrap; - justify-content: start; + justify-content: space-around; } .chart-col { @@ -42,12 +40,24 @@ max-width: 450px; display: flex; flex-direction: column; + margin-top: 1em; } .chart-place { max-width: 380px; } +.charts-column { + width: 100%; + display: flex; + flex-direction: column; + align-items: center; +} + +.target { + border-right: 1px solid #6B7280CC; +} + @media (max-width: 900px) { .chart-row { gap: 2em; diff --git a/app/views/decidim/stratified_sortitions/admin/stratified_sortitions/_strata_charts.html.erb b/app/views/decidim/stratified_sortitions/admin/stratified_sortitions/_strata_charts.html.erb new file mode 100644 index 0000000..0a0db3f --- /dev/null +++ b/app/views/decidim/stratified_sortitions/admin/stratified_sortitions/_strata_charts.html.erb @@ -0,0 +1,19 @@ + +

+ <%= local_assigns[:title] || "" %> +

+
+<% (strata_data || []).each do |stratum_data| %> +
+ <%= translated_attribute(stratum_data[:stratum].name).upcase %> + <% if stratum_data[:chart_data].present? %> + <%= pie_chart stratum_data[:chart_data], + legend: "bottom", + donut: false %> + <% else %> +

+ <%= t('decidim.stratified_sortitions.admin.stratified_sortitions.upload_sample.no_data') %> +

+ <% end %> +
+<% end %> diff --git a/app/views/decidim/stratified_sortitions/admin/stratified_sortitions/upload_sample.html.erb b/app/views/decidim/stratified_sortitions/admin/stratified_sortitions/upload_sample.html.erb index 546324a..af0e86a 100644 --- a/app/views/decidim/stratified_sortitions/admin/stratified_sortitions/upload_sample.html.erb +++ b/app/views/decidim/stratified_sortitions/admin/stratified_sortitions/upload_sample.html.erb @@ -22,7 +22,6 @@
<%= form_tag samples_path(id: @stratified_sortition.id), multipart: true, class: 'form' do %>
- <%= file_field_tag :file, id: 'sample-file-input' %> <% if @stratified_sortition.strata_and_substrata_configured? %> @@ -61,25 +60,13 @@
- -

- <%= t(".target") %> -

-
- <% @strata_data.each do |stratum_data| %> -
- <%= translated_attribute(stratum_data[:stratum].name).upcase %> - <% if stratum_data[:chart_data].present? %> - <%= pie_chart stratum_data[:chart_data], - legend: "bottom", - donut: false - %> - <% else %> -

<%= t('.no_data') %>

- <% end %> -
- <% end %> +
+ <%= render partial: "strata_charts", locals: { strata_data: @strata_data, title: t(".target") } %> +
+
+ <%= render partial: "strata_charts", locals: { strata_data: @candidates_data, title: t(".candidates") } %> +
diff --git a/config/locales/ca.yml b/config/locales/ca.yml index fdd8902..173a4e6 100644 --- a/config/locales/ca.yml +++ b/config/locales/ca.yml @@ -96,6 +96,7 @@ ca: success: Sorteig estratificat actualitzat amb èxit upload_sample: age: Grup d'edat + candidates: Candidats census_file: Triar un fitxer census_file_label: Arxiu excel.csv amb les dades del cens configure_strata_first: Primer has de configurar els estrats i subestrats diff --git a/config/locales/en.yml b/config/locales/en.yml index a4ba016..7c2f687 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -94,6 +94,7 @@ en: success: Stratified sortition successfully updated upload_sample: age: Age group + candidates: Candidates census_file: Choose a file census_file_label: Excel.csv file with census data configure_strata_first: You must configure strata and substrata first diff --git a/config/locales/es.yml b/config/locales/es.yml index aca21a1..3d2cd34 100644 --- a/config/locales/es.yml +++ b/config/locales/es.yml @@ -96,6 +96,7 @@ es: success: Sorteo estratificado actualizado con éxito upload_sample: age: Grupo de edad + candidates: Candidatos census_file: Elegir un archivo census_file_label: Archivo excel.csv con los datos del censo configure_strata_first: Primero debes configurar los estratos y subestratos diff --git a/spec/controllers/decidim/sortitions/admin/stratified_sortitions_controller_spec.rb b/spec/controllers/decidim/sortitions/admin/stratified_sortitions_controller_spec.rb index dcc5969..4ae8c40 100644 --- a/spec/controllers/decidim/sortitions/admin/stratified_sortitions_controller_spec.rb +++ b/spec/controllers/decidim/sortitions/admin/stratified_sortitions_controller_spec.rb @@ -205,6 +205,58 @@ module Admin end end end + + describe "upload_sample" do + let(:stratified_sortition) { create(:stratified_sortition) } + let(:params) do + { + participatory_process_slug: component.participatory_space.slug, + id: stratified_sortition.id, + } + end + + before do + stratum_1 = create(:stratum, stratified_sortition:, kind: "value", name: { ca: "Gènere", es: "Género", en: "Gender" }) + substratum_1 = create(:substratum, stratum: stratum_1, name: { ca: "Home", es: "Hombre", en: "Man" }, value: "H", weighing: "50") + substratum_2 = create(:substratum, stratum: stratum_1, name: { ca: "Dona", es: "Mujer", en: "Woman" }, value: "D", weighing: "50") + + sample_import = create(:sample_import, stratified_sortition:) + participant_1 = create(:sample_participant, decidim_stratified_sortition: stratified_sortition, decidim_stratified_sortitions_sample_import: sample_import) + participant_2 = create(:sample_participant, decidim_stratified_sortition: stratified_sortition, decidim_stratified_sortitions_sample_import: sample_import) + + create(:sample_participant_stratum, decidim_stratified_sortitions_sample_participant: participant_1, decidim_stratified_sortitions_stratum: stratum_1, decidim_stratified_sortitions_substratum: substratum_1) + create(:sample_participant_stratum, decidim_stratified_sortitions_sample_participant: participant_2, decidim_stratified_sortitions_stratum: stratum_1, decidim_stratified_sortitions_substratum: substratum_2) + end + + it "renders the upload_sample template" do + get(:upload_sample, params:) + expect(response).to render_template(:upload_sample) + end + + it "assigns @stratified_sortition" do + get(:upload_sample, params:) + expect(assigns(:stratified_sortition)).to eq(stratified_sortition) + end + + it "assigns @sample_participants_count" do + get(:upload_sample, params:) + expect(assigns(:sample_participants_count)).to eq(stratified_sortition.sample_participants.count) + end + + it "assigns @strata_data and @candidates_data" do + get(:upload_sample, params:) + expect(assigns(:strata_data)).to be_an(Array) + expect(assigns(:candidates_data)).to be_an(Array) + expect(assigns(:strata_data).first[:stratum]).to be_present + expect(assigns(:candidates_data).first[:stratum]).to be_present + end + + it "@candidates_data refleja los datos importados" do + get(:upload_sample, params:) + imported = assigns(:candidates_data).first[:chart_data].map(&:last) + expect(imported.sum).to eq(stratified_sortition.sample_participants.count) + end + end end end end