commit
53db2c95ab
47 changed files with 1872 additions and 633 deletions
2
Gemfile
2
Gemfile
|
@ -1,6 +1,7 @@
|
||||||
source 'https://rubygems.org'
|
source 'https://rubygems.org'
|
||||||
|
|
||||||
gem 'aasm'
|
gem 'aasm'
|
||||||
|
gem 'actiontext', github: 'kobaltz/actiontext', branch: 'archive', require: 'action_text'
|
||||||
gem 'active_link_to' # Automatically set a class on active links
|
gem 'active_link_to' # Automatically set a class on active links
|
||||||
gem 'active_model_serializers'
|
gem 'active_model_serializers'
|
||||||
gem 'activestorage-openstack', git: 'https://github.com/fredZen/activestorage-openstack.git', branch: 'frederic/fix_upload_signature'
|
gem 'activestorage-openstack', git: 'https://github.com/fredZen/activestorage-openstack.git', branch: 'frederic/fix_upload_signature'
|
||||||
|
@ -103,6 +104,7 @@ group :development, :test do
|
||||||
gem 'rspec-rails'
|
gem 'rspec-rails'
|
||||||
gem 'rspec_junit_formatter', require: false
|
gem 'rspec_junit_formatter', require: false
|
||||||
gem 'ruby-debug-ide', require: false
|
gem 'ruby-debug-ide', require: false
|
||||||
|
gem 'simple_xlsx_reader'
|
||||||
gem 'spring' # Spring speeds up development by keeping your application running in the background
|
gem 'spring' # Spring speeds up development by keeping your application running in the background
|
||||||
gem 'spring-commands-rspec'
|
gem 'spring-commands-rspec'
|
||||||
end
|
end
|
||||||
|
|
14
Gemfile.lock
14
Gemfile.lock
|
@ -1,3 +1,12 @@
|
||||||
|
GIT
|
||||||
|
remote: git://github.com/kobaltz/actiontext.git
|
||||||
|
revision: ef59c4ba99d1b7614dd47f5a294eef553224db88
|
||||||
|
branch: archive
|
||||||
|
specs:
|
||||||
|
actiontext (0.1.0)
|
||||||
|
nokogiri
|
||||||
|
rails (>= 5.2.0)
|
||||||
|
|
||||||
GIT
|
GIT
|
||||||
remote: https://github.com/fredZen/activestorage-openstack.git
|
remote: https://github.com/fredZen/activestorage-openstack.git
|
||||||
revision: c71d5107a51701eab9d9267dd0000e6c1cf3e39a
|
revision: c71d5107a51701eab9d9267dd0000e6c1cf3e39a
|
||||||
|
@ -576,6 +585,9 @@ GEM
|
||||||
simple_form (4.1.0)
|
simple_form (4.1.0)
|
||||||
actionpack (>= 5.0)
|
actionpack (>= 5.0)
|
||||||
activemodel (>= 5.0)
|
activemodel (>= 5.0)
|
||||||
|
simple_xlsx_reader (1.0.4)
|
||||||
|
nokogiri
|
||||||
|
rubyzip
|
||||||
sinatra (2.0.5)
|
sinatra (2.0.5)
|
||||||
mustermann (~> 1.0)
|
mustermann (~> 1.0)
|
||||||
rack (~> 2.0)
|
rack (~> 2.0)
|
||||||
|
@ -666,6 +678,7 @@ PLATFORMS
|
||||||
|
|
||||||
DEPENDENCIES
|
DEPENDENCIES
|
||||||
aasm
|
aasm
|
||||||
|
actiontext!
|
||||||
active_link_to
|
active_link_to
|
||||||
active_model_serializers
|
active_model_serializers
|
||||||
activestorage-openstack!
|
activestorage-openstack!
|
||||||
|
@ -747,6 +760,7 @@ DEPENDENCIES
|
||||||
sentry-raven
|
sentry-raven
|
||||||
shoulda-matchers
|
shoulda-matchers
|
||||||
simple_form
|
simple_form
|
||||||
|
simple_xlsx_reader
|
||||||
skylight
|
skylight
|
||||||
smart_listing
|
smart_listing
|
||||||
spreadsheet_architect
|
spreadsheet_architect
|
||||||
|
|
|
@ -63,7 +63,7 @@ En local, un utilisateur de test est créé automatiquement, avec les identifian
|
||||||
|
|
||||||
AutoArchiveProcedureJob.set(cron: "* * * * *").perform_later
|
AutoArchiveProcedureJob.set(cron: "* * * * *").perform_later
|
||||||
WeeklyOverviewJob.set(cron: "0 7 * * 1").perform_later
|
WeeklyOverviewJob.set(cron: "0 7 * * 1").perform_later
|
||||||
AutoReceiveDossiersForProcedureJob.set(cron: "* * * * *").perform_later(procedure_declaratoire_id, Dossier.states.fetch(:en_instruction))
|
DeclarativeProceduresJob.set(cron: "* * * * *").perform_later
|
||||||
UpdateAdministrateurUsageStatisticsJob.set(cron: "0 10 * * *").perform_later
|
UpdateAdministrateurUsageStatisticsJob.set(cron: "0 10 * * *").perform_later
|
||||||
FindDubiousProceduresJob.set(cron: "0 0 * * *").perform_later
|
FindDubiousProceduresJob.set(cron: "0 0 * * *").perform_later
|
||||||
Administrateurs::ActivateBeforeExpirationJob.set(cron: "0 8 * * *").perform_later
|
Administrateurs::ActivateBeforeExpirationJob.set(cron: "0 8 * * *").perform_later
|
||||||
|
|
36
app/assets/stylesheets/new_design/actiontext.scss
Normal file
36
app/assets/stylesheets/new_design/actiontext.scss
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
//
|
||||||
|
// Provides a drop-in pointer for the default Trix stylesheet that will format the toolbar and
|
||||||
|
// the trix-editor content (whether displayed or under editing). Feel free to incorporate this
|
||||||
|
// inclusion directly in any other asset bundle and remove this file.
|
||||||
|
//
|
||||||
|
// = require trix
|
||||||
|
|
||||||
|
// We need to override trix.css’s image gallery styles to accommodate the
|
||||||
|
// <action-text-attachment> element we wrap around attachments. Otherwise,
|
||||||
|
// images in galleries will be squished by the max-width: 33%; rule.
|
||||||
|
.trix-content {
|
||||||
|
.attachment-gallery {
|
||||||
|
> action-text-attachment,
|
||||||
|
> .attachment {
|
||||||
|
flex: 1 0 33%;
|
||||||
|
padding: 0 0.5em;
|
||||||
|
max-width: 33%;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.attachment-gallery--2,
|
||||||
|
&.attachment-gallery--4 {
|
||||||
|
> action-text-attachment,
|
||||||
|
> .attachment {
|
||||||
|
flex-basis: 50%;
|
||||||
|
max-width: 50%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
action-text-attachment {
|
||||||
|
.attachment {
|
||||||
|
padding: 0 !important;
|
||||||
|
max-width: 100% !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -183,7 +183,7 @@
|
||||||
color: $black;
|
color: $black;
|
||||||
padding: $default-padding;
|
padding: $default-padding;
|
||||||
|
|
||||||
h4 {
|
.title {
|
||||||
font-size: 24px;
|
font-size: 24px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -266,6 +266,10 @@
|
||||||
color: $black;
|
color: $black;
|
||||||
margin-bottom: $default-spacer;
|
margin-bottom: $default-spacer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&.with-top-border {
|
||||||
|
border-top: 1px solid $grey;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.dropdown-form {
|
.dropdown-form {
|
||||||
|
|
|
@ -93,6 +93,13 @@ module Gestionnaires
|
||||||
render partial: 'state_button_refresh', locals: { dossier: dossier }
|
render partial: 'state_button_refresh', locals: { dossier: dossier }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def repasser_en_instruction
|
||||||
|
flash.notice = "Le dossier #{dossier.id} a été repassé en instruction."
|
||||||
|
dossier.repasser_en_instruction!(current_gestionnaire)
|
||||||
|
|
||||||
|
render partial: 'state_button_refresh', locals: { dossier: dossier }
|
||||||
|
end
|
||||||
|
|
||||||
def terminer
|
def terminer
|
||||||
motivation = params[:dossier] && params[:dossier][:motivation]
|
motivation = params[:dossier] && params[:dossier][:motivation]
|
||||||
justificatif = params[:dossier] && params[:dossier][:justificatif_motivation]
|
justificatif = params[:dossier] && params[:dossier][:justificatif_motivation]
|
||||||
|
|
|
@ -168,7 +168,7 @@ module Gestionnaires
|
||||||
end
|
end
|
||||||
|
|
||||||
def download_dossiers
|
def download_dossiers
|
||||||
options = params.permit(:limit, :since, tables: [])
|
options = params.permit(:version, :limit, :since, tables: [])
|
||||||
|
|
||||||
respond_to do |format|
|
respond_to do |format|
|
||||||
format.csv do
|
format.csv do
|
||||||
|
|
|
@ -20,16 +20,6 @@ module Manager
|
||||||
# Custom actions
|
# Custom actions
|
||||||
#
|
#
|
||||||
|
|
||||||
def change_state_to_instruction
|
|
||||||
dossier = Dossier.find(params[:id])
|
|
||||||
dossier.update(state: Dossier.states.fetch(:en_instruction), processed_at: nil, motivation: nil)
|
|
||||||
dossier.attestation&.destroy
|
|
||||||
logger.info("Le dossier #{dossier.id} est repassé en instruction par #{current_administration.email}")
|
|
||||||
flash[:notice] = "Le dossier #{dossier.id} est repassé en instruction"
|
|
||||||
DossierMailer.notify_revert_to_instruction(dossier).deliver_later
|
|
||||||
redirect_to manager_dossier_path(dossier)
|
|
||||||
end
|
|
||||||
|
|
||||||
def hide
|
def hide
|
||||||
dossier = Dossier.find(params[:id])
|
dossier = Dossier.find(params[:id])
|
||||||
deleted_dossier = dossier.hide!(current_administration)
|
deleted_dossier = dossier.hide!(current_administration)
|
||||||
|
|
|
@ -5,7 +5,7 @@ module DossierHelper
|
||||||
elsif dossier.sans_suite?
|
elsif dossier.sans_suite?
|
||||||
'without-continuation'
|
'without-continuation'
|
||||||
elsif dossier.refuse?
|
elsif dossier.refuse?
|
||||||
'refuse'
|
'refused'
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -54,6 +54,13 @@ module ProcedureHelper
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def procedure_dossiers_download_path(procedure, format:, version:)
|
||||||
|
download_dossiers_gestionnaire_procedure_path(format: format,
|
||||||
|
procedure_id: procedure.id,
|
||||||
|
tables: [:etablissements],
|
||||||
|
version: version)
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
TOGGLES = {
|
TOGGLES = {
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import '../shared/polyfills';
|
import '../shared/polyfills';
|
||||||
import Turbolinks from 'turbolinks';
|
import Turbolinks from 'turbolinks';
|
||||||
import Rails from 'rails-ujs';
|
import Rails from '@rails/ujs';
|
||||||
import * as ActiveStorage from 'activestorage';
|
import * as ActiveStorage from '@rails/activestorage';
|
||||||
import jQuery from 'jquery';
|
import jQuery from 'jquery';
|
||||||
|
|
||||||
import '../shared/activestorage/ujs';
|
import '../shared/activestorage/ujs';
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
import '../shared/polyfills';
|
import '../shared/polyfills';
|
||||||
import Turbolinks from 'turbolinks';
|
import Turbolinks from 'turbolinks';
|
||||||
import Rails from 'rails-ujs';
|
import Rails from '@rails/ujs';
|
||||||
import * as ActiveStorage from 'activestorage';
|
import * as ActiveStorage from '@rails/activestorage';
|
||||||
|
import '@rails/actiontext';
|
||||||
import Chartkick from 'chartkick';
|
import Chartkick from 'chartkick';
|
||||||
import Highcharts from 'highcharts';
|
import Highcharts from 'highcharts';
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { DirectUpload } from 'activestorage';
|
import { DirectUpload } from '@rails/activestorage';
|
||||||
import ProgressBar from './progress-bar';
|
import ProgressBar from './progress-bar';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import Rails from 'rails-ujs';
|
import Rails from '@rails/ujs';
|
||||||
import jQuery from 'jquery';
|
import jQuery from 'jquery';
|
||||||
import { delegate } from '@utils';
|
import { delegate } from '@utils';
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import Rails from 'rails-ujs';
|
import Rails from '@rails/ujs';
|
||||||
import $ from 'jquery';
|
import $ from 'jquery';
|
||||||
import debounce from 'debounce';
|
import debounce from 'debounce';
|
||||||
|
|
||||||
|
|
7
app/jobs/declarative_procedures_job.rb
Normal file
7
app/jobs/declarative_procedures_job.rb
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
class DeclarativeProceduresJob < ApplicationJob
|
||||||
|
queue_as :cron
|
||||||
|
|
||||||
|
def perform(*args)
|
||||||
|
Procedure.declarative.find_each(&:process_dossiers!)
|
||||||
|
end
|
||||||
|
end
|
|
@ -37,6 +37,16 @@ class Avis < ApplicationRecord
|
||||||
Avis.find_by(id: avis_id)&.email == email
|
Avis.find_by(id: avis_id)&.email == email
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def spreadsheet_columns
|
||||||
|
[
|
||||||
|
['Dossier ID', dossier_id.to_s],
|
||||||
|
['Question / Introduction', :introduction],
|
||||||
|
['Réponse', :answer],
|
||||||
|
['Créé le', :created_at],
|
||||||
|
['Répondu le', :updated_at]
|
||||||
|
]
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def notify_gestionnaire
|
def notify_gestionnaire
|
||||||
|
|
|
@ -20,4 +20,25 @@ class Champs::RepetitionChamp < Champ
|
||||||
def search_terms
|
def search_terms
|
||||||
# The user cannot enter any information here so it doesn’t make much sense to search
|
# The user cannot enter any information here so it doesn’t make much sense to search
|
||||||
end
|
end
|
||||||
|
|
||||||
|
class Row < Hashie::Dash
|
||||||
|
property :index
|
||||||
|
property :dossier_id
|
||||||
|
property :champs
|
||||||
|
|
||||||
|
def spreadsheet_columns
|
||||||
|
[
|
||||||
|
['Dossier ID', :dossier_id],
|
||||||
|
['Ligne', :index]
|
||||||
|
] + exported_champs
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def exported_champs
|
||||||
|
champs.reject(&:exclude_from_export?).map do |champ|
|
||||||
|
[champ.libelle, champ.for_export]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -11,6 +11,15 @@ module MailTemplateConcern
|
||||||
replace_tags(body, dossier)
|
replace_tags(body, dossier)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def update_rich_body
|
||||||
|
self.rich_body = self.body
|
||||||
|
end
|
||||||
|
|
||||||
|
included do
|
||||||
|
has_rich_text :rich_body
|
||||||
|
before_save :update_rich_body
|
||||||
|
end
|
||||||
|
|
||||||
module ClassMethods
|
module ClassMethods
|
||||||
def default_for_procedure(procedure)
|
def default_for_procedure(procedure)
|
||||||
template_name = default_template_name_for_procedure(procedure)
|
template_name = default_template_name_for_procedure(procedure)
|
||||||
|
|
|
@ -40,6 +40,54 @@ class Dossier < ApplicationRecord
|
||||||
accepts_nested_attributes_for :champs
|
accepts_nested_attributes_for :champs
|
||||||
accepts_nested_attributes_for :champs_private
|
accepts_nested_attributes_for :champs_private
|
||||||
|
|
||||||
|
include AASM
|
||||||
|
|
||||||
|
aasm whiny_persistence: true, column: :state, enum: true do
|
||||||
|
state :brouillon, initial: true
|
||||||
|
state :en_construction
|
||||||
|
state :en_instruction
|
||||||
|
state :accepte
|
||||||
|
state :refuse
|
||||||
|
state :sans_suite
|
||||||
|
|
||||||
|
event :passer_en_construction, after: :after_passer_en_construction do
|
||||||
|
transitions from: :brouillon, to: :en_construction
|
||||||
|
end
|
||||||
|
|
||||||
|
event :passer_en_instruction, after: :after_passer_en_instruction do
|
||||||
|
transitions from: :en_construction, to: :en_instruction
|
||||||
|
end
|
||||||
|
|
||||||
|
event :passer_automatiquement_en_instruction, after: :after_passer_automatiquement_en_instruction do
|
||||||
|
transitions from: :en_construction, to: :en_instruction
|
||||||
|
end
|
||||||
|
|
||||||
|
event :repasser_en_construction, after: :after_repasser_en_construction do
|
||||||
|
transitions from: :en_instruction, to: :en_construction
|
||||||
|
end
|
||||||
|
|
||||||
|
event :accepter, after: :after_accepter do
|
||||||
|
transitions from: :en_instruction, to: :accepte
|
||||||
|
end
|
||||||
|
|
||||||
|
event :accepter_automatiquement, after: :after_accepter_automatiquement do
|
||||||
|
transitions from: :en_construction, to: :accepte
|
||||||
|
end
|
||||||
|
|
||||||
|
event :refuser, after: :after_refuser do
|
||||||
|
transitions from: :en_instruction, to: :refuse
|
||||||
|
end
|
||||||
|
|
||||||
|
event :classer_sans_suite, after: :after_classer_sans_suite do
|
||||||
|
transitions from: :en_instruction, to: :sans_suite
|
||||||
|
end
|
||||||
|
|
||||||
|
event :repasser_en_instruction, after: :after_repasser_en_instruction do
|
||||||
|
transitions from: :refuse, to: :en_instruction
|
||||||
|
transitions from: :sans_suite, to: :en_instruction
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
default_scope { where(hidden_at: nil) }
|
default_scope { where(hidden_at: nil) }
|
||||||
scope :state_brouillon, -> { where(state: states.fetch(:brouillon)) }
|
scope :state_brouillon, -> { where(state: states.fetch(:brouillon)) }
|
||||||
scope :state_not_brouillon, -> { where.not(state: states.fetch(:brouillon)) }
|
scope :state_not_brouillon, -> { where.not(state: states.fetch(:brouillon)) }
|
||||||
|
@ -59,7 +107,7 @@ class Dossier < ApplicationRecord
|
||||||
scope :en_construction, -> { not_archived.state_en_construction }
|
scope :en_construction, -> { not_archived.state_en_construction }
|
||||||
scope :en_instruction, -> { not_archived.state_en_instruction }
|
scope :en_instruction, -> { not_archived.state_en_instruction }
|
||||||
scope :termine, -> { not_archived.state_termine }
|
scope :termine, -> { not_archived.state_termine }
|
||||||
scope :downloadable_sorted, -> { state_not_brouillon.includes(:etablissement, :user, :individual, :followers_gestionnaires, champs: { etablissement: [], type_de_champ: :drop_down_list }, champs_private: { etablissement: [], type_de_champ: :drop_down_list }).order(en_construction_at: 'asc') }
|
scope :downloadable_sorted, -> { state_not_brouillon.includes(:etablissement, :user, :individual, :followers_gestionnaires, :avis, champs: { etablissement: [:champ], type_de_champ: :drop_down_list }, champs_private: { etablissement: [:champ], type_de_champ: :drop_down_list }).order(en_construction_at: 'asc') }
|
||||||
scope :en_cours, -> { not_archived.state_en_construction_ou_instruction }
|
scope :en_cours, -> { not_archived.state_en_construction_ou_instruction }
|
||||||
scope :without_followers, -> { left_outer_joins(:follows).where(follows: { id: nil }) }
|
scope :without_followers, -> { left_outer_joins(:follows).where(follows: { id: nil }) }
|
||||||
scope :followed_by, -> (gestionnaire) { joins(:follows).where(follows: { gestionnaire: gestionnaire }) }
|
scope :followed_by, -> (gestionnaire) { joins(:follows).where(follows: { gestionnaire: gestionnaire }) }
|
||||||
|
@ -282,55 +330,85 @@ class Dossier < ApplicationRecord
|
||||||
DossierMailer.notify_deletion_to_user(deleted_dossier, user.email).deliver_later
|
DossierMailer.notify_deletion_to_user(deleted_dossier, user.email).deliver_later
|
||||||
end
|
end
|
||||||
|
|
||||||
def passer_en_instruction!(gestionnaire)
|
def after_passer_en_instruction(gestionnaire)
|
||||||
en_instruction!
|
|
||||||
gestionnaire.follow(self)
|
gestionnaire.follow(self)
|
||||||
|
|
||||||
log_dossier_operation(gestionnaire, :passer_en_instruction)
|
log_dossier_operation(gestionnaire, :passer_en_instruction)
|
||||||
end
|
end
|
||||||
|
|
||||||
def passer_automatiquement_en_instruction!
|
def after_passer_automatiquement_en_instruction
|
||||||
en_instruction!
|
|
||||||
|
|
||||||
log_automatic_dossier_operation(:passer_en_instruction)
|
log_automatic_dossier_operation(:passer_en_instruction)
|
||||||
end
|
end
|
||||||
|
|
||||||
def repasser_en_construction!(gestionnaire)
|
def after_repasser_en_construction(gestionnaire)
|
||||||
self.en_instruction_at = nil
|
self.en_instruction_at = nil
|
||||||
en_construction!
|
|
||||||
|
|
||||||
|
save!
|
||||||
log_dossier_operation(gestionnaire, :repasser_en_construction)
|
log_dossier_operation(gestionnaire, :repasser_en_construction)
|
||||||
end
|
end
|
||||||
|
|
||||||
def accepter!(gestionnaire, motivation, justificatif = nil)
|
def after_repasser_en_instruction(gestionnaire)
|
||||||
|
self.processed_at = nil
|
||||||
|
self.motivation = nil
|
||||||
|
attestation&.destroy
|
||||||
|
|
||||||
|
save!
|
||||||
|
DossierMailer.notify_revert_to_instruction(self).deliver_later
|
||||||
|
log_dossier_operation(gestionnaire, :repasser_en_instruction)
|
||||||
|
end
|
||||||
|
|
||||||
|
def after_accepter(gestionnaire, motivation, justificatif = nil)
|
||||||
self.motivation = motivation
|
self.motivation = motivation
|
||||||
self.en_instruction_at ||= Time.zone.now
|
|
||||||
if justificatif
|
if justificatif
|
||||||
self.justificatif_motivation.attach(justificatif)
|
self.justificatif_motivation.attach(justificatif)
|
||||||
end
|
end
|
||||||
accepte!
|
|
||||||
|
|
||||||
if attestation.nil?
|
if attestation.nil?
|
||||||
update(attestation: build_attestation)
|
self.attestation = build_attestation
|
||||||
end
|
end
|
||||||
|
|
||||||
|
save!
|
||||||
NotificationMailer.send_closed_notification(self).deliver_later
|
NotificationMailer.send_closed_notification(self).deliver_later
|
||||||
log_dossier_operation(gestionnaire, :accepter, self)
|
log_dossier_operation(gestionnaire, :accepter, self)
|
||||||
end
|
end
|
||||||
|
|
||||||
def accepter_automatiquement!
|
def after_accepter_automatiquement
|
||||||
self.en_instruction_at ||= Time.zone.now
|
self.en_instruction_at ||= Time.zone.now
|
||||||
|
|
||||||
accepte!
|
|
||||||
|
|
||||||
if attestation.nil?
|
if attestation.nil?
|
||||||
update(attestation: build_attestation)
|
self.attestation = build_attestation
|
||||||
end
|
end
|
||||||
|
|
||||||
|
save!
|
||||||
NotificationMailer.send_closed_notification(self).deliver_later
|
NotificationMailer.send_closed_notification(self).deliver_later
|
||||||
log_automatic_dossier_operation(:accepter, self)
|
log_automatic_dossier_operation(:accepter, self)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def after_refuser(gestionnaire, motivation, justificatif = nil)
|
||||||
|
self.motivation = motivation
|
||||||
|
|
||||||
|
if justificatif
|
||||||
|
self.justificatif_motivation.attach(justificatif)
|
||||||
|
end
|
||||||
|
|
||||||
|
save!
|
||||||
|
NotificationMailer.send_refused_notification(self).deliver_later
|
||||||
|
log_dossier_operation(gestionnaire, :refuser, self)
|
||||||
|
end
|
||||||
|
|
||||||
|
def after_classer_sans_suite(gestionnaire, motivation, justificatif = nil)
|
||||||
|
self.motivation = motivation
|
||||||
|
|
||||||
|
if justificatif
|
||||||
|
self.justificatif_motivation.attach(justificatif)
|
||||||
|
end
|
||||||
|
|
||||||
|
save!
|
||||||
|
NotificationMailer.send_without_continuation_notification(self).deliver_later
|
||||||
|
log_dossier_operation(gestionnaire, :classer_sans_suite, self)
|
||||||
|
end
|
||||||
|
|
||||||
def hide!(administration)
|
def hide!(administration)
|
||||||
update(hidden_at: Time.zone.now)
|
update(hidden_at: Time.zone.now)
|
||||||
|
|
||||||
|
@ -338,30 +416,6 @@ class Dossier < ApplicationRecord
|
||||||
log_dossier_operation(administration, :supprimer, self)
|
log_dossier_operation(administration, :supprimer, self)
|
||||||
end
|
end
|
||||||
|
|
||||||
def refuser!(gestionnaire, motivation, justificatif = nil)
|
|
||||||
self.motivation = motivation
|
|
||||||
self.en_instruction_at ||= Time.zone.now
|
|
||||||
if justificatif
|
|
||||||
self.justificatif_motivation.attach(justificatif)
|
|
||||||
end
|
|
||||||
refuse!
|
|
||||||
|
|
||||||
NotificationMailer.send_refused_notification(self).deliver_later
|
|
||||||
log_dossier_operation(gestionnaire, :refuser, self)
|
|
||||||
end
|
|
||||||
|
|
||||||
def classer_sans_suite!(gestionnaire, motivation, justificatif = nil)
|
|
||||||
self.motivation = motivation
|
|
||||||
self.en_instruction_at ||= Time.zone.now
|
|
||||||
if justificatif
|
|
||||||
self.justificatif_motivation.attach(justificatif)
|
|
||||||
end
|
|
||||||
sans_suite!
|
|
||||||
|
|
||||||
NotificationMailer.send_without_continuation_notification(self).deliver_later
|
|
||||||
log_dossier_operation(gestionnaire, :classer_sans_suite, self)
|
|
||||||
end
|
|
||||||
|
|
||||||
def check_mandatory_champs
|
def check_mandatory_champs
|
||||||
(champs + champs.select(&:repetition?).flat_map(&:champs))
|
(champs + champs.select(&:repetition?).flat_map(&:champs))
|
||||||
.select(&:mandatory_and_blank?)
|
.select(&:mandatory_and_blank?)
|
||||||
|
@ -380,6 +434,37 @@ class Dossier < ApplicationRecord
|
||||||
log_dossier_operation(avis.claimant, :demander_un_avis, avis)
|
log_dossier_operation(avis.claimant, :demander_un_avis, avis)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def spreadsheet_columns
|
||||||
|
[
|
||||||
|
['ID', id.to_s],
|
||||||
|
['Email', user.email],
|
||||||
|
['Civilité', individual&.gender],
|
||||||
|
['Nom', individual&.nom],
|
||||||
|
['Prénom', individual&.prenom],
|
||||||
|
['Date de naissance', individual&.birthdate],
|
||||||
|
['Archivé', :archived],
|
||||||
|
['État du dossier', I18n.t(state, scope: [:activerecord, :attributes, :dossier, :state])],
|
||||||
|
['Dernière mise à jour le', :updated_at],
|
||||||
|
['Passé en construction le', :en_instruction_at],
|
||||||
|
['Passé en instruction le', :en_construction_at],
|
||||||
|
['Traité le', :processed_at],
|
||||||
|
['Motivation de la décision', :motivation],
|
||||||
|
['Instructeurs', followers_gestionnaires.map(&:email).join(' ')]
|
||||||
|
] + champs_for_export + annotations_for_export
|
||||||
|
end
|
||||||
|
|
||||||
|
def champs_for_export
|
||||||
|
champs.reject(&:exclude_from_export?).map do |champ|
|
||||||
|
[champ.libelle, champ.for_export]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def annotations_for_export
|
||||||
|
champs_private.reject(&:exclude_from_export?).map do |champ|
|
||||||
|
[champ.libelle, champ.for_export]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def log_dossier_operation(author, operation, subject = nil)
|
def log_dossier_operation(author, operation, subject = nil)
|
||||||
|
@ -411,13 +496,13 @@ class Dossier < ApplicationRecord
|
||||||
end
|
end
|
||||||
|
|
||||||
def send_dossier_received
|
def send_dossier_received
|
||||||
if saved_change_to_state? && en_instruction?
|
if saved_change_to_state? && en_instruction? && !procedure.declarative_accepte?
|
||||||
NotificationMailer.send_dossier_received(self).deliver_later
|
NotificationMailer.send_dossier_received(self).deliver_later
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def send_draft_notification_email
|
def send_draft_notification_email
|
||||||
if brouillon?
|
if brouillon? && !procedure.declarative?
|
||||||
DossierMailer.notify_new_draft(self).deliver_later
|
DossierMailer.notify_new_draft(self).deliver_later
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -2,6 +2,7 @@ class DossierOperationLog < ApplicationRecord
|
||||||
enum operation: {
|
enum operation: {
|
||||||
passer_en_instruction: 'passer_en_instruction',
|
passer_en_instruction: 'passer_en_instruction',
|
||||||
repasser_en_construction: 'repasser_en_construction',
|
repasser_en_construction: 'repasser_en_construction',
|
||||||
|
repasser_en_instruction: 'repasser_en_instruction',
|
||||||
accepter: 'accepter',
|
accepter: 'accepter',
|
||||||
refuser: 'refuser',
|
refuser: 'refuser',
|
||||||
classer_sans_suite: 'classer_sans_suite',
|
classer_sans_suite: 'classer_sans_suite',
|
||||||
|
|
|
@ -33,6 +33,43 @@ class Etablissement < ApplicationRecord
|
||||||
]
|
]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def spreadsheet_columns
|
||||||
|
[
|
||||||
|
['Dossier ID', :dossier_id_for_export],
|
||||||
|
['Champ', :libelle_for_export],
|
||||||
|
['Établissement SIRET', :siret],
|
||||||
|
['Établissement siège social', :siege_social],
|
||||||
|
['Établissement NAF', :naf],
|
||||||
|
['Établissement libellé NAF', :libelle_naf],
|
||||||
|
['Établissement Adresse', :adresse],
|
||||||
|
['Établissement numero voie', :numero_voie],
|
||||||
|
['Établissement type voie', :type_voie],
|
||||||
|
['Établissement nom voie', :nom_voie],
|
||||||
|
['Établissement complément adresse', :complement_adresse],
|
||||||
|
['Établissement code postal', :code_postal],
|
||||||
|
['Établissement localité', :localite],
|
||||||
|
['Établissement code INSEE localité', :code_insee_localite],
|
||||||
|
['Entreprise SIREN', :entreprise_siren],
|
||||||
|
['Entreprise capital social', :entreprise_capital_social],
|
||||||
|
['Entreprise numero TVA intracommunautaire', :entreprise_numero_tva_intracommunautaire],
|
||||||
|
['Entreprise forme juridique', :entreprise_forme_juridique],
|
||||||
|
['Entreprise forme juridique code', :entreprise_forme_juridique_code],
|
||||||
|
['Entreprise nom commercial', :entreprise_nom_commercial],
|
||||||
|
['Entreprise raison sociale', :entreprise_raison_sociale],
|
||||||
|
['Entreprise SIRET siège social', :entreprise_siret_siege_social],
|
||||||
|
['Entreprise code effectif entreprise', :entreprise_code_effectif_entreprise],
|
||||||
|
['Entreprise date de création', :entreprise_date_creation],
|
||||||
|
['Entreprise nom', :entreprise_nom],
|
||||||
|
['Entreprise prénom', :entreprise_prenom],
|
||||||
|
['Association RNA', :association_rna],
|
||||||
|
['Association titre', :association_titre],
|
||||||
|
['Association objet', :association_objet],
|
||||||
|
['Association date de création', :association_date_creation],
|
||||||
|
['Association date de déclaration', :association_date_declaration],
|
||||||
|
['Association date de publication', :association_date_publication]
|
||||||
|
]
|
||||||
|
end
|
||||||
|
|
||||||
def siren
|
def siren
|
||||||
entreprise_siren
|
entreprise_siren
|
||||||
end
|
end
|
||||||
|
@ -71,4 +108,18 @@ class Etablissement < ApplicationRecord
|
||||||
inline_adresse: inline_adresse
|
inline_adresse: inline_adresse
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def dossier_id_for_export
|
||||||
|
if dossier_id
|
||||||
|
dossier_id.to_s
|
||||||
|
elsif champ
|
||||||
|
champ.dossier_id.to_s
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def libelle_for_export
|
||||||
|
champ&.libelle
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -46,6 +46,7 @@ class Procedure < ApplicationRecord
|
||||||
scope :created_during, -> (range) { where(created_at: range) }
|
scope :created_during, -> (range) { where(created_at: range) }
|
||||||
scope :cloned_from_library, -> { where(cloned_from_library: true) }
|
scope :cloned_from_library, -> { where(cloned_from_library: true) }
|
||||||
scope :avec_lien, -> { where.not(path: nil) }
|
scope :avec_lien, -> { where.not(path: nil) }
|
||||||
|
scope :declarative, -> { where.not(declarative_with_state: nil) }
|
||||||
|
|
||||||
scope :for_api, -> {
|
scope :for_api, -> {
|
||||||
includes(
|
includes(
|
||||||
|
@ -57,6 +58,11 @@ class Procedure < ApplicationRecord
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum declarative_with_state: {
|
||||||
|
en_instruction: 'en_instruction',
|
||||||
|
accepte: 'accepte'
|
||||||
|
}
|
||||||
|
|
||||||
validates :libelle, presence: true, allow_blank: false, allow_nil: false
|
validates :libelle, presence: true, allow_blank: false, allow_nil: false
|
||||||
validates :description, presence: true, allow_blank: false, allow_nil: false
|
validates :description, presence: true, allow_blank: false, allow_nil: false
|
||||||
validates :administrateurs, presence: true
|
validates :administrateurs, presence: true
|
||||||
|
@ -141,6 +147,14 @@ class Procedure < ApplicationRecord
|
||||||
module_api_carto&.use_api_carto? && module_api_carto&.migrated?
|
module_api_carto&.use_api_carto? && module_api_carto&.migrated?
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def declarative?
|
||||||
|
declarative_with_state.present?
|
||||||
|
end
|
||||||
|
|
||||||
|
def declarative_accepte?
|
||||||
|
declarative_with_state == Procedure.declarative_with_states.fetch(:accepte)
|
||||||
|
end
|
||||||
|
|
||||||
# Warning: dossier after_save build_default_champs must be removed
|
# Warning: dossier after_save build_default_champs must be removed
|
||||||
# to save a dossier created from this method
|
# to save a dossier created from this method
|
||||||
def new_dossier
|
def new_dossier
|
||||||
|
@ -282,7 +296,13 @@ class Procedure < ApplicationRecord
|
||||||
end
|
end
|
||||||
|
|
||||||
def export(options = {})
|
def export(options = {})
|
||||||
ProcedureExportService.new(self, **options.to_h.symbolize_keys)
|
version = options.delete(:version)
|
||||||
|
if version == 'v2'
|
||||||
|
options.delete(:tables)
|
||||||
|
ProcedureExportV2Service.new(self, **options.to_h.symbolize_keys)
|
||||||
|
else
|
||||||
|
ProcedureExportService.new(self, **options.to_h.symbolize_keys)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def to_csv(options = {})
|
def to_csv(options = {})
|
||||||
|
@ -431,6 +451,19 @@ class Procedure < ApplicationRecord
|
||||||
update!(collection_attribute_name => attributes)
|
update!(collection_attribute_name => attributes)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def process_dossiers!
|
||||||
|
case declarative_with_state
|
||||||
|
when Procedure.declarative_with_states.fetch(:en_instruction)
|
||||||
|
dossiers
|
||||||
|
.state_en_construction
|
||||||
|
.find_each(&:passer_automatiquement_en_instruction!)
|
||||||
|
when Procedure.declarative_with_states.fetch(:accepte)
|
||||||
|
dossiers
|
||||||
|
.state_en_construction
|
||||||
|
.find_each(&:accepter_automatiquement!)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def move_type_de_champ_attributes(types_de_champ, type_de_champ, new_index)
|
def move_type_de_champ_attributes(types_de_champ, type_de_champ, new_index)
|
||||||
|
|
88
app/services/procedure_export_v2_service.rb
Normal file
88
app/services/procedure_export_v2_service.rb
Normal file
|
@ -0,0 +1,88 @@
|
||||||
|
class ProcedureExportV2Service
|
||||||
|
attr_reader :dossiers
|
||||||
|
|
||||||
|
def initialize(procedure, ids: nil, since: nil, limit: nil)
|
||||||
|
@procedure = procedure
|
||||||
|
@dossiers = procedure.dossiers.downloadable_sorted
|
||||||
|
if ids
|
||||||
|
@dossiers = @dossiers.where(id: ids)
|
||||||
|
end
|
||||||
|
if since
|
||||||
|
@dossiers = @dossiers.since(since)
|
||||||
|
end
|
||||||
|
if limit
|
||||||
|
@dossiers = @dossiers.limit(limit)
|
||||||
|
end
|
||||||
|
@tables = [:dossiers, :etablissements, :avis] + champs_repetables_options
|
||||||
|
end
|
||||||
|
|
||||||
|
def to_csv(table = :dossiers)
|
||||||
|
SpreadsheetArchitect.to_csv(options_for(table))
|
||||||
|
end
|
||||||
|
|
||||||
|
def to_xlsx
|
||||||
|
# We recursively build multi page spreadsheet
|
||||||
|
@tables.reduce(nil) do |package, table|
|
||||||
|
SpreadsheetArchitect.to_axlsx_package(options_for(table), package)
|
||||||
|
end.to_stream.read
|
||||||
|
end
|
||||||
|
|
||||||
|
def to_ods
|
||||||
|
# We recursively build multi page spreadsheet
|
||||||
|
@tables.reduce(nil) do |spreadsheet, table|
|
||||||
|
SpreadsheetArchitect.to_rodf_spreadsheet(options_for(table), spreadsheet)
|
||||||
|
end.bytes
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def etablissements
|
||||||
|
@etablissements ||= dossiers.flat_map do |dossier|
|
||||||
|
[dossier.champs, dossier.champs_private]
|
||||||
|
.flatten
|
||||||
|
.select { |champ| champ.is_a?(Champs::SiretChamp) }
|
||||||
|
end.map(&:etablissement).compact + dossiers.map(&:etablissement).compact
|
||||||
|
end
|
||||||
|
|
||||||
|
def avis
|
||||||
|
@avis ||= dossiers.flat_map(&:avis)
|
||||||
|
end
|
||||||
|
|
||||||
|
def champs_repetables
|
||||||
|
@champs_repetables ||= dossiers.flat_map do |dossier|
|
||||||
|
[dossier.champs, dossier.champs_private]
|
||||||
|
.flatten
|
||||||
|
.select { |champ| champ.is_a?(Champs::RepetitionChamp) }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def champs_repetables_options
|
||||||
|
champs_repetables.map do |champ|
|
||||||
|
[
|
||||||
|
champ.libelle,
|
||||||
|
champ.rows.each_with_index.map do |champs, index|
|
||||||
|
Champs::RepetitionChamp::Row.new(index: index + 1, dossier_id: champ.dossier_id.to_s, champs: champs)
|
||||||
|
end
|
||||||
|
]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
DEFAULT_STYLES = {
|
||||||
|
header_style: { background_color: "000000", color: "FFFFFF", font_size: 12, bold: true },
|
||||||
|
row_style: { background_color: nil, color: "000000", font_size: 12 }
|
||||||
|
}
|
||||||
|
|
||||||
|
def options_for(table)
|
||||||
|
case table
|
||||||
|
when :dossiers
|
||||||
|
{ instances: dossiers.to_a, sheet_name: 'Dossiers' }.merge(DEFAULT_STYLES)
|
||||||
|
when :etablissements
|
||||||
|
{ instances: etablissements.to_a, sheet_name: 'Etablissements' }.merge(DEFAULT_STYLES)
|
||||||
|
when :avis
|
||||||
|
{ instances: avis.to_a, sheet_name: 'Avis' }.merge(DEFAULT_STYLES)
|
||||||
|
when Array
|
||||||
|
# We have to truncate the label here as spreadsheets have a (30 char) limit on length.
|
||||||
|
{ instances: table.last, sheet_name: table.first.to_s.truncate(30) }.merge(DEFAULT_STYLES)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
14
app/views/active_storage/blobs/_blob.html.erb
Normal file
14
app/views/active_storage/blobs/_blob.html.erb
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
<figure class="attachment attachment--<%= blob.representable? ? "preview" : "file" %> attachment--<%= blob.filename.extension %>">
|
||||||
|
<% if blob.representable? %>
|
||||||
|
<%= image_tag blob.representation(resize_to_fit: local_assigns[:in_gallery] ? [ 800, 600 ] : [ 1024, 768 ]) %>
|
||||||
|
<% end %>
|
||||||
|
|
||||||
|
<figcaption class="attachment__caption">
|
||||||
|
<% if caption = blob.try(:caption) %>
|
||||||
|
<%= caption %>
|
||||||
|
<% else %>
|
||||||
|
<span class="attachment__name"><%= blob.filename %></span>
|
||||||
|
<span class="attachment__size"><%= number_to_human_size blob.byte_size %></span>
|
||||||
|
<% end %>
|
||||||
|
</figcaption>
|
||||||
|
</figure>
|
|
@ -58,14 +58,24 @@
|
||||||
= dossier_display_state(dossier, lower: true)
|
= dossier_display_state(dossier, lower: true)
|
||||||
.dropdown-content.fade-in-down.terminated
|
.dropdown-content.fade-in-down.terminated
|
||||||
- if dossier.motivation.present?
|
- if dossier.motivation.present?
|
||||||
%h4 Motivation
|
%h4.title Motivation
|
||||||
%p.dossier-motivation= dossier.motivation
|
%p.dossier-motivation= dossier.motivation
|
||||||
= render partial: 'users/dossiers/show/download_justificatif', locals: { dossier: dossier }
|
= render partial: 'users/dossiers/show/download_justificatif', locals: { dossier: dossier }
|
||||||
|
|
||||||
- if dossier.attestation.present?
|
- if dossier.attestation.present?
|
||||||
%h4 Attestation
|
%h4.title Attestation
|
||||||
%p.attestation L'acceptation du dossier a envoyé automatiquement une attestation au demandeur
|
%p.attestation L'acceptation du dossier a envoyé automatiquement une attestation au demandeur
|
||||||
= link_to "Voir l'attestation", attestation_gestionnaire_dossier_path(dossier.procedure, dossier), target: '_blank', rel: 'noopener', class: 'button'
|
= link_to "Voir l'attestation", attestation_gestionnaire_dossier_path(dossier.procedure, dossier), target: '_blank', rel: 'noopener', class: 'button'
|
||||||
|
|
||||||
|
|
||||||
|
- if dossier.refuse? || dossier.sans_suite?
|
||||||
|
%ul.dropdown-items.with-top-border
|
||||||
|
%li
|
||||||
|
= link_to repasser_en_instruction_gestionnaire_dossier_path(dossier.procedure, dossier), method: :post, data: { remote:true, confirm: "Voulez vous remettre le dossier #{dossier.id} en instruction ?" } do
|
||||||
|
%span.icon.in-progress
|
||||||
|
.dropdown-description
|
||||||
|
%h4 Repasser en instruction
|
||||||
|
L’usager sera notifié que son dossier est réexaminé.
|
||||||
- else
|
- else
|
||||||
%span.label{ class: button_or_label_class(dossier) }
|
%span.label{ class: button_or_label_class(dossier) }
|
||||||
= dossier_display_state(dossier, lower: true)
|
= dossier_display_state(dossier, lower: true)
|
||||||
|
|
|
@ -2,11 +2,23 @@
|
||||||
%span.dropdown
|
%span.dropdown
|
||||||
%button.button.dropdown-button
|
%button.button.dropdown-button
|
||||||
Télécharger tous les dossiers
|
Télécharger tous les dossiers
|
||||||
.dropdown-content.fade-in-down
|
- old_format_limit_date = Date.parse("Oct 31 2019")
|
||||||
|
- export_v1_enabled = old_format_limit_date > Time.zone.today
|
||||||
|
- export_v2_enabled = Flipflop.procedure_export_v2_enabled? || !export_v1_enabled
|
||||||
|
- old_format_message = export_v1_enabled && export_v2_enabled ? "(ancien format, jusqu’au #{old_format_limit_date.strftime('%d/%m/%Y')})" : ''
|
||||||
|
.dropdown-content.fade-in-down{ style: export_v1_enabled && export_v2_enabled ? 'width: 330px' : '' }
|
||||||
%ul.dropdown-items
|
%ul.dropdown-items
|
||||||
%li
|
- if export_v2_enabled
|
||||||
= link_to "Au format .csv", download_dossiers_gestionnaire_procedure_path(format: :csv, procedure_id: procedure.id), target: "_blank", rel: "noopener"
|
%li
|
||||||
%li
|
= link_to "Au format .xlsx", procedure_dossiers_download_path(procedure, format: :xlsx, version: 'v2'), target: "_blank", rel: "noopener"
|
||||||
= link_to "Au format .xlsx", download_dossiers_gestionnaire_procedure_path(format: :xlsx, procedure_id: procedure.id, tables: [:etablissements]), target: "_blank", rel: "noopener"
|
%li
|
||||||
%li
|
= link_to "Au format .ods", procedure_dossiers_download_path(procedure, format: :ods, version: 'v2'), target: "_blank", rel: "noopener"
|
||||||
= link_to "Au format .ods", download_dossiers_gestionnaire_procedure_path(format: :ods, procedure_id: procedure.id, tables: [:etablissements]), target: "_blank", rel: "noopener"
|
%li
|
||||||
|
= link_to "Au format .csv", procedure_dossiers_download_path(procedure, format: :csv, version: 'v2'), target: "_blank", rel: "noopener"
|
||||||
|
- if export_v1_enabled
|
||||||
|
%li
|
||||||
|
= link_to "Au format .xlsx #{old_format_message}", procedure_dossiers_download_path(procedure, format: :xlsx, version: 'v1'), target: "_blank", rel: "noopener"
|
||||||
|
%li
|
||||||
|
= link_to "Au format .ods #{old_format_message}", procedure_dossiers_download_path(procedure, format: :ods, version: 'v1'), target: "_blank", rel: "noopener"
|
||||||
|
%li
|
||||||
|
= link_to "Au format .csv #{old_format_message}", procedure_dossiers_download_path(procedure, format: :csv, version: 'v1'), target: "_blank", rel: "noopener"
|
||||||
|
|
|
@ -28,9 +28,6 @@ as well as a link to its edit page.
|
||||||
</h1>
|
</h1>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<% if dossier.termine? %>
|
|
||||||
<%= link_to 'Repasser en instruction', change_state_to_instruction_manager_dossier_path(dossier), method: :post, class: 'button', data: { confirm: "Repasser en instruction ?" } %>
|
|
||||||
<% end %>
|
|
||||||
<% if dossier.hidden_at.nil? %>
|
<% if dossier.hidden_at.nil? %>
|
||||||
<%= link_to 'Supprimer le dossier', hide_manager_dossier_path(dossier), method: :post, class: 'button', data: { confirm: "Confirmez vous la suppression du dossier ?" } %>
|
<%= link_to 'Supprimer le dossier', hide_manager_dossier_path(dossier), method: :post, class: 'button', data: { confirm: "Confirmez vous la suppression du dossier ?" } %>
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|
|
@ -26,8 +26,8 @@
|
||||||
%h1.role-panel-title Vous souhaitez effectuer une demande auprès d'une administration ?
|
%h1.role-panel-title Vous souhaitez effectuer une demande auprès d'une administration ?
|
||||||
%p.role-panel-explanation Réalisez vos demandes en toute simplicité et retrouvez vos dossiers en ligne
|
%p.role-panel-explanation Réalisez vos demandes en toute simplicité et retrouvez vos dossiers en ligne
|
||||||
|
|
||||||
= link_to "Voir les démarches disponibles",
|
= link_to "Comment trouver ma démarche ?",
|
||||||
LISTE_DES_DEMARCHES_URL,
|
COMMENT_TROUVER_MA_DEMARCHE_URL,
|
||||||
target: "_blank",
|
target: "_blank",
|
||||||
rel: "noopener noreferrer",
|
rel: "noopener noreferrer",
|
||||||
class: "role-panel-button-primary"
|
class: "role-panel-button-primary"
|
||||||
|
|
|
@ -30,6 +30,7 @@ module.exports = function(api) {
|
||||||
{
|
{
|
||||||
forceAllTransforms: true,
|
forceAllTransforms: true,
|
||||||
useBuiltIns: 'entry',
|
useBuiltIns: 'entry',
|
||||||
|
corejs: 2,
|
||||||
modules: false,
|
modules: false,
|
||||||
exclude: ['transform-typeof-symbol']
|
exclude: ['transform-typeof-symbol']
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,6 +16,7 @@ Flipflop.configure do
|
||||||
feature :web_hook
|
feature :web_hook
|
||||||
feature :enable_email_login_token
|
feature :enable_email_login_token
|
||||||
|
|
||||||
|
feature :procedure_export_v2_enabled
|
||||||
feature :operation_log_serialize_subject
|
feature :operation_log_serialize_subject
|
||||||
|
|
||||||
group :development do
|
group :development do
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
Rails.application.config.assets.version = '1.0'
|
Rails.application.config.assets.version = '1.0'
|
||||||
|
|
||||||
# Add additional assets to the asset load path
|
# Add additional assets to the asset load path
|
||||||
# Rails.application.config.assets.paths << Emoji.images_path
|
Rails.application.config.assets.paths << Rails.root.join('node_modules', 'trix', 'dist')
|
||||||
|
|
||||||
# Precompile additional assets.
|
# Precompile additional assets.
|
||||||
# application.js, application.css, and all non-JS/CSS in app/assets folder are already added.
|
# application.js, application.css, and all non-JS/CSS in app/assets folder are already added.
|
||||||
|
|
|
@ -25,5 +25,6 @@ API_DOC_URL = [DOC_URL, "pour-aller-plus-loin", "api"].join("/")
|
||||||
WEBHOOK_DOC_URL = [DOC_URL, "pour-aller-plus-loin", "webhook"].join("/")
|
WEBHOOK_DOC_URL = [DOC_URL, "pour-aller-plus-loin", "webhook"].join("/")
|
||||||
FAQ_URL = "https://faq.demarches-simplifiees.fr"
|
FAQ_URL = "https://faq.demarches-simplifiees.fr"
|
||||||
FAQ_ADMIN_URL = "https://faq.demarches-simplifiees.fr/collection/1-administrateur"
|
FAQ_ADMIN_URL = "https://faq.demarches-simplifiees.fr/collection/1-administrateur"
|
||||||
|
COMMENT_TROUVER_MA_DEMARCHE_URL = [FAQ_URL, "article", "59-comment-trouver-ma-demarche"].join("/")
|
||||||
STATUS_PAGE_URL = "https://status.demarches-simplifiees.fr"
|
STATUS_PAGE_URL = "https://status.demarches-simplifiees.fr"
|
||||||
MATOMO_IFRAME_URL = "https://stats.data.gouv.fr/index.php?module=CoreAdminHome&action=optOut&language=fr&&fontColor=333333&fontSize=16px&fontFamily=Muli"
|
MATOMO_IFRAME_URL = "https://stats.data.gouv.fr/index.php?module=CoreAdminHome&action=optOut&language=fr&&fontColor=333333&fontSize=16px&fontFamily=Muli"
|
||||||
|
|
|
@ -15,7 +15,6 @@ Rails.application.routes.draw do
|
||||||
end
|
end
|
||||||
|
|
||||||
resources :dossiers, only: [:index, :show] do
|
resources :dossiers, only: [:index, :show] do
|
||||||
post 'change_state_to_instruction', on: :member
|
|
||||||
post 'hide', on: :member
|
post 'hide', on: :member
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -325,6 +324,7 @@ Rails.application.routes.draw do
|
||||||
post 'commentaire' => 'dossiers#create_commentaire'
|
post 'commentaire' => 'dossiers#create_commentaire'
|
||||||
post 'passer-en-instruction' => 'dossiers#passer_en_instruction'
|
post 'passer-en-instruction' => 'dossiers#passer_en_instruction'
|
||||||
post 'repasser-en-construction' => 'dossiers#repasser_en_construction'
|
post 'repasser-en-construction' => 'dossiers#repasser_en_construction'
|
||||||
|
post 'repasser-en-instruction' => 'dossiers#repasser_en_instruction'
|
||||||
post 'terminer'
|
post 'terminer'
|
||||||
post 'send-to-instructeurs' => 'dossiers#send_to_instructeurs'
|
post 'send-to-instructeurs' => 'dossiers#send_to_instructeurs'
|
||||||
post 'avis' => 'dossiers#create_avis'
|
post 'avis' => 'dossiers#create_avis'
|
||||||
|
|
|
@ -0,0 +1,15 @@
|
||||||
|
# This migration comes from action_text (originally 201805281641)
|
||||||
|
class CreateActionTextTables < ActiveRecord::Migration[5.2]
|
||||||
|
def change
|
||||||
|
create_table :action_text_rich_texts do |t|
|
||||||
|
t.string :name, null: false
|
||||||
|
t.text :body, limit: 16777215
|
||||||
|
t.references :record, null: false, polymorphic: true, index: false
|
||||||
|
|
||||||
|
t.datetime :created_at, null: false
|
||||||
|
t.datetime :updated_at, null: false
|
||||||
|
|
||||||
|
t.index [:record_type, :record_id, :name], name: "index_action_text_rich_texts_uniqueness", unique: true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,6 @@
|
||||||
|
class AddDeclarativeWithStateToProcedures < ActiveRecord::Migration[5.2]
|
||||||
|
def change
|
||||||
|
add_column :procedures, :declarative_with_state, :string
|
||||||
|
add_index :procedures, :declarative_with_state
|
||||||
|
end
|
||||||
|
end
|
12
db/schema.rb
12
db/schema.rb
|
@ -16,6 +16,16 @@ ActiveRecord::Schema.define(version: 2019_06_27_132911) do
|
||||||
enable_extension "plpgsql"
|
enable_extension "plpgsql"
|
||||||
enable_extension "unaccent"
|
enable_extension "unaccent"
|
||||||
|
|
||||||
|
create_table "action_text_rich_texts", force: :cascade do |t|
|
||||||
|
t.string "name", null: false
|
||||||
|
t.text "body"
|
||||||
|
t.string "record_type", null: false
|
||||||
|
t.bigint "record_id", null: false
|
||||||
|
t.datetime "created_at", null: false
|
||||||
|
t.datetime "updated_at", null: false
|
||||||
|
t.index ["record_type", "record_id", "name"], name: "index_action_text_rich_texts_uniqueness", unique: true
|
||||||
|
end
|
||||||
|
|
||||||
create_table "active_storage_attachments", force: :cascade do |t|
|
create_table "active_storage_attachments", force: :cascade do |t|
|
||||||
t.string "name", null: false
|
t.string "name", null: false
|
||||||
t.string "record_type", null: false
|
t.string "record_type", null: false
|
||||||
|
@ -492,6 +502,8 @@ ActiveRecord::Schema.define(version: 2019_06_27_132911) do
|
||||||
t.boolean "durees_conservation_required", default: true
|
t.boolean "durees_conservation_required", default: true
|
||||||
t.string "path"
|
t.string "path"
|
||||||
t.boolean "expects_multiple_submissions", default: false, null: false
|
t.boolean "expects_multiple_submissions", default: false, null: false
|
||||||
|
t.string "declarative_with_state"
|
||||||
|
t.index ["declarative_with_state"], name: "index_procedures_on_declarative_with_state"
|
||||||
t.index ["hidden_at"], name: "index_procedures_on_hidden_at"
|
t.index ["hidden_at"], name: "index_procedures_on_hidden_at"
|
||||||
t.index ["parent_procedure_id"], name: "index_procedures_on_parent_procedure_id"
|
t.index ["parent_procedure_id"], name: "index_procedures_on_parent_procedure_id"
|
||||||
t.index ["service_id"], name: "index_procedures_on_service_id"
|
t.index ["service_id"], name: "index_procedures_on_service_id"
|
||||||
|
|
|
@ -0,0 +1,26 @@
|
||||||
|
namespace :after_party do
|
||||||
|
desc 'Deployment task: migrate_mail_body_to_actiontext'
|
||||||
|
task migrate_mail_body_to_actiontext: :environment do
|
||||||
|
puts "Running deploy task 'migrate_mail_body_to_actiontext'"
|
||||||
|
|
||||||
|
# Put your task implementation HERE.
|
||||||
|
|
||||||
|
[Mails::InitiatedMail, Mails::ReceivedMail, Mails::ClosedMail, Mails::WithoutContinuationMail, Mails::RefusedMail].each do |mt_class|
|
||||||
|
progress = ProgressReport.new(mt_class.all.count)
|
||||||
|
|
||||||
|
mt_class.all.each do |mt|
|
||||||
|
if mt.body.present?
|
||||||
|
mt.rich_body = mt.body
|
||||||
|
mt.save
|
||||||
|
end
|
||||||
|
progress.inc
|
||||||
|
end
|
||||||
|
|
||||||
|
progress.finish
|
||||||
|
end
|
||||||
|
|
||||||
|
# Update task as completed. If you remove the line below, the task will
|
||||||
|
# run with every deploy (or every time you call after_party:run).
|
||||||
|
AfterParty::TaskRecord.create version: '20190410131747'
|
||||||
|
end # task :migrate_mail_body_to_actiontext
|
||||||
|
end # namespace :after_party
|
|
@ -0,0 +1,22 @@
|
||||||
|
namespace :after_party do
|
||||||
|
desc 'Deployment task: set_declarative_procedures'
|
||||||
|
task set_declarative_procedures: :environment do
|
||||||
|
puts "Running deploy task 'set_declarative_procedures'"
|
||||||
|
|
||||||
|
Delayed::Job.where.not(cron: nil).find_each do |job|
|
||||||
|
job_data = YAML.load_dj(job.handler).job_data
|
||||||
|
|
||||||
|
if job_data['job_class'] == 'AutoReceiveDossiersForProcedureJob'
|
||||||
|
procedure_id, state = job_data['arguments']
|
||||||
|
procedure = Procedure.find(procedure_id)
|
||||||
|
procedure.declarative_with_state = state
|
||||||
|
procedure.save!
|
||||||
|
job.delete
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Update task as completed. If you remove the line below, the task will
|
||||||
|
# run with every deploy (or every time you call after_party:run).
|
||||||
|
AfterParty::TaskRecord.create version: '20190523122639'
|
||||||
|
end
|
||||||
|
end
|
|
@ -16,6 +16,6 @@ namespace :after_party do
|
||||||
|
|
||||||
# Update task as completed. If you remove the line below, the task will
|
# Update task as completed. If you remove the line below, the task will
|
||||||
# run with every deploy (or every time you call after_party:run).
|
# run with every deploy (or every time you call after_party:run).
|
||||||
AfterParty::TaskRecord.create version: '20190521131030'
|
AfterParty::TaskRecord.create version: '20190701131030'
|
||||||
end
|
end
|
||||||
end
|
end
|
28
package.json
28
package.json
|
@ -1,26 +1,28 @@
|
||||||
{
|
{
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/preset-react": "^7.0.0",
|
"@babel/preset-react": "^7.0.0",
|
||||||
"@fortawesome/fontawesome-svg-core": "^1.2.18",
|
"@fortawesome/fontawesome-svg-core": "^1.2.19",
|
||||||
"@fortawesome/free-solid-svg-icons": "^5.8.2",
|
"@fortawesome/free-solid-svg-icons": "^5.9.0",
|
||||||
"@fortawesome/react-fontawesome": "^0.1.4",
|
"@fortawesome/react-fontawesome": "^0.1.4",
|
||||||
"@rails/webpacker": "4.0.2",
|
"@rails/actiontext": "^6.0.0-alpha",
|
||||||
"@sentry/browser": "^5.2.1",
|
"@rails/activestorage": "^6.0.0-alpha",
|
||||||
|
"@rails/ujs": "^6.0.0-alpha",
|
||||||
|
"@rails/webpacker": "4.0.7",
|
||||||
|
"@sentry/browser": "^5.4.3",
|
||||||
"@turf/area": "^6.0.1",
|
"@turf/area": "^6.0.1",
|
||||||
"activestorage": "^5.2.3",
|
|
||||||
"autocomplete.js": "^0.36.0",
|
"autocomplete.js": "^0.36.0",
|
||||||
"babel-plugin-macros": "^2.5.1",
|
"babel-plugin-macros": "^2.6.1",
|
||||||
"babel-plugin-transform-react-remove-prop-types": "^0.4.24",
|
"babel-plugin-transform-react-remove-prop-types": "^0.4.24",
|
||||||
"chartkick": "^3.0.2",
|
"chartkick": "^3.0.2",
|
||||||
|
"core-js": "^2.0.0",
|
||||||
"debounce": "^1.2.0",
|
"debounce": "^1.2.0",
|
||||||
"dom4": "^2.1.4",
|
"dom4": "^2.1.5",
|
||||||
"highcharts": "^6.1.2",
|
"highcharts": "^6.1.2",
|
||||||
"intersection-observer": "^0.7.0",
|
"intersection-observer": "^0.7.0",
|
||||||
"jquery": "^3.4.1",
|
"jquery": "^3.4.1",
|
||||||
"leaflet": "^1.4.0",
|
"leaflet": "^1.4.0",
|
||||||
"leaflet-freedraw": "^2.10.0",
|
"leaflet-freedraw": "^2.10.0",
|
||||||
"prop-types": "^15.7.2",
|
"prop-types": "^15.7.2",
|
||||||
"rails-ujs": "^5.2.3",
|
|
||||||
"ramda": "=0.24.1",
|
"ramda": "=0.24.1",
|
||||||
"react": "^16.8.6",
|
"react": "^16.8.6",
|
||||||
"react-dom": "^16.8.6",
|
"react-dom": "^16.8.6",
|
||||||
|
@ -32,15 +34,15 @@
|
||||||
"turbolinks": "^5.2.0"
|
"turbolinks": "^5.2.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"babel-eslint": "^10.0.1",
|
"babel-eslint": "^10.0.2",
|
||||||
"eclint": "^2.8.1",
|
"eclint": "^2.8.1",
|
||||||
"eslint": "^5.16.0",
|
"eslint": "^5.16.0",
|
||||||
"eslint-config-prettier": "^4.2.0",
|
"eslint-config-prettier": "^4.2.0",
|
||||||
"eslint-plugin-prettier": "^3.1.0",
|
"eslint-plugin-prettier": "^3.1.0",
|
||||||
"eslint-plugin-react": "^7.13.0",
|
"eslint-plugin-react": "^7.14.2",
|
||||||
"eslint-plugin-react-hooks": "^1.6.0",
|
"eslint-plugin-react-hooks": "^1.6.1",
|
||||||
"prettier": "^1.17.1",
|
"prettier": "^1.18.2",
|
||||||
"webpack-dev-server": "^3.3.1"
|
"webpack-dev-server": "^3.7.2"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"lint:ec": "eclint check $({ git ls-files ; find vendor -type f ; echo 'db/schema.rb' ; } | sort | uniq -u)",
|
"lint:ec": "eclint check $({ git ls-files ; find vendor -type f ; echo 'db/schema.rb' ; } | sort | uniq -u)",
|
||||||
|
|
82
spec/jobs/declarative_procedures_job_spec.rb
Normal file
82
spec/jobs/declarative_procedures_job_spec.rb
Normal file
|
@ -0,0 +1,82 @@
|
||||||
|
require 'rails_helper'
|
||||||
|
|
||||||
|
RSpec.describe DeclarativeProceduresJob, type: :job do
|
||||||
|
describe "perform" do
|
||||||
|
let(:date) { Time.utc(2017, 9, 1, 10, 5, 0) }
|
||||||
|
let(:instruction_date) { date + 120 }
|
||||||
|
|
||||||
|
let(:state) { nil }
|
||||||
|
let(:procedure) { create(:procedure, :with_gestionnaire, declarative_with_state: state) }
|
||||||
|
let(:nouveau_dossier1) { create(:dossier, :en_construction, procedure: procedure) }
|
||||||
|
let(:nouveau_dossier2) { create(:dossier, :en_construction, procedure: procedure) }
|
||||||
|
let(:dossier_recu) { create(:dossier, :en_instruction, procedure: procedure) }
|
||||||
|
let(:dossier_brouillon) { create(:dossier, procedure: procedure) }
|
||||||
|
|
||||||
|
before do
|
||||||
|
Timecop.freeze(date)
|
||||||
|
dossiers = [
|
||||||
|
nouveau_dossier1,
|
||||||
|
nouveau_dossier2,
|
||||||
|
dossier_recu,
|
||||||
|
dossier_brouillon
|
||||||
|
]
|
||||||
|
|
||||||
|
create(:attestation_template, procedure: procedure)
|
||||||
|
DeclarativeProceduresJob.new.perform
|
||||||
|
|
||||||
|
dossiers.each(&:reload)
|
||||||
|
end
|
||||||
|
|
||||||
|
after { Timecop.return }
|
||||||
|
|
||||||
|
context "with some dossiers" do
|
||||||
|
context "en_construction" do
|
||||||
|
let(:state) { Dossier.states.fetch(:en_instruction) }
|
||||||
|
let(:last_operation) { nouveau_dossier1.dossier_operation_logs.last }
|
||||||
|
|
||||||
|
it {
|
||||||
|
expect(nouveau_dossier1.en_instruction?).to be true
|
||||||
|
expect(nouveau_dossier1.en_instruction_at).to eq(date)
|
||||||
|
expect(last_operation.operation).to eq('passer_en_instruction')
|
||||||
|
expect(last_operation.automatic_operation?).to be_truthy
|
||||||
|
|
||||||
|
expect(nouveau_dossier2.en_instruction?).to be true
|
||||||
|
expect(nouveau_dossier2.en_instruction_at).to eq(date)
|
||||||
|
|
||||||
|
expect(dossier_recu.en_instruction?).to be true
|
||||||
|
expect(dossier_recu.en_instruction_at).to eq(instruction_date)
|
||||||
|
|
||||||
|
expect(dossier_brouillon.brouillon?).to be true
|
||||||
|
expect(dossier_brouillon.en_instruction_at).to eq(nil)
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
context "accepte" do
|
||||||
|
let(:state) { Dossier.states.fetch(:accepte) }
|
||||||
|
let(:last_operation) { nouveau_dossier1.dossier_operation_logs.last }
|
||||||
|
|
||||||
|
it {
|
||||||
|
expect(nouveau_dossier1.accepte?).to be true
|
||||||
|
expect(nouveau_dossier1.en_instruction_at).to eq(date)
|
||||||
|
expect(nouveau_dossier1.processed_at).to eq(date)
|
||||||
|
expect(nouveau_dossier1.attestation).to be_present
|
||||||
|
expect(last_operation.operation).to eq('accepter')
|
||||||
|
expect(last_operation.automatic_operation?).to be_truthy
|
||||||
|
|
||||||
|
expect(nouveau_dossier2.accepte?).to be true
|
||||||
|
expect(nouveau_dossier2.en_instruction_at).to eq(date)
|
||||||
|
expect(nouveau_dossier2.processed_at).to eq(date)
|
||||||
|
expect(nouveau_dossier2.attestation).to be_present
|
||||||
|
|
||||||
|
expect(dossier_recu.en_instruction?).to be true
|
||||||
|
expect(dossier_recu.en_instruction_at).to eq(instruction_date)
|
||||||
|
expect(dossier_recu.processed_at).to eq(nil)
|
||||||
|
|
||||||
|
expect(dossier_brouillon.brouillon?).to be true
|
||||||
|
expect(dossier_brouillon.en_instruction_at).to eq(nil)
|
||||||
|
expect(dossier_brouillon.processed_at).to eq(nil)
|
||||||
|
}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,24 @@
|
||||||
|
describe '20190410131747_migrate_mail_body_to_actiontext.rake' do
|
||||||
|
let(:rake_task) { Rake::Task['after_party:migrate_mail_body_to_actiontext'] }
|
||||||
|
|
||||||
|
let!(:closed_mail) { create(:closed_mail, body: body) }
|
||||||
|
|
||||||
|
before do
|
||||||
|
rake_task.invoke
|
||||||
|
closed_mail.reload
|
||||||
|
end
|
||||||
|
|
||||||
|
after { rake_task.reenable }
|
||||||
|
|
||||||
|
context 'with a plain text body' do
|
||||||
|
let(:body) { "Test de body" }
|
||||||
|
|
||||||
|
it { expect(closed_mail.rich_body.to_plain_text).to eq(closed_mail.body) }
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'with a html text body' do
|
||||||
|
let(:body) { "Test de body<br>" }
|
||||||
|
|
||||||
|
it { expect(closed_mail.rich_body.to_s.squish).to eq("<div class=\"trix-content\"> #{closed_mail.body} </div>".squish) }
|
||||||
|
end
|
||||||
|
end
|
|
@ -113,4 +113,10 @@ describe MailTemplateConcern do
|
||||||
expect(initiated_mail.body_for_dossier(dossier2)).to eq("n #{dossier2.id}")
|
expect(initiated_mail.body_for_dossier(dossier2)).to eq("n #{dossier2.id}")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe '#update_rich_body' do
|
||||||
|
before { initiated_mail.update(body: "Voici le corps du mail") }
|
||||||
|
|
||||||
|
it { expect(initiated_mail.rich_body.to_plain_text).to eq(initiated_mail.body) }
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -794,7 +794,7 @@ describe Dossier do
|
||||||
end
|
end
|
||||||
|
|
||||||
describe '#accepter!' do
|
describe '#accepter!' do
|
||||||
let(:dossier) { create(:dossier) }
|
let(:dossier) { create(:dossier, :en_instruction) }
|
||||||
let(:last_operation) { dossier.dossier_operation_logs.last }
|
let(:last_operation) { dossier.dossier_operation_logs.last }
|
||||||
let(:operation_serialized) { JSON.parse(last_operation.serialized.download) }
|
let(:operation_serialized) { JSON.parse(last_operation.serialized.download) }
|
||||||
let!(:gestionnaire) { create(:gestionnaire) }
|
let!(:gestionnaire) { create(:gestionnaire) }
|
||||||
|
@ -813,7 +813,7 @@ describe Dossier do
|
||||||
after { Timecop.return }
|
after { Timecop.return }
|
||||||
|
|
||||||
it { expect(dossier.motivation).to eq('motivation') }
|
it { expect(dossier.motivation).to eq('motivation') }
|
||||||
it { expect(dossier.en_instruction_at).to eq(now) }
|
it { expect(dossier.en_instruction_at).to eq(dossier.en_instruction_at) }
|
||||||
it { expect(dossier.processed_at).to eq(now) }
|
it { expect(dossier.processed_at).to eq(now) }
|
||||||
it { expect(dossier.state).to eq('accepte') }
|
it { expect(dossier.state).to eq('accepte') }
|
||||||
it { expect(last_operation.operation).to eq('accepter') }
|
it { expect(last_operation.operation).to eq('accepter') }
|
||||||
|
@ -826,7 +826,7 @@ describe Dossier do
|
||||||
end
|
end
|
||||||
|
|
||||||
describe '#accepter_automatiquement!' do
|
describe '#accepter_automatiquement!' do
|
||||||
let(:dossier) { create(:dossier) }
|
let(:dossier) { create(:dossier, :en_construction) }
|
||||||
let(:last_operation) { dossier.dossier_operation_logs.last }
|
let(:last_operation) { dossier.dossier_operation_logs.last }
|
||||||
let!(:now) { Time.zone.parse('01/01/2100') }
|
let!(:now) { Time.zone.parse('01/01/2100') }
|
||||||
let(:attestation) { Attestation.new }
|
let(:attestation) { Attestation.new }
|
||||||
|
@ -853,7 +853,7 @@ describe Dossier do
|
||||||
end
|
end
|
||||||
|
|
||||||
describe '#passer_en_instruction!' do
|
describe '#passer_en_instruction!' do
|
||||||
let(:dossier) { create(:dossier) }
|
let(:dossier) { create(:dossier, :en_construction) }
|
||||||
let(:last_operation) { dossier.dossier_operation_logs.last }
|
let(:last_operation) { dossier.dossier_operation_logs.last }
|
||||||
let(:operation_serialized) { JSON.parse(last_operation.serialized.download) }
|
let(:operation_serialized) { JSON.parse(last_operation.serialized.download) }
|
||||||
let(:gestionnaire) { create(:gestionnaire) }
|
let(:gestionnaire) { create(:gestionnaire) }
|
||||||
|
@ -870,7 +870,7 @@ describe Dossier do
|
||||||
end
|
end
|
||||||
|
|
||||||
describe '#passer_automatiquement_en_instruction!' do
|
describe '#passer_automatiquement_en_instruction!' do
|
||||||
let(:dossier) { create(:dossier) }
|
let(:dossier) { create(:dossier, :en_construction) }
|
||||||
let(:last_operation) { dossier.dossier_operation_logs.last }
|
let(:last_operation) { dossier.dossier_operation_logs.last }
|
||||||
let(:operation_serialized) { JSON.parse(last_operation.serialized.download) }
|
let(:operation_serialized) { JSON.parse(last_operation.serialized.download) }
|
||||||
let(:gestionnaire) { create(:gestionnaire) }
|
let(:gestionnaire) { create(:gestionnaire) }
|
||||||
|
@ -987,4 +987,28 @@ describe Dossier do
|
||||||
it { expect(last_operation.operation).to eq('supprimer') }
|
it { expect(last_operation.operation).to eq('supprimer') }
|
||||||
it { expect(last_operation.automatic_operation?).to be_falsey }
|
it { expect(last_operation.automatic_operation?).to be_falsey }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe '#repasser_en_instruction!' do
|
||||||
|
let(:dossier) { create(:dossier, :refuse, :with_attestation) }
|
||||||
|
let!(:gestionnaire) { create(:gestionnaire) }
|
||||||
|
let(:last_operation) { dossier.dossier_operation_logs.last }
|
||||||
|
|
||||||
|
before do
|
||||||
|
Timecop.freeze
|
||||||
|
allow(DossierMailer).to receive(:notify_revert_to_instruction)
|
||||||
|
.and_return(double(deliver_later: true))
|
||||||
|
dossier.repasser_en_instruction!(gestionnaire)
|
||||||
|
dossier.reload
|
||||||
|
end
|
||||||
|
|
||||||
|
it { expect(dossier.state).to eq('en_instruction') }
|
||||||
|
it { expect(dossier.processed_at).to be_nil }
|
||||||
|
it { expect(dossier.motivation).to be_nil }
|
||||||
|
it { expect(dossier.attestation).to be_nil }
|
||||||
|
it { expect(last_operation.operation).to eq('repasser_en_instruction') }
|
||||||
|
it { expect(JSON.parse(last_operation.serialized.download)['author']['email']).to eq(gestionnaire.email) }
|
||||||
|
it { expect(DossierMailer).to have_received(:notify_revert_to_instruction).with(dossier) }
|
||||||
|
|
||||||
|
after { Timecop.return }
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
181
spec/services/procedure_export_v2_service_spec.rb
Normal file
181
spec/services/procedure_export_v2_service_spec.rb
Normal file
|
@ -0,0 +1,181 @@
|
||||||
|
require 'spec_helper'
|
||||||
|
|
||||||
|
describe ProcedureExportV2Service do
|
||||||
|
describe 'to_data' do
|
||||||
|
let(:procedure) { create(:procedure, :published, :with_all_champs) }
|
||||||
|
subject do
|
||||||
|
Tempfile.create do |f|
|
||||||
|
f << ProcedureExportV2Service.new(procedure).to_xlsx
|
||||||
|
f.rewind
|
||||||
|
SimpleXlsxReader.open(f.path)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
let(:dossiers_sheet) { subject.sheets.first }
|
||||||
|
let(:etablissements_sheet) { subject.sheets.second }
|
||||||
|
let(:avis_sheet) { subject.sheets.third }
|
||||||
|
let(:repetition_sheet) { subject.sheets.fourth }
|
||||||
|
|
||||||
|
before do
|
||||||
|
# change one tdc place to check if the header is ordered
|
||||||
|
tdc_first = procedure.types_de_champ.first
|
||||||
|
tdc_last = procedure.types_de_champ.last
|
||||||
|
|
||||||
|
tdc_first.update(order_place: tdc_last.order_place + 1)
|
||||||
|
procedure.reload
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'dossiers' do
|
||||||
|
it 'should have sheets' do
|
||||||
|
expect(subject.sheets.map(&:name)).to eq(['Dossiers', 'Etablissements', 'Avis'])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'with dossier' do
|
||||||
|
let!(:dossier) { create(:dossier, :en_instruction, :with_all_champs, :for_individual, procedure: procedure) }
|
||||||
|
|
||||||
|
it 'should have headers' do
|
||||||
|
expect(dossiers_sheet.headers).to eq([
|
||||||
|
"ID",
|
||||||
|
"Email",
|
||||||
|
"Civilité",
|
||||||
|
"Nom",
|
||||||
|
"Prénom",
|
||||||
|
"Date de naissance",
|
||||||
|
"Archivé",
|
||||||
|
"État du dossier",
|
||||||
|
"Dernière mise à jour le",
|
||||||
|
"Passé en construction le",
|
||||||
|
"Passé en instruction le",
|
||||||
|
"Traité le",
|
||||||
|
"Motivation de la décision",
|
||||||
|
"Instructeurs",
|
||||||
|
"textarea",
|
||||||
|
"date",
|
||||||
|
"datetime",
|
||||||
|
"number",
|
||||||
|
"decimal_number",
|
||||||
|
"integer_number",
|
||||||
|
"checkbox",
|
||||||
|
"civilite",
|
||||||
|
"email",
|
||||||
|
"phone",
|
||||||
|
"address",
|
||||||
|
"yes_no",
|
||||||
|
"simple_drop_down_list",
|
||||||
|
"multiple_drop_down_list",
|
||||||
|
"linked_drop_down_list",
|
||||||
|
"pays",
|
||||||
|
"regions",
|
||||||
|
"departements",
|
||||||
|
"engagement",
|
||||||
|
"dossier_link",
|
||||||
|
"piece_justificative",
|
||||||
|
"siret",
|
||||||
|
"carte",
|
||||||
|
"text"
|
||||||
|
])
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'should have data' do
|
||||||
|
expect(dossiers_sheet.data.size).to eq(1)
|
||||||
|
expect(etablissements_sheet.data.size).to eq(1)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'with etablissement' do
|
||||||
|
let!(:dossier) { create(:dossier, :en_instruction, :with_all_champs, :with_entreprise, procedure: procedure) }
|
||||||
|
|
||||||
|
it 'should have headers' do
|
||||||
|
expect(etablissements_sheet.headers).to eq([
|
||||||
|
"Dossier ID",
|
||||||
|
"Champ",
|
||||||
|
"Établissement SIRET",
|
||||||
|
"Établissement siège social",
|
||||||
|
"Établissement NAF",
|
||||||
|
"Établissement libellé NAF",
|
||||||
|
"Établissement Adresse",
|
||||||
|
"Établissement numero voie",
|
||||||
|
"Établissement type voie",
|
||||||
|
"Établissement nom voie",
|
||||||
|
"Établissement complément adresse",
|
||||||
|
"Établissement code postal",
|
||||||
|
"Établissement localité",
|
||||||
|
"Établissement code INSEE localité",
|
||||||
|
"Entreprise SIREN",
|
||||||
|
"Entreprise capital social",
|
||||||
|
"Entreprise numero TVA intracommunautaire",
|
||||||
|
"Entreprise forme juridique",
|
||||||
|
"Entreprise forme juridique code",
|
||||||
|
"Entreprise nom commercial",
|
||||||
|
"Entreprise raison sociale",
|
||||||
|
"Entreprise SIRET siège social",
|
||||||
|
"Entreprise code effectif entreprise",
|
||||||
|
"Entreprise date de création",
|
||||||
|
"Entreprise nom",
|
||||||
|
"Entreprise prénom",
|
||||||
|
"Association RNA",
|
||||||
|
"Association titre",
|
||||||
|
"Association objet",
|
||||||
|
"Association date de création",
|
||||||
|
"Association date de déclaration",
|
||||||
|
"Association date de publication"
|
||||||
|
])
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'should have data' do
|
||||||
|
expect(etablissements_sheet.data.size).to eq(2)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'with avis' do
|
||||||
|
let!(:dossier) { create(:dossier, :en_instruction, :with_all_champs, :for_individual, procedure: procedure) }
|
||||||
|
let!(:avis) { create(:avis, :with_answer, dossier: dossier) }
|
||||||
|
|
||||||
|
it 'should have headers' do
|
||||||
|
expect(avis_sheet.headers).to eq([
|
||||||
|
"Dossier ID",
|
||||||
|
"Question / Introduction",
|
||||||
|
"Réponse",
|
||||||
|
"Créé le",
|
||||||
|
"Répondu le"
|
||||||
|
])
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'should have data' do
|
||||||
|
expect(avis_sheet.data.size).to eq(1)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'with repetitions' do
|
||||||
|
let!(:dossier) { create(:dossier, :en_instruction, :with_all_champs, :for_individual, procedure: procedure) }
|
||||||
|
let(:champ_repetition) { dossier.champs.find { |champ| champ.type_champ == 'repetition' } }
|
||||||
|
let(:type_de_champ_text) { create(:type_de_champ_text, order_place: 0, parent: champ_repetition.type_de_champ) }
|
||||||
|
let(:type_de_champ_number) { create(:type_de_champ_number, order_place: 1, parent: champ_repetition.type_de_champ) }
|
||||||
|
|
||||||
|
before do
|
||||||
|
create(:champ_text, row: 0, type_de_champ: type_de_champ_text, parent: champ_repetition)
|
||||||
|
create(:champ_number, row: 0, type_de_champ: type_de_champ_number, parent: champ_repetition)
|
||||||
|
create(:champ_text, row: 1, type_de_champ: type_de_champ_text, parent: champ_repetition)
|
||||||
|
create(:champ_number, row: 1, type_de_champ: type_de_champ_number, parent: champ_repetition)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'should have sheets' do
|
||||||
|
expect(subject.sheets.map(&:name)).to eq(['Dossiers', 'Etablissements', 'Avis', champ_repetition.libelle])
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'should have headers' do
|
||||||
|
expect(repetition_sheet.headers).to eq([
|
||||||
|
"Dossier ID",
|
||||||
|
"Ligne",
|
||||||
|
type_de_champ_text.libelle,
|
||||||
|
type_de_champ_number.libelle
|
||||||
|
])
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'should have data' do
|
||||||
|
expect(repetition_sheet.data.size).to eq(2)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
Loading…
Reference in a new issue