From 64f39e2c780dff8c1b607f5dbdf0cccfa2370d57 Mon Sep 17 00:00:00 2001 From: benoitqueyron <72251526+Benoit-MINT@users.noreply.github.com> Date: Tue, 19 Nov 2024 16:11:32 +0100 Subject: [PATCH 1/7] nouveau model InstructeursProcedure avec position --- app/models/instructeur.rb | 2 ++ app/models/instructeurs_procedure.rb | 4 ++++ app/models/procedure.rb | 2 ++ ...241119142129_create_instructeurs_procedures.rb | 15 +++++++++++++++ db/schema.rb | 15 ++++++++++++++- 5 files changed, 37 insertions(+), 1 deletion(-) create mode 100644 app/models/instructeurs_procedure.rb create mode 100644 db/migrate/20241119142129_create_instructeurs_procedures.rb diff --git a/app/models/instructeur.rb b/app/models/instructeur.rb index b84e2c3b7..579b7de90 100644 --- a/app/models/instructeur.rb +++ b/app/models/instructeur.rb @@ -27,6 +27,8 @@ class Instructeur < ApplicationRecord has_many :exports, as: :user_profile has_many :archives, as: :user_profile + has_many :instructeurs_procedures, dependent: :destroy + belongs_to :user scope :with_instant_email_message_notifications, -> { diff --git a/app/models/instructeurs_procedure.rb b/app/models/instructeurs_procedure.rb new file mode 100644 index 000000000..a16ad581b --- /dev/null +++ b/app/models/instructeurs_procedure.rb @@ -0,0 +1,4 @@ +class InstructeursProcedure < ApplicationRecord + belongs_to :instructeur + belongs_to :procedure +end diff --git a/app/models/procedure.rb b/app/models/procedure.rb index 90344edc9..633037599 100644 --- a/app/models/procedure.rb +++ b/app/models/procedure.rb @@ -63,6 +63,8 @@ class Procedure < ApplicationRecord has_many :bulk_messages, dependent: :destroy has_many :labels, dependent: :destroy + has_many :instructeurs_procedures, dependent: :destroy + def active_dossier_submitted_message published_dossier_submitted_message || draft_dossier_submitted_message end diff --git a/db/migrate/20241119142129_create_instructeurs_procedures.rb b/db/migrate/20241119142129_create_instructeurs_procedures.rb new file mode 100644 index 000000000..1fa66210f --- /dev/null +++ b/db/migrate/20241119142129_create_instructeurs_procedures.rb @@ -0,0 +1,15 @@ +# frozen_string_literal: true + +class CreateInstructeursProcedures < ActiveRecord::Migration[7.0] + def change + create_table :instructeurs_procedures do |t| + t.references :instructeur, null: false, foreign_key: true + t.references :procedure, null: false, foreign_key: true + t.integer :position + + t.timestamps + end + + add_index :instructeurs_procedures, [:instructeur_id, :procedure_id], unique: true, name: 'index_instructeurs_procedures_on_instructeur_and_procedure' + end +end diff --git a/db/schema.rb b/db/schema.rb index 8da54cc84..b76f5fc53 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema[7.0].define(version: 2024_11_12_090128) do +ActiveRecord::Schema[7.0].define(version: 2024_11_19_142129) do # These are extensions that must be enabled in order to support this database enable_extension "pg_buffercache" enable_extension "pg_stat_statements" @@ -819,6 +819,17 @@ ActiveRecord::Schema[7.0].define(version: 2024_11_12_090128) do t.index ["user_id"], name: "index_instructeurs_on_user_id" end + create_table "instructeurs_procedures", force: :cascade do |t| + t.datetime "created_at", null: false + t.bigint "instructeur_id", null: false + t.integer "position" + t.bigint "procedure_id", null: false + t.datetime "updated_at", null: false + t.index ["instructeur_id", "procedure_id"], name: "index_instructeurs_procedures_on_instructeur_and_procedure", unique: true + t.index ["instructeur_id"], name: "index_instructeurs_procedures_on_instructeur_id" + t.index ["procedure_id"], name: "index_instructeurs_procedures_on_procedure_id" + end + create_table "invites", id: :serial, force: :cascade do |t| t.datetime "created_at", precision: nil t.integer "dossier_id" @@ -1323,6 +1334,8 @@ ActiveRecord::Schema[7.0].define(version: 2024_11_12_090128) do add_foreign_key "groupe_instructeurs", "procedures" add_foreign_key "initiated_mails", "procedures" add_foreign_key "instructeurs", "users" + add_foreign_key "instructeurs_procedures", "instructeurs" + add_foreign_key "instructeurs_procedures", "procedures" add_foreign_key "labels", "procedures" add_foreign_key "merge_logs", "users" add_foreign_key "procedure_presentations", "assign_tos" From 010ea0586c6675ec665c672af6f4df259a1077d9 Mon Sep 17 00:00:00 2001 From: benoitqueyron <72251526+Benoit-MINT@users.noreply.github.com> Date: Wed, 20 Nov 2024 14:38:16 +0100 Subject: [PATCH 2/7] affichage selon l'ordre de instructeurs_procedures.position --- .../instructeurs/procedures_controller.rb | 3 ++- app/models/instructeur.rb | 11 +++++++++++ app/models/procedure.rb | 15 +++++++++++---- 3 files changed, 24 insertions(+), 5 deletions(-) diff --git a/app/controllers/instructeurs/procedures_controller.rb b/app/controllers/instructeurs/procedures_controller.rb index 4aababff6..d5d7cdc53 100644 --- a/app/controllers/instructeurs/procedures_controller.rb +++ b/app/controllers/instructeurs/procedures_controller.rb @@ -25,7 +25,8 @@ module Instructeurs @procedures = all_procedures.order(closed_at: :desc, unpublished_at: :desc, published_at: :desc, created_at: :desc) publiees_or_closes_with_dossiers_en_cours = all_procedures_for_listing.publiees.or(all_procedures.closes.where(id: procedures_dossiers_en_cours)) - @procedures_en_cours = publiees_or_closes_with_dossiers_en_cours.order(published_at: :desc).page(params[:page]).per(ITEMS_PER_PAGE) + current_instructeur.ensure_instructeur_procedures_for(publiees_or_closes_with_dossiers_en_cours) + @procedures_en_cours = publiees_or_closes_with_dossiers_en_cours.order_by_position_for(current_instructeur).page(params[:page]).per(ITEMS_PER_PAGE) closes_with_no_dossier_en_cours = all_procedures.closes.excluding(all_procedures.closes.where(id: procedures_dossiers_en_cours)) @procedures_closes = closes_with_no_dossier_en_cours.order(created_at: :desc).page(params[:page]).per(ITEMS_PER_PAGE) @procedures_draft = all_procedures_for_listing.brouillons.order(created_at: :desc).page(params[:page]).per(ITEMS_PER_PAGE) diff --git a/app/models/instructeur.rb b/app/models/instructeur.rb index 579b7de90..40cd09587 100644 --- a/app/models/instructeur.rb +++ b/app/models/instructeur.rb @@ -107,6 +107,17 @@ class Instructeur < ApplicationRecord end end + def ensure_instructeur_procedures_for(procedures) + current_instructeur_procedures = instructeurs_procedures.where(procedure_id: procedures.map(&:id)) + top_position = current_instructeur_procedures.map(&:position).max || 0 + missing_instructeur_procedures = procedures.sort_by(&:published_at).map(&:id).filter_map do |procedure_id| + if !procedure_id.in?(current_instructeur_procedures.map(&:procedure_id)) + { instructeur_id: id, procedure_id:, position: top_position += 1 } + end + end + InstructeursProcedure.insert_all(missing_instructeur_procedures) if missing_instructeur_procedures.size.positive? + end + def procedure_presentation_and_errors_for_procedure_id(procedure_id) assign_to .joins(:groupe_instructeur) diff --git a/app/models/procedure.rb b/app/models/procedure.rb index 633037599..41f9fc803 100644 --- a/app/models/procedure.rb +++ b/app/models/procedure.rb @@ -193,6 +193,17 @@ class Procedure < ApplicationRecord ) } + scope :for_api_v2, -> { + includes(:draft_revision, :published_revision, administrateurs: :user) + } + + scope :order_by_position_for, -> (instructeur) { + joins(:instructeurs_procedures) + .select('procedures.*, instructeurs_procedures.position AS position') + .where(instructeurs_procedures: { instructeur_id: instructeur.id }) + .order('position DESC') + } + enum declarative_with_state: { en_instruction: 'en_instruction', accepte: 'accepte' @@ -203,10 +214,6 @@ class Procedure < ApplicationRecord other: 'other' }, _prefix: true - scope :for_api_v2, -> { - includes(:draft_revision, :published_revision, administrateurs: :user) - } - validates :libelle, presence: true, allow_blank: false, allow_nil: false validates :description, presence: true, allow_blank: false, allow_nil: false validates :administrateurs, presence: true From bc3730a0325b1132e7c5a6c9f0d915b7df45df70 Mon Sep 17 00:00:00 2001 From: benoitqueyron <72251526+Benoit-MINT@users.noreply.github.com> Date: Wed, 20 Nov 2024 16:33:57 +0100 Subject: [PATCH 3/7] nouvelle page pour ordonner avec empty layout --- .../instructeurs/procedures_controller.rb | 10 +++++- .../instructeurs/procedures/index.html.haml | 13 +++++--- .../procedures/order_positions.html.haml | 24 ++++++++++++++ app/views/layouts/empty_layout.html.haml | 31 +++++++++++++++++++ config/routes.rb | 5 +++ 5 files changed, 77 insertions(+), 6 deletions(-) create mode 100644 app/views/instructeurs/procedures/order_positions.html.haml create mode 100644 app/views/layouts/empty_layout.html.haml diff --git a/app/controllers/instructeurs/procedures_controller.rb b/app/controllers/instructeurs/procedures_controller.rb index d5d7cdc53..ba5cf835f 100644 --- a/app/controllers/instructeurs/procedures_controller.rb +++ b/app/controllers/instructeurs/procedures_controller.rb @@ -2,7 +2,7 @@ module Instructeurs class ProceduresController < InstructeurController - before_action :ensure_ownership!, except: [:index] + before_action :ensure_ownership!, except: [:index, :order_positions, :update_order_positions] before_action :ensure_not_super_admin!, only: [:download_export, :exports] ITEMS_PER_PAGE = 100 @@ -68,6 +68,14 @@ module Instructeurs @statut.blank? ? @statut = 'en-cours' : @statut = params[:statut] end + def order_positions + @procedures = Procedure.where(id: params[:collection_ids]).order_by_position_for(current_instructeur) + render layout: "empty_layout" + end + + def update_order_positions + end + def show @procedure = procedure # Technically, procedure_presentation already sets the attribute. diff --git a/app/views/instructeurs/procedures/index.html.haml b/app/views/instructeurs/procedures/index.html.haml index f18d64e94..7a04633b7 100644 --- a/app/views/instructeurs/procedures/index.html.haml +++ b/app/views/instructeurs/procedures/index.html.haml @@ -12,17 +12,17 @@ = tab_item(t('pluralize.closed', count: @procedures_closes_count), instructeur_procedures_path(statut: 'archivees'), active: @statut == 'archivees', badge: number_with_html_delimiter(@procedures_closes_count)) .fr-container - - if @statut.in? ["publiees", "en-cours"] # FIX ME: @statut === "en-cours" à partir du 1/11/2023 + - if @statut == "en-cours" = render Dsfr::CalloutComponent.new(title: nil) do |c| - c.with_body do = t(".procedure_en_cours_description") - collection = @procedures_en_cours - - if @statut === "brouillons" + - if @statut == "brouillons" = render Dsfr::CalloutComponent.new(title: nil) do |c| - c.with_body do = t(".procedure_en_test_description") - collection = @procedures_draft - - if @statut === "archivees" + - if @statut == "archivees" = render Dsfr::CalloutComponent.new(title: nil) do |c| - c.with_body do = t(".procedure_close_description") @@ -30,8 +30,11 @@ - if collection.present? - %h2.fr-h6 - = page_entries_info collection + .fr-container.flex.justify-between.fr-mb-6w + %h2.fr-h6.fr-m-0 + = page_entries_info collection + - if (@statut == "en-cours" && collection.size > 1) + = link_to "Personnaliser l'ordre", order_positions_instructeur_procedures_path(collection_ids: collection.map(&:id)), class: 'fr-btn fr-btn--sm fr-btn--tertiary fr-btn--icon-left fr-icon-settings-5-line' %ul.procedure-list.fr-pl-0 = render partial: 'instructeurs/procedures/list', collection: collection, diff --git a/app/views/instructeurs/procedures/order_positions.html.haml b/app/views/instructeurs/procedures/order_positions.html.haml new file mode 100644 index 000000000..7d3634aba --- /dev/null +++ b/app/views/instructeurs/procedures/order_positions.html.haml @@ -0,0 +1,24 @@ +.fr-container.fr-mt-6w.fr-mb-15w + = link_to " Liste des démarches", instructeur_procedures_path, class: 'fr-link fr-icon-arrow-left-line fr-link--icon--left fr-icon--sm' + %h3.fr-my-3w + Personnaliser l'ordre des #{@procedures.size} démarches « en cours » + %p Déplacez les démarches dans la liste pour les classer en fonction de vos préférences : + + %fr-container + = form_tag update_order_positions_instructeur_procedures_path, method: :patch do + - @procedures.each do |procedure| + .fr-card.fr-mb-1w.fr-py-1w.fr-px-2w + .flex.align-center + %button.fr-btn.fr-icon-arrow-up-line.fr-btn--secondary.fr-col-1 + %button.fr-btn.fr-icon-arrow-down-line.fr-btn--secondary.fr-col-1.fr-mx-2w + - if procedure.close? + %span.fr-badge.fr-mr-2w Close + - elsif procedure.depubliee? + %span.fr-badge.fr-mr-2w Dépubliée + = "#{procedure.libelle} - n°#{procedure.id}" + = hidden_field_tag "ordered_procedure_ids[]", procedure.id + +.fixed-footer.fr-py-1w + .fr-btns-group.fr-btns-group--center.fr-btns-group--inline.fr-btns-group--inline-lg + = link_to "Annuler", instructeur_procedures_path, class: 'fr-btn fr-btn--secondary fr-my-1w' + %button.fr-btn.fr-my-1w{ type: "submit", form: 'order-instructeur-procedures-form' } Valider diff --git a/app/views/layouts/empty_layout.html.haml b/app/views/layouts/empty_layout.html.haml new file mode 100644 index 000000000..fee313006 --- /dev/null +++ b/app/views/layouts/empty_layout.html.haml @@ -0,0 +1,31 @@ +!!! 5 +%html{ lang: html_lang, data: { fr_scheme: 'system' }, class: yield(:root_class) } + %head + %meta{ "http-equiv": "Content-Type", content: "text/html; charset=UTF-8" } + %meta{ "http-equiv": "X-UA-Compatible", content: "IE=edge" } + %meta{ name: "viewport", content: "width=device-width, initial-scale=1" } + %meta{ name: "application-name", content: Current.application_name } + %meta{ name: "apple-mobile-web-app-title", content: Current.application_name } + = csrf_meta_tags + + %title + = content_for?(:title) ? "#{yield(:title)} · #{Current.application_name}" : Current.application_name + + = render partial: "layouts/favicons" + + = vite_client_tag + = vite_react_refresh_tag + = vite_javascript_tag 'application' + + = preload_link_tag(asset_url("Marianne-Regular.woff2")) + = preload_link_tag(asset_url("Spectral-Regular.ttf")) + + = vite_stylesheet_tag 'main', media: 'all' + = stylesheet_link_tag 'application', media: 'all' + + = render partial: 'layouts/setup_theme' + + %body{ class: browser.platform.ios? ? 'ios' : nil, data: { controller: 'turbo' } } + .page-wrapper + %main + = content_for?(:content) ? yield(:content) : yield diff --git a/config/routes.rb b/config/routes.rb index 518f513aa..4f6ac0518 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -461,6 +461,11 @@ Rails.application.routes.draw do put 'preview' end end + + collection do + get 'order_positions' + patch 'update_order_positions' + end end resources :procedure_presentation, only: [:update] do From 9d50034a16e5199188e87c33f6e78480c25887b2 Mon Sep 17 00:00:00 2001 From: benoitqueyron <72251526+Benoit-MINT@users.noreply.github.com> Date: Fri, 6 Dec 2024 17:02:02 +0100 Subject: [PATCH 4/7] =?UTF-8?q?controller=20TS:=20modification=20de=20l'or?= =?UTF-8?q?dre,=20=C3=A9tat=20des=20boutons?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../move_procedures_position_controller.ts | 62 +++++++++++++++++++ .../procedures/order_positions.html.haml | 6 +- 2 files changed, 65 insertions(+), 3 deletions(-) create mode 100644 app/javascript/controllers/move_procedures_position_controller.ts diff --git a/app/javascript/controllers/move_procedures_position_controller.ts b/app/javascript/controllers/move_procedures_position_controller.ts new file mode 100644 index 000000000..90b9476fb --- /dev/null +++ b/app/javascript/controllers/move_procedures_position_controller.ts @@ -0,0 +1,62 @@ +import { ApplicationController } from './application_controller'; + +export class MoveProceduresPositionController extends ApplicationController { + connect() { + this.updateButtonsStates(); + } + + async moveUp(event: Event) { + event.preventDefault(); + const button = event.currentTarget as HTMLButtonElement; + const upCard = button.closest('.fr-card'); + + await this.switchCards(upCard!, upCard!.previousElementSibling!); + + upCard!.parentNode!.insertBefore(upCard!, upCard!.previousElementSibling); + this.updateButtonsStates(); + } + + async moveDown(event: Event) { + event.preventDefault(); + const button = event.currentTarget as HTMLButtonElement; + const downCard = button.closest('.fr-card'); + + await this.switchCards(downCard!.nextElementSibling!, downCard!); + + downCard!.parentNode!.insertBefore(downCard!.nextElementSibling!, downCard); + this.updateButtonsStates(); + } + + private async switchCards(upCard: Element, downCard: Element): Promise { + const upCardRect = upCard.getBoundingClientRect(); + const downCardRect = downCard.getBoundingClientRect(); + + const upAnimation = upCard.animate( + [ + { transform: `translateY(0)` }, + { transform: `translateY(${downCardRect.top - upCardRect.top}px)` } + ], + { duration: 300, easing: 'ease-in-out' } + ); + + const downAnimation = downCard.animate( + [ + { transform: `translateY(0)` }, + { transform: `translateY(${upCardRect.top - downCardRect.top}px)` } + ], + { duration: 300, easing: 'ease-in-out' } + ); + + await Promise.all([upAnimation.finished, downAnimation.finished]); + } + + private updateButtonsStates() { + const buttons = [ + ...this.element.querySelectorAll('button') + ] as HTMLButtonElement[]; + buttons.forEach( + (button, index) => + (button.disabled = index == 0 || index == buttons.length - 1) + ); + } +} diff --git a/app/views/instructeurs/procedures/order_positions.html.haml b/app/views/instructeurs/procedures/order_positions.html.haml index 7d3634aba..f50de80e5 100644 --- a/app/views/instructeurs/procedures/order_positions.html.haml +++ b/app/views/instructeurs/procedures/order_positions.html.haml @@ -4,13 +4,13 @@ Personnaliser l'ordre des #{@procedures.size} démarches « en cours » %p Déplacez les démarches dans la liste pour les classer en fonction de vos préférences : - %fr-container + %fr-container{ data: { controller: 'move-procedures-position' } } = form_tag update_order_positions_instructeur_procedures_path, method: :patch do - @procedures.each do |procedure| .fr-card.fr-mb-1w.fr-py-1w.fr-px-2w .flex.align-center - %button.fr-btn.fr-icon-arrow-up-line.fr-btn--secondary.fr-col-1 - %button.fr-btn.fr-icon-arrow-down-line.fr-btn--secondary.fr-col-1.fr-mx-2w + %button.fr-btn.fr-icon-arrow-up-line.fr-btn--secondary.fr-col-1{ data: { action: "move-procedures-position#moveUp" } } + %button.fr-btn.fr-icon-arrow-down-line.fr-btn--secondary.fr-col-1.fr-mx-2w{ data: { action: "move-procedures-position#moveDown" } } - if procedure.close? %span.fr-badge.fr-mr-2w Close - elsif procedure.depubliee? From 3e1a510286e7e9a07bd9b30c0f7e0d6b7ec96fb4 Mon Sep 17 00:00:00 2001 From: benoitqueyron <72251526+Benoit-MINT@users.noreply.github.com> Date: Fri, 6 Dec 2024 10:55:18 +0100 Subject: [PATCH 5/7] =?UTF-8?q?r=C3=A9cup=C3=A9ration=20et=20update=20des?= =?UTF-8?q?=20InstructeursProcedure=20positions?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/controllers/instructeurs/procedures_controller.rb | 6 ++++++ app/models/instructeur.rb | 9 +++++++++ app/models/instructeurs_procedure.rb | 2 ++ 3 files changed, 17 insertions(+) diff --git a/app/controllers/instructeurs/procedures_controller.rb b/app/controllers/instructeurs/procedures_controller.rb index ba5cf835f..decaa9c17 100644 --- a/app/controllers/instructeurs/procedures_controller.rb +++ b/app/controllers/instructeurs/procedures_controller.rb @@ -74,6 +74,8 @@ module Instructeurs end def update_order_positions + current_instructeur.update_instructeur_procedures_positions(ordered_procedure_ids_params) + redirect_to instructeur_procedures_path, notice: "L'ordre des démarches a été mis à jour." end def show @@ -381,5 +383,9 @@ module Instructeurs def cookies_export_key "exports_#{@procedure.id}_seen_at" end + + def ordered_procedure_ids_params + params.require(:ordered_procedure_ids) + end end end diff --git a/app/models/instructeur.rb b/app/models/instructeur.rb index 40cd09587..83f035d44 100644 --- a/app/models/instructeur.rb +++ b/app/models/instructeur.rb @@ -118,6 +118,15 @@ class Instructeur < ApplicationRecord InstructeursProcedure.insert_all(missing_instructeur_procedures) if missing_instructeur_procedures.size.positive? end + def update_instructeur_procedures_positions(ordered_procedure_ids) + procedure_id_position = ordered_procedure_ids.reverse.each.with_index.to_h + InstructeursProcedure.transaction do + procedure_id_position.each do |procedure_id, position| + InstructeursProcedure.where(procedure_id:, instructeur_id: id).update(position:) + end + end + end + def procedure_presentation_and_errors_for_procedure_id(procedure_id) assign_to .joins(:groupe_instructeur) diff --git a/app/models/instructeurs_procedure.rb b/app/models/instructeurs_procedure.rb index a16ad581b..6f0216fa4 100644 --- a/app/models/instructeurs_procedure.rb +++ b/app/models/instructeurs_procedure.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class InstructeursProcedure < ApplicationRecord belongs_to :instructeur belongs_to :procedure From 95a3f179760dff0f126de9ee2605bac02e6fd433 Mon Sep 17 00:00:00 2001 From: benoitqueyron <72251526+Benoit-MINT@users.noreply.github.com> Date: Thu, 21 Nov 2024 17:54:52 +0100 Subject: [PATCH 6/7] test: instructeurs_procedure_spec --- spec/factories/instructeurs_procedure.rb | 8 +++ spec/models/instructeur_spec.rb | 63 ++++++++++++++++++++++++ 2 files changed, 71 insertions(+) create mode 100644 spec/factories/instructeurs_procedure.rb diff --git a/spec/factories/instructeurs_procedure.rb b/spec/factories/instructeurs_procedure.rb new file mode 100644 index 000000000..e872fea74 --- /dev/null +++ b/spec/factories/instructeurs_procedure.rb @@ -0,0 +1,8 @@ +# frozen_string_literal: true + +FactoryBot.define do + factory :instructeurs_procedure do + association :instructeur + association :procedure + end +end diff --git a/spec/models/instructeur_spec.rb b/spec/models/instructeur_spec.rb index 5ac18c0df..bf4603322 100644 --- a/spec/models/instructeur_spec.rb +++ b/spec/models/instructeur_spec.rb @@ -862,6 +862,69 @@ describe Instructeur, type: :model do end end + describe '.ensure_instructeur_procedures_for' do + let(:instructeur) { create(:instructeur) } + let!(:procedures) { create_list(:procedure, 5, published_at: Time.current) } + + context 'when some procedures are missing for the instructeur' do + before do + create(:instructeurs_procedure, instructeur: instructeur, procedure: procedures.first, position: 0) + end + + it 'creates missing instructeurs_procedures with correct positions' do + expect { + instructeur.ensure_instructeur_procedures_for(procedures) + }.to change { InstructeursProcedure.count }.by(4) + + instructeur_procedures = InstructeursProcedure.where(instructeur: instructeur) + expect(instructeur_procedures.pluck(:procedure_id)).to match_array(procedures.map(&:id)) + expect(instructeur_procedures.pluck(:position)).to eq([0, 1, 2, 3, 4]) + end + end + + context 'when all procedures already exist for the instructeur' do + before do + procedures.each_with_index do |procedure, index| + create(:instructeurs_procedure, instructeur: instructeur, procedure: procedure, position: index + 1) + end + end + + it 'does not create any new instructeurs_procedures' do + expect { + instructeur.ensure_instructeur_procedures_for(procedures) + }.not_to change { InstructeursProcedure.count } + end + end + end + + describe '.update_instructeur_procedures_positions' do + let(:instructeur) { create(:instructeur) } + let!(:procedures) { create_list(:procedure, 5, published_at: Time.current) } + + before do + procedures.each_with_index do |procedure, index| + create(:instructeurs_procedure, instructeur: instructeur, procedure: procedure, position: index + 1) + end + end + + it 'updates the positions of the specified instructeurs_procedures' do + instructeur.update_instructeur_procedures_positions(procedures.map(&:id)) + + updated_positions = InstructeursProcedure + .where(instructeur:) + .order(:procedure_id) + .pluck(:procedure_id, :position) + + expect(updated_positions).to match_array([ + [procedures[0].id, 4], + [procedures[1].id, 3], + [procedures[2].id, 2], + [procedures[3].id, 1], + [procedures[4].id, 0] + ]) + end + end + private def assign(procedure_to_assign, instructeur_assigne: instructeur) From e0f07e45e236abde9a7857c331d5d3b64a3c281d Mon Sep 17 00:00:00 2001 From: benoitqueyron <72251526+Benoit-MINT@users.noreply.github.com> Date: Fri, 6 Dec 2024 20:02:39 +0100 Subject: [PATCH 7/7] fix conflit schema.rb --- db/schema.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/db/schema.rb b/db/schema.rb index b76f5fc53..c669b9ca0 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema[7.0].define(version: 2024_11_19_142129) do +ActiveRecord::Schema[7.0].define(version: 2024_11_26_145420) do # These are extensions that must be enabled in order to support this database enable_extension "pg_buffercache" enable_extension "pg_stat_statements"