diff --git a/app/commands/decidim/stratified_sortitions/admin/duplicate_stratified_sortition.rb b/app/commands/decidim/stratified_sortitions/admin/duplicate_stratified_sortition.rb index 0b9b26d..40be463 100644 --- a/app/commands/decidim/stratified_sortitions/admin/duplicate_stratified_sortition.rb +++ b/app/commands/decidim/stratified_sortitions/admin/duplicate_stratified_sortition.rb @@ -41,7 +41,31 @@ def duplicate_stratified_sortition current_user, ) do @duplicated_stratified_sortition = stratified_sortition.dup - @duplicated_stratified_sortition.save! + @duplicated_stratified_sortition.status = :pending + if @duplicated_stratified_sortition.save! + duplicate_strata + @duplicated_stratified_sortition + else + broadcast(:invalid) + end + end + end + + def duplicate_strata + stratified_sortition.strata.order(:position).each do |stratum| + new_stratum = stratum.dup + new_stratum.decidim_stratified_sortition_id = @duplicated_stratified_sortition.id + new_stratum.save! + + duplicate_substrata(stratum, new_stratum) + end + end + + def duplicate_substrata(stratum, new_stratum) + stratum.substrata.order(:position).each do |substratum| + new_substratum = substratum.dup + new_substratum.decidim_stratified_sortitions_stratum_id = new_stratum.id + new_substratum.save! end end end diff --git a/spec/commands/decidim/sortitions/admin/duplicate_stratified_sortition_spec.rb b/spec/commands/decidim/sortitions/admin/duplicate_stratified_sortition_spec.rb index 5168664..f79e3a6 100644 --- a/spec/commands/decidim/sortitions/admin/duplicate_stratified_sortition_spec.rb +++ b/spec/commands/decidim/sortitions/admin/duplicate_stratified_sortition_spec.rb @@ -29,6 +29,13 @@ module Admin expect(duplicated.component).to eq(stratified_sortition.component) end + it "sets the duplicated sortition status to pending" do + command.call + duplicated = Decidim::StratifiedSortitions::StratifiedSortition.last + + expect(duplicated.status).to eq("pending") + end + it "traces the action, versioning: true" do expect(Decidim.traceability) .to receive(:perform_action!) @@ -39,6 +46,100 @@ module Admin action_log = Decidim::ActionLog.last expect(action_log.action).to eq("duplicate") end + + context "when the sortition has strata and substrata" do + let!(:stratum_1) { create(:stratum, stratified_sortition:, position: 0, name: { en: "Gender" }, kind: "value") } + let!(:stratum_2) { create(:stratum, stratified_sortition:, position: 1, name: { en: "Age" }, kind: "numeric_range") } + let!(:substratum_1a) { create(:substratum, stratum: stratum_1, position: 0, name: { en: "Male" }, value: { en: "M" }, max_quota_percentage: "60") } + let!(:substratum_1b) { create(:substratum, stratum: stratum_1, position: 1, name: { en: "Female" }, value: { en: "F" }, max_quota_percentage: "60") } + let!(:substratum_2a) { create(:substratum, stratum: stratum_2, position: 0, name: { en: "18-30" }, range: "18-30", max_quota_percentage: "50") } + + it "duplicates all strata" do + expect { command.call }.to change(Decidim::StratifiedSortitions::Stratum, :count).by(2) + end + + it "duplicates all substrata" do + expect { command.call }.to change(Decidim::StratifiedSortitions::Substratum, :count).by(3) + end + + it "copies strata attributes and preserves position order" do + command.call + duplicated = Decidim::StratifiedSortitions::StratifiedSortition.last + duplicated_strata = duplicated.strata.order(:position) + + expect(duplicated_strata.size).to eq(2) + expect(duplicated_strata[0].name).to eq(stratum_1.name) + expect(duplicated_strata[0].kind).to eq(stratum_1.kind) + expect(duplicated_strata[0].position).to eq(stratum_1.position) + expect(duplicated_strata[1].name).to eq(stratum_2.name) + expect(duplicated_strata[1].kind).to eq(stratum_2.kind) + expect(duplicated_strata[1].position).to eq(stratum_2.position) + end + + it "copies substrata attributes and links them to the new strata" do + command.call + duplicated = Decidim::StratifiedSortitions::StratifiedSortition.last + duplicated_strata = duplicated.strata.order(:position) + + substrata_of_first = duplicated_strata[0].substrata.order(:position) + expect(substrata_of_first.size).to eq(2) + expect(substrata_of_first[0].name).to eq(substratum_1a.name) + expect(substrata_of_first[0].value).to eq(substratum_1a.value) + expect(substrata_of_first[0].max_quota_percentage).to eq(substratum_1a.max_quota_percentage) + expect(substrata_of_first[0].position).to eq(substratum_1a.position) + expect(substrata_of_first[1].name).to eq(substratum_1b.name) + expect(substrata_of_first[1].position).to eq(substratum_1b.position) + + substrata_of_second = duplicated_strata[1].substrata.order(:position) + expect(substrata_of_second.size).to eq(1) + expect(substrata_of_second[0].name).to eq(substratum_2a.name) + expect(substrata_of_second[0].range).to eq(substratum_2a.range) + expect(substrata_of_second[0].max_quota_percentage).to eq(substratum_2a.max_quota_percentage) + end + + it "does not modify the original strata" do + expect { command.call }.not_to(change { stratified_sortition.strata.reload.count }) + end + end + + context "when the duplicated sortition fails to save" do + let!(:stratum) { create(:stratum, stratified_sortition:, position: 0) } + let!(:substratum) { create(:substratum, stratum:, position: 0) } + + before do + allow_any_instance_of(Decidim::StratifiedSortitions::StratifiedSortition).to receive(:dup).and_wrap_original do |method| + duped = method.call + allow(duped).to receive(:save!).and_raise(ActiveRecord::RecordInvalid) + duped + end + end + + it "raises an error" do + expect { command.call }.to raise_error(ActiveRecord::RecordInvalid) + end + + it "does not create a new sortition" do + expect do + command.call + rescue ActiveRecord::RecordInvalid + nil + end.not_to change(Decidim::StratifiedSortitions::StratifiedSortition, :count) + end + + it "does not duplicate strata or substrata" do + expect do + command.call + rescue ActiveRecord::RecordInvalid + nil + end.not_to change(Decidim::StratifiedSortitions::Stratum, :count) + + expect do + command.call + rescue ActiveRecord::RecordInvalid + nil + end.not_to change(Decidim::StratifiedSortitions::Substratum, :count) + end + end end end end