commit
408124d61c
17 changed files with 4206 additions and 184 deletions
4
.gitignore
vendored
4
.gitignore
vendored
|
@ -34,3 +34,7 @@ vendor/*
|
|||
/yarn-error.log
|
||||
yarn-debug.log*
|
||||
.yarn-integrity
|
||||
/docs
|
||||
|
||||
# Local Netlify folder
|
||||
.netlify
|
||||
|
|
|
@ -454,7 +454,7 @@ GEM
|
|||
ast (~> 2.4.1)
|
||||
pdf-core (0.7.0)
|
||||
pg (1.2.3)
|
||||
phonelib (0.6.43)
|
||||
phonelib (0.6.45)
|
||||
prawn (2.2.2)
|
||||
pdf-core (~> 0.7.0)
|
||||
ttfunk (~> 1.5)
|
||||
|
|
|
@ -30,17 +30,16 @@ module Instructeurs
|
|||
.reorder(nil)
|
||||
.count
|
||||
|
||||
@all_dossiers_counts = {}
|
||||
@all_dossiers_counts['à suivre'] = dossiers.without_followers.en_cours.count
|
||||
@all_dossiers_counts['suivis'] = current_instructeur
|
||||
.followed_dossiers
|
||||
.joins(:groupe_instructeur)
|
||||
.en_cours
|
||||
.where(groupe_instructeur_id: groupe_ids)
|
||||
.count
|
||||
@all_dossiers_counts['traités'] = dossiers.termine.count
|
||||
@all_dossiers_counts['dossiers'] = dossiers.all_state.count
|
||||
@all_dossiers_counts['archivés'] = dossiers.archived.count
|
||||
@all_dossiers_counts = {
|
||||
'à suivre' => @dossiers_a_suivre_count_per_procedure.sum { |_, v| v },
|
||||
'suivis' => @followed_dossiers_count_per_procedure.sum { |_, v| v },
|
||||
'traités' => @dossiers_termines_count_per_procedure.sum { |_, v| v },
|
||||
'dossiers' => @dossiers_count_per_procedure.sum { |_, v| v },
|
||||
'archivés' => @dossiers_archived_count_per_procedure.sum { |_, v| v }
|
||||
}
|
||||
|
||||
@procedure_ids_en_cours_with_notifications = current_instructeur.procedure_ids_with_notifications(:en_cours)
|
||||
@procedure_ids_termines_with_notifications = current_instructeur.procedure_ids_with_notifications(:termine)
|
||||
end
|
||||
|
||||
def show
|
||||
|
|
|
@ -20,5 +20,5 @@ class Champs::PhoneChamp < Champs::TextChamp
|
|||
possible: true,
|
||||
allow_blank: true,
|
||||
message: I18n.t(:not_a_phone, scope: 'activerecord.errors.messages')
|
||||
}
|
||||
}, unless: -> { Phonelib.valid_for_country?(value, :pf) }
|
||||
end
|
||||
|
|
|
@ -144,17 +144,14 @@ class Instructeur < ApplicationRecord
|
|||
.with_notifications(self)
|
||||
end
|
||||
|
||||
def procedures_with_notifications(scope)
|
||||
dossiers = Dossier
|
||||
def procedure_ids_with_notifications(scope)
|
||||
groupe_instructeur_ids = Dossier
|
||||
.send(scope) # :en_cours or :termine (or any other Dossier scope)
|
||||
.merge(followed_dossiers)
|
||||
.with_notifications(self)
|
||||
.select(:groupe_instructeur_id)
|
||||
|
||||
Procedure
|
||||
.where(id: dossiers.joins(:groupe_instructeur)
|
||||
.select('groupe_instructeurs.procedure_id')
|
||||
.distinct)
|
||||
.distinct
|
||||
GroupeInstructeur.where(id: groupe_instructeur_ids).pluck(:procedure_id)
|
||||
end
|
||||
|
||||
def mark_tab_as_seen(dossier, tab)
|
||||
|
|
|
@ -1,63 +1,61 @@
|
|||
%ul.procedure-list
|
||||
- procedures.each do |p|
|
||||
%li.procedure-item.flex.align-start
|
||||
= link_to(instructeur_procedure_path(p)) do
|
||||
.flex
|
||||
%li.procedure-item.flex.align-start
|
||||
= link_to(instructeur_procedure_path(p)) do
|
||||
.flex
|
||||
|
||||
.procedure-logo{ style: "background-image: url(#{p.logo_url})" }
|
||||
.procedure-logo{ style: "background-image: url(#{p.logo_url})" }
|
||||
|
||||
.procedure-details
|
||||
%p.procedure-title
|
||||
= procedure_libelle p
|
||||
%ul.procedure-stats.flex
|
||||
%li
|
||||
%object
|
||||
= link_to(instructeur_procedure_path(p, statut: 'a-suivre')) do
|
||||
- a_suivre_count = dossiers_a_suivre_count_per_procedure[p.id] || 0
|
||||
.stats-number
|
||||
= number_with_html_delimiter(a_suivre_count)
|
||||
.stats-legend
|
||||
à suivre
|
||||
%li
|
||||
%object
|
||||
= link_to(instructeur_procedure_path(p, statut: 'suivis')) do
|
||||
- if current_instructeur.procedures_with_notifications(:en_cours).include?(p)
|
||||
%span.notifications{ 'aria-label': "notifications" }
|
||||
- followed_count = followed_dossiers_count_per_procedure[p.id] || 0
|
||||
.stats-number
|
||||
= number_with_html_delimiter(followed_count)
|
||||
.stats-legend
|
||||
= t('pluralize.followed', count: followed_count)
|
||||
%li
|
||||
%object
|
||||
= link_to(instructeur_procedure_path(p, statut: 'traites')) do
|
||||
- if current_instructeur.procedures_with_notifications(:termine).include?(p)
|
||||
%span.notifications{ 'aria-label': "notifications" }
|
||||
- termines_count = dossiers_termines_count_per_procedure[p.id] || 0
|
||||
.stats-number
|
||||
= number_with_html_delimiter(termines_count)
|
||||
.stats-legend
|
||||
= t('pluralize.processed', count: termines_count)
|
||||
%li
|
||||
%object
|
||||
= link_to(instructeur_procedure_path(p, statut: 'tous')) do
|
||||
- dossier_count = dossiers_count_per_procedure[p.id] || 0
|
||||
.stats-number
|
||||
= number_with_html_delimiter(dossier_count)
|
||||
.stats-legend
|
||||
= t('pluralize.case', count: dossier_count)
|
||||
%li
|
||||
%object
|
||||
= link_to(instructeur_procedure_path(p, statut: 'archives')) do
|
||||
- archived_count = dossiers_archived_count_per_procedure[p.id] || 0
|
||||
.stats-number
|
||||
= number_with_html_delimiter(archived_count)
|
||||
.stats-legend
|
||||
= t('pluralize.archived', count: archived_count)
|
||||
.procedure-details
|
||||
%p.procedure-title
|
||||
= procedure_libelle p
|
||||
%ul.procedure-stats.flex
|
||||
%li
|
||||
%object
|
||||
= link_to(instructeur_procedure_path(p, statut: 'a-suivre')) do
|
||||
- a_suivre_count = dossiers_a_suivre_count_per_procedure[p.id] || 0
|
||||
.stats-number
|
||||
= number_with_html_delimiter(a_suivre_count)
|
||||
.stats-legend
|
||||
à suivre
|
||||
%li
|
||||
%object
|
||||
= link_to(instructeur_procedure_path(p, statut: 'suivis')) do
|
||||
- if procedure_ids_en_cours_with_notifications.include?(p.id)
|
||||
%span.notifications{ 'aria-label': "notifications" }
|
||||
- followed_count = followed_dossiers_count_per_procedure[p.id] || 0
|
||||
.stats-number
|
||||
= number_with_html_delimiter(followed_count)
|
||||
.stats-legend
|
||||
= t('pluralize.followed', count: followed_count)
|
||||
%li
|
||||
%object
|
||||
= link_to(instructeur_procedure_path(p, statut: 'traites')) do
|
||||
- if procedure_ids_termines_with_notifications.include?(p.id)
|
||||
%span.notifications{ 'aria-label': "notifications" }
|
||||
- termines_count = dossiers_termines_count_per_procedure[p.id] || 0
|
||||
.stats-number
|
||||
= number_with_html_delimiter(termines_count)
|
||||
.stats-legend
|
||||
= t('pluralize.processed', count: termines_count)
|
||||
%li
|
||||
%object
|
||||
= link_to(instructeur_procedure_path(p, statut: 'tous')) do
|
||||
- dossier_count = dossiers_count_per_procedure[p.id] || 0
|
||||
.stats-number
|
||||
= number_with_html_delimiter(dossier_count)
|
||||
.stats-legend
|
||||
= t('pluralize.case', count: dossier_count)
|
||||
%li
|
||||
%object
|
||||
= link_to(instructeur_procedure_path(p, statut: 'archives')) do
|
||||
- archived_count = dossiers_archived_count_per_procedure[p.id] || 0
|
||||
.stats-number
|
||||
= number_with_html_delimiter(archived_count)
|
||||
.stats-legend
|
||||
= t('pluralize.archived', count: archived_count)
|
||||
|
||||
- if p.close?
|
||||
.procedure-status
|
||||
%span.label Close
|
||||
- elsif p.depubliee?
|
||||
.procedure-status
|
||||
%span.label Dépubliée
|
||||
- if p.close?
|
||||
.procedure-status
|
||||
%span.label Close
|
||||
- elsif p.depubliee?
|
||||
.procedure-status
|
||||
%span.label Dépubliée
|
||||
|
|
|
@ -4,9 +4,14 @@
|
|||
%h1.page-title Démarches
|
||||
= render partial: 'instructeurs/procedures/synthese', locals: { procedures: @procedures, all_dossiers_counts: @all_dossiers_counts }
|
||||
|
||||
= render partial: 'instructeurs/procedures/list', locals: { procedures: @procedures,
|
||||
dossiers_count_per_procedure: @dossiers_count_per_procedure,
|
||||
dossiers_a_suivre_count_per_procedure: @dossiers_a_suivre_count_per_procedure,
|
||||
dossiers_archived_count_per_procedure: @dossiers_archived_count_per_procedure,
|
||||
dossiers_termines_count_per_procedure: @dossiers_termines_count_per_procedure,
|
||||
followed_dossiers_count_per_procedure: @followed_dossiers_count_per_procedure }
|
||||
%ul.procedure-list
|
||||
= render partial: 'instructeurs/procedures/list',
|
||||
collection: @procedures,
|
||||
as: :p,
|
||||
locals: { dossiers_count_per_procedure: @dossiers_count_per_procedure,
|
||||
dossiers_a_suivre_count_per_procedure: @dossiers_a_suivre_count_per_procedure,
|
||||
dossiers_archived_count_per_procedure: @dossiers_archived_count_per_procedure,
|
||||
dossiers_termines_count_per_procedure: @dossiers_termines_count_per_procedure,
|
||||
followed_dossiers_count_per_procedure: @followed_dossiers_count_per_procedure,
|
||||
procedure_ids_en_cours_with_notifications: @procedure_ids_en_cours_with_notifications,
|
||||
procedure_ids_termines_with_notifications: @procedure_ids_termines_with_notifications }
|
||||
|
|
|
@ -19,9 +19,13 @@ max_logo_width = body_width
|
|||
max_logo_height = 50.mm
|
||||
max_signature_size = 50.mm
|
||||
|
||||
title = @attestation.fetch(:title)
|
||||
body = @attestation.fetch(:body)
|
||||
footer = @attestation.fetch(:footer)
|
||||
def normalize_pdf_text(text)
|
||||
text&.tr("\t", ' ')
|
||||
end
|
||||
|
||||
title = normalize_pdf_text(@attestation.fetch(:title))
|
||||
body = normalize_pdf_text(@attestation.fetch(:body))
|
||||
footer = normalize_pdf_text(@attestation.fetch(:footer))
|
||||
created_at = @attestation.fetch(:created_at)
|
||||
|
||||
logo = @attestation[:logo]
|
||||
|
|
|
@ -225,7 +225,7 @@
|
|||
.cta-panel-wrapper
|
||||
%div
|
||||
%h1.cta-panel-title Une question, un problème ?
|
||||
%p.cta-panel-explanation Notre équipe est disponible pour vous renseigner et vous aider
|
||||
%p.cta-panel-explanation Consultez notre FAQ
|
||||
%div
|
||||
%a.cta-panel-button-white{ rel: 'noopener noreferrer', href:'/contact-admin' }
|
||||
Contactez-nous
|
||||
%a.cta-panel-button-white{ rel: 'noopener noreferrer', href:"#{ FAQ_URL }" }
|
||||
Voir la FAQ
|
||||
|
|
|
@ -43,7 +43,7 @@
|
|||
%ul.numbers
|
||||
%li.number
|
||||
.number-value
|
||||
= number_with_delimiter(Procedure.includes(:administrateurs).publiees_ou_closes.flat_map(&:administrateurs).uniq.count, :locale => :fr)
|
||||
= number_with_delimiter(AdministrateursProcedure.joins(:procedure).merge(Procedure.publiees_ou_closes).select('distinct administrateur_id').count, :locale => :fr)
|
||||
.number-label<
|
||||
administrations
|
||||
%br<>
|
||||
|
|
11
package.json
11
package.json
|
@ -38,6 +38,7 @@
|
|||
"whatwg-fetch": "^3.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@2fd/graphdoc": "^2.4.0",
|
||||
"babel-eslint": "^10.1.0",
|
||||
"eclint": "^2.8.1",
|
||||
"eslint": "^7.0.0",
|
||||
|
@ -45,6 +46,7 @@
|
|||
"eslint-plugin-prettier": "^3.1.3",
|
||||
"eslint-plugin-react": "^7.20.0",
|
||||
"eslint-plugin-react-hooks": "^4.0.2",
|
||||
"netlify-cli": "^2.61.2",
|
||||
"prettier": "^2.0.5",
|
||||
"webpack-bundle-analyzer": "^3.7.0",
|
||||
"webpack-dev-server": "^3.11.0"
|
||||
|
@ -52,9 +54,16 @@
|
|||
"scripts": {
|
||||
"lint:ec": "eclint check $({ git ls-files | grep -v app/graphql/schema.graphql ; find vendor -type f ; echo 'db/schema.rb' ; } | sort | uniq -u)",
|
||||
"lint:js": "eslint ./app/javascript ./app/assets/javascripts ./config/webpack",
|
||||
"webpack:build": "NODE_ENV=production bin/webpack"
|
||||
"webpack:build": "NODE_ENV=production bin/webpack",
|
||||
"graphql:docs:build": "graphdoc --force",
|
||||
"graphql:docs:deploy": "netlify deploy -d ./docs/graphql --prod",
|
||||
"graphql:docs:publish": "yarn graphql:docs:build && yarn graphql:docs:deploy"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 12.*"
|
||||
},
|
||||
"graphdoc": {
|
||||
"endpoint": "https://www.demarches-simplifiees.fr/api/v2/graphql",
|
||||
"output": "./docs/graphql"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -698,6 +698,43 @@ describe Users::DossiersController, type: :controller do
|
|||
expect(instructeur.reload.followed_dossiers.with_notifications(instructeur)).to eq([dossier.reload])
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the champ is a phone number' do
|
||||
let(:procedure) { create(:procedure, :published, :with_phone) }
|
||||
let!(:dossier) { create(:dossier, :en_construction, user: user, procedure: procedure) }
|
||||
let(:first_champ) { dossier.champs.first }
|
||||
let(:now) { Time.zone.parse('01/01/2100') }
|
||||
|
||||
let(:submit_payload) do
|
||||
{
|
||||
id: dossier.id,
|
||||
dossier: {
|
||||
champs_attributes: [
|
||||
{
|
||||
id: first_champ.id,
|
||||
value: value
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
context 'with a valid value sent as string' do
|
||||
let(:value) { '0612345678' }
|
||||
it 'updates the value' do
|
||||
subject
|
||||
expect(first_champ.reload.value).to eq('0612345678')
|
||||
end
|
||||
end
|
||||
|
||||
context 'with a valid value sent as number' do
|
||||
let(:value) { '45187272'.to_i }
|
||||
it 'updates the value' do
|
||||
subject
|
||||
expect(first_champ.reload.value).to eq('45187272')
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#index' do
|
||||
|
|
|
@ -182,6 +182,12 @@ FactoryBot.define do
|
|||
end
|
||||
end
|
||||
|
||||
trait :with_phone do
|
||||
after(:build) do |procedure, _evaluator|
|
||||
build(:type_de_champ_phone, procedure: procedure)
|
||||
end
|
||||
end
|
||||
|
||||
trait :published do
|
||||
after(:build) do |procedure, _evaluator|
|
||||
procedure.path = generate(:published_path)
|
||||
|
|
|
@ -13,7 +13,23 @@ RSpec.describe ApplicationJob, type: :job do
|
|||
end
|
||||
end
|
||||
|
||||
context 'when ::Excon::Error::BadRequest is raised' do
|
||||
# https://api.rubyonrails.org/classes/ActiveJob/Exceptions/ClassMethods.html#method-i-retry_on
|
||||
# retry on will try 5 times and then bubble up the error
|
||||
it 'makes 5 attempts' do
|
||||
assert_performed_jobs 5 do
|
||||
ExconErrJob.perform_later rescue ::Excon::Error::BadRequest
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
class ChildJob < ApplicationJob
|
||||
def perform; end
|
||||
end
|
||||
|
||||
class ExconErrJob < ApplicationJob
|
||||
def perform
|
||||
raise ::Excon::Error::BadRequest.new('bad request')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -20,6 +20,19 @@ describe Champs::PhoneChamp do
|
|||
expect(build(:champ_phone, value: "+1(0) - 123456789")).to be_valid
|
||||
expect(build(:champ_phone, value: "+49 2109 87654321")).to be_valid
|
||||
expect(build(:champ_phone, value: "012345678")).to be_valid
|
||||
# polynesian numbers should not return errors in any way
|
||||
## landline numbers start with 40 or 45
|
||||
expect(build(:champ_phone, value: "45187272")).to be_valid
|
||||
expect(build(:champ_phone, value: "40 473 500")).to be_valid
|
||||
expect(build(:champ_phone, value: "40473500")).to be_valid
|
||||
expect(build(:champ_phone, value: "45473500")).to be_valid
|
||||
## +689 is the international indicator
|
||||
expect(build(:champ_phone, value: "+689 45473500")).to be_valid
|
||||
expect(build(:champ_phone, value: "0145473500")).to be_valid
|
||||
## polynesian mobile numbers start with 87, 88, 89
|
||||
expect(build(:champ_phone, value: "87473500")).to be_valid
|
||||
expect(build(:champ_phone, value: "88473500")).to be_valid
|
||||
expect(build(:champ_phone, value: "89473500")).to be_valid
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -352,17 +352,17 @@ describe Instructeur, type: :model do
|
|||
end
|
||||
end
|
||||
|
||||
describe '#notifications_per_procedure' do
|
||||
describe '#procedure_ids_with_notifications' do
|
||||
let!(:dossier) { create(:dossier, :followed, state: Dossier.states.fetch(:en_construction)) }
|
||||
let(:instructeur) { dossier.follows.first.instructeur }
|
||||
let(:procedure) { dossier.procedure }
|
||||
|
||||
subject { instructeur.procedures_with_notifications(:en_cours) }
|
||||
subject { instructeur.procedure_ids_with_notifications(:en_cours) }
|
||||
|
||||
context 'when there is a modification on public champs' do
|
||||
before { dossier.update!(last_champ_updated_at: Time.zone.now) }
|
||||
|
||||
it { is_expected.to match([procedure]) }
|
||||
it { is_expected.to match([procedure.id]) }
|
||||
end
|
||||
end
|
||||
|
||||
|
|
Loading…
Reference in a new issue