diff --git a/app/assets/images/mailer/gestionnaire_mailer/logo.png b/app/assets/images/mailer/gestionnaire_mailer/logo.png
new file mode 100755
index 000000000..b8c63e7c3
Binary files /dev/null and b/app/assets/images/mailer/gestionnaire_mailer/logo.png differ
diff --git a/app/mailers/gestionnaire_mailer.rb b/app/mailers/gestionnaire_mailer.rb
index 8acbe7237..118537a8d 100644
--- a/app/mailers/gestionnaire_mailer.rb
+++ b/app/mailers/gestionnaire_mailer.rb
@@ -8,6 +8,11 @@ class GestionnaireMailer < ApplicationMailer
send_mail email, email_admin, "Vous avez été assigné à un nouvel administrateur sur la plateforme TPS"
end
+ def last_week_overview(gestionnaire, overview)
+ headers['X-mailjet-campaign'] = 'last_week_overview'
+ send_mail gestionnaire.email, overview, 'Résumé de la semaine'
+ end
+
private
def vars_mailer email, args
diff --git a/app/models/gestionnaire.rb b/app/models/gestionnaire.rb
index b5e84bcdd..f4cb1578b 100644
--- a/app/models/gestionnaire.rb
+++ b/app/models/gestionnaire.rb
@@ -92,6 +92,26 @@ class Gestionnaire < ActiveRecord::Base
notifications.pluck(:dossier_id).uniq.count
end
+ def last_week_overview
+ start_date = DateTime.now.beginning_of_week
+
+ active_procedure_overviews = procedures
+ .where(published: true)
+ .all
+ .map { |procedure| procedure.procedure_overview(start_date, dossiers_with_notifications_count_for_procedure(procedure)) }
+ .select(&:had_some_activities?)
+
+ if active_procedure_overviews.count == 0 && notifications.count == 0
+ nil
+ else
+ {
+ start_date: start_date,
+ procedure_overviews: active_procedure_overviews,
+ notifications: notifications
+ }
+ end
+ end
+
private
def valid_couple_table_attr? table, column
diff --git a/app/models/procedure.rb b/app/models/procedure.rb
index 2e910acd3..8c863697c 100644
--- a/app/models/procedure.rb
+++ b/app/models/procedure.rb
@@ -141,4 +141,7 @@ class Procedure < ActiveRecord::Base
}
end
+ def procedure_overview(start_date, notifications_count)
+ ProcedureOverview.new(self, start_date, notifications_count)
+ end
end
diff --git a/app/models/procedure_overview.rb b/app/models/procedure_overview.rb
new file mode 100644
index 000000000..5bce9e5b5
--- /dev/null
+++ b/app/models/procedure_overview.rb
@@ -0,0 +1,82 @@
+class ProcedureOverview
+ include Rails.application.routes.url_helpers
+ attr_accessor :libelle, :notifications_count, :received_dossiers_count, :created_dossiers_count, :processed_dossiers_count, :date
+
+ def initialize(procedure, start_date, notifications_count)
+ @libelle = procedure.libelle
+ @procedure_url = backoffice_dossiers_procedure_path(procedure)
+ @notifications_count = notifications_count
+
+ @received_dossiers_count = procedure.dossiers.where(state: :received).count
+ @created_dossiers_count = procedure.dossiers
+ .where(created_at: start_date..DateTime.now)
+ .where.not(state: :draft)
+ .count
+ @processed_dossiers_count = procedure.dossiers.where(processed_at: start_date..DateTime.now).count
+ end
+
+ def had_some_activities?
+ [received_dossiers_count,
+ created_dossiers_count,
+ processed_dossiers_count,
+ notifications_count].reduce(:+) > 0
+ end
+
+ def to_html
+ [libelle_description,
+ dossiers_en_instruction_description,
+ created_dossier_description,
+ processed_dossier_description,
+ notifications_description].compact.join('
')
+ end
+
+ private
+
+ def libelle_description
+ "#{libelle}"
+ end
+
+ def dossiers_en_instruction_description
+ case received_dossiers_count
+ when 0
+ nil
+ when 1
+ "1 dossier est en cours d'instruction"
+ else
+ "#{received_dossiers_count} dossiers sont en cours d'instruction"
+ end
+ end
+
+ def created_dossier_description
+ case created_dossiers_count
+ when 0
+ nil
+ when 1
+ '1 nouveau dossier a été déposé'
+ else
+ "#{created_dossiers_count} nouveaux dossiers ont été déposés"
+ end
+ end
+
+ def processed_dossier_description
+ case processed_dossiers_count
+ when 0
+ nil
+ when 1
+ '1 dossier a été instruit'
+ else
+ "#{processed_dossiers_count} dossiers ont été instruits"
+ end
+ end
+
+ def notifications_description
+ case notifications_count
+ when 0
+ nil
+ when 1
+ '1 notification en attente sur les dossiers que vous suivez'
+ else
+ "#{notifications_count} notifications en attente sur les dossiers que vous suivez"
+ end
+ end
+end
diff --git a/app/views/gestionnaire_mailer/last_week_overview.html.haml b/app/views/gestionnaire_mailer/last_week_overview.html.haml
new file mode 100644
index 000000000..a82bb9497
--- /dev/null
+++ b/app/views/gestionnaire_mailer/last_week_overview.html.haml
@@ -0,0 +1,26 @@
+%table{ align: 'center', border: '0', cellpadding: '0', cellspacing: '0', height: '100%', style: 'background-color: #fafafa', width: '100%' }
+ %tbody
+ %tr
+ %td{ align: 'center', style: 'height: 100%; margin: 0; padding: 30px; width: 100%; border-top: 0', valign: 'top' }
+ %table{ border: '0', cellpadding: '0', cellspacing: '0', style: 'border-collapse: collapse; border: 0; max-width: 600px!important;', width: '100%' }
+ %tbody
+ %tr
+ %td{ style: 'background: #ffffff none no-repeat center/cover; background-color: #ffffff; background-image: none; background-repeat: no-repeat; background-position: center; background-size: cover; border-top: 0; padding-top: 0;', valign: 'top' }
+ %table{ border: '0', cellpadding: '0', cellspacing: '0', style: 'min-width: 100%; border-collapse: collapse', width: '100%' }
+ %tr
+ %td{ style: 'padding: 0 30px; mso-line-height-rule: exactly; -ms-text-size-adjust: 100%; -webkit-text-size-adjust: 100%; ', valign: 'top' }
+ %img{ align: 'middle', alt: 'Logo TPS', src: image_url('mailer/gestionnaire_mailer/logo.png'), style: 'max-width: 125px; padding: 30px 0; display: inline !important; vertical-align: bottom; border: 0; height: auto; outline: none; text-decoration: none; -ms-interpolation-mode: bicubic;' }
+ %tr
+ %td{ style: 'padding: 0 30px 30px; word-break: break-word; color: #333333; font-family: Helvetica; font-size: 16px; line-height: 150%; text-align: left; border-bottom: 2px solid #4393F3;', valign: 'top' }
+ Bonjour, voici votre résumé de l'activité de la semaine du #{l(@args[:start_date], format: '%d %B')} au #{l(DateTime.now, format: '%d %B')}.
+ %br
+ %br
+
+ - @args[:procedure_overviews].each do |procedure_overview|
+ = procedure_overview.to_html.html_safe
+ %br
+ %br
+ Bonne journée,
+ %br
+ %br
+ L'équipe Téléprocédures Simplifiées
diff --git a/app/workers/weekly_overview_worker.rb b/app/workers/weekly_overview_worker.rb
new file mode 100644
index 000000000..8f15194a7
--- /dev/null
+++ b/app/workers/weekly_overview_worker.rb
@@ -0,0 +1,13 @@
+class WeeklyOverviewWorker
+ include Sidekiq::Worker
+
+ def perform(*args)
+ # Feature flipped to avoid mails in staging due to unprocessed dossier
+ if Features.weekly_overview
+ Gestionnaire.all
+ .map { |gestionnaire| [gestionnaire, gestionnaire.last_week_overview] }
+ .reject { |_, overview| overview.nil? }
+ .each { |gestionnaire, overview| GestionnaireMailer.last_week_overview(gestionnaire, overview).deliver_now }
+ end
+ end
+end
diff --git a/config/environments/development.rb b/config/environments/development.rb
index acb324db7..a03dda8e0 100644
--- a/config/environments/development.rb
+++ b/config/environments/development.rb
@@ -42,6 +42,7 @@ Rails.application.configure do
# Action Mailer settings
config.action_mailer.delivery_method = :smtp
config.action_mailer.default_url_options = { host: 'localhost', port: 3000 }
+ config.action_mailer.asset_host = 'http://localhost:3000'
# Config for mailcatcher https://mailcatcher.me/
config.action_mailer.smtp_settings = {
:address => "localhost",
diff --git a/config/initializers/features.yml b/config/initializers/features.yml
index e91fb5346..7776e7e30 100644
--- a/config/initializers/features.yml
+++ b/config/initializers/features.yml
@@ -1 +1,2 @@
remote_storage: false
+weekly_overview: false
diff --git a/config/schedule.yml b/config/schedule.yml
index 79dbdefc9..9a2979d42 100644
--- a/config/schedule.yml
+++ b/config/schedule.yml
@@ -1,3 +1,6 @@
auto_archive_procedure:
cron: "* * * * *"
class: "AutoArchiveProcedureWorker"
+weekly_overview_worker:
+ cron: "0 8 * * 0"
+ class: "WeeklyOverviewWorker"
diff --git a/spec/mailers/previews/gestionnaire_mailer_preview.rb b/spec/mailers/previews/gestionnaire_mailer_preview.rb
new file mode 100644
index 000000000..2e62b4f5c
--- /dev/null
+++ b/spec/mailers/previews/gestionnaire_mailer_preview.rb
@@ -0,0 +1,6 @@
+class GestionnaireMailerPreview < ActionMailer::Preview
+ def last_week_overview
+ gestionnaire = Gestionnaire.first
+ GestionnaireMailer.last_week_overview(gestionnaire, gestionnaire.last_week_overview)
+ end
+end
diff --git a/spec/models/gestionnaire_spec.rb b/spec/models/gestionnaire_spec.rb
index 8525b2e86..27cb3502e 100644
--- a/spec/models/gestionnaire_spec.rb
+++ b/spec/models/gestionnaire_spec.rb
@@ -347,4 +347,52 @@ describe Gestionnaire, type: :model do
end
end
end
+
+ describe 'last_week_overview' do
+ let!(:gestionnaire2) { create(:gestionnaire) }
+ subject { gestionnaire2.last_week_overview }
+ let(:friday) { DateTime.new(2017, 5, 12) }
+ let(:monday) { DateTime.now.beginning_of_week }
+
+ before :each do
+ Timecop.freeze(friday)
+ end
+
+ context 'when no procedure published was active last week' do
+ let!(:procedure) { create(:procedure, gestionnaires: [gestionnaire2], libelle: 'procedure', published: true) }
+ context 'when the gestionnaire has no notifications' do
+ it { is_expected.to eq(nil) }
+ end
+
+ context 'when the gestionnaire has one notification' do
+ before :each do
+ expect(gestionnaire2).to receive(:notifications).twice.and_return([1])
+ end
+
+ it { is_expected.to eq({ start_date: monday, procedure_overviews: [], notifications: [1] }) }
+ end
+ end
+
+ context 'when a procedure published was active' do
+ let!(:procedure) { create(:procedure, gestionnaires: [gestionnaire2], libelle: 'procedure', published: true) }
+ let(:procedure_overview) { double('procedure_overview', 'had_some_activities?'.to_sym => true) }
+
+ before :each do
+ expect_any_instance_of(Procedure).to receive(:procedure_overview).and_return(procedure_overview)
+ end
+
+ it { expect(gestionnaire.last_week_overview[:procedure_overviews]).to match([procedure_overview]) }
+ end
+
+ context 'when a procedure not published was active with no notifications' do
+ let!(:procedure) { create(:procedure, gestionnaires: [gestionnaire2], libelle: 'procedure', published: false) }
+ let(:procedure_overview) { double('procedure_overview', 'had_some_activities?'.to_sym => true) }
+
+ before :each do
+ allow_any_instance_of(Procedure).to receive(:procedure_overview).and_return(procedure_overview)
+ end
+
+ it { is_expected.to eq(nil) }
+ end
+ end
end
diff --git a/spec/models/procedure_overview_spec.rb b/spec/models/procedure_overview_spec.rb
new file mode 100644
index 000000000..c6670d730
--- /dev/null
+++ b/spec/models/procedure_overview_spec.rb
@@ -0,0 +1,87 @@
+require 'spec_helper'
+
+describe ProcedureOverview, type: :model do
+ let(:procedure) { create(:procedure, libelle: 'libelle') }
+ let(:friday) { DateTime.new(2017, 5, 12) } # vendredi 12 mai 2017, de la semaine du 8 mai
+ let(:monday) { DateTime.new(2017, 5, 8) }
+
+ before :each do
+ Timecop.freeze(friday)
+ end
+
+ let(:procedure_overview) { ProcedureOverview.new(procedure, monday, 0) }
+
+ describe 'received_dossiers_count' do
+ let!(:received_dossier) do
+ dossier = create(:dossier, procedure: procedure, state: :received, created_at: monday)
+ end
+
+ it { expect(procedure_overview.received_dossiers_count).to eq(1) }
+ end
+
+ describe 'created_dossiers_count' do
+ let!(:created_dossier_during_the_week) do
+ create(:dossier, procedure: procedure, created_at: monday, state: :received)
+ end
+
+ let!(:created_dossier_during_the_week_but_in_draft) do
+ create(:dossier, procedure: procedure, created_at: monday, state: :draft)
+ end
+
+ let!(:created_dossier_before_the_week) do
+ create(:dossier, procedure: procedure, created_at: (monday - 1.week), state: :received)
+ end
+
+ it { expect(procedure_overview.created_dossiers_count).to eq(1) }
+ end
+
+ describe 'processed_dossiers_count' do
+ let!(:processed_dossier_during_the_week) do
+ create(:dossier, procedure: procedure, created_at: monday, processed_at: monday)
+ end
+
+ let!(:processed_dossier_before_the_week) do
+ create(:dossier, procedure: procedure, created_at: (monday - 1.week), processed_at: (monday - 1.week))
+ end
+
+ it { expect(procedure_overview.processed_dossiers_count).to eq(1) }
+ end
+
+ describe 'to_html' do
+ subject { procedure_overview.to_html }
+
+ context 'when the different count are equal to 0' do
+ it { is_expected.to match(/^libelle<\/strong><\/a>$/) }
+ end
+
+ context 'when the different counts are equal to 1' do
+ before :each do
+ procedure_overview.notifications_count = 1
+ procedure_overview.received_dossiers_count = 1
+ procedure_overview.created_dossiers_count = 1
+ procedure_overview.processed_dossiers_count = 1
+ end
+
+ it { is_expected.to match(/^libelle<\/strong><\/a>/) }
+ it { is_expected.to include("1 dossier est en cours d'instruction") }
+ it { is_expected.to include('1 nouveau dossier a été déposé') }
+ it { is_expected.to include('1 dossier a été instruit') }
+ it { is_expected.to include('1 notification en attente sur les dossiers que vous suivez') }
+ end
+
+ context 'when the different counts are equal to 2' do
+ before :each do
+ procedure_overview.notifications_count = 2
+ procedure_overview.received_dossiers_count = 3
+ procedure_overview.created_dossiers_count = 4
+ procedure_overview.processed_dossiers_count = 5
+ end
+
+ it { is_expected.to match(/^libelle<\/strong><\/a>/) }
+ it { is_expected.to include("3 dossiers sont en cours d'instruction") }
+ it { is_expected.to include('4 nouveaux dossiers ont été déposés') }
+ it { is_expected.to include('5 dossiers ont été instruits') }
+ it { is_expected.to include('2 notifications en attente sur les dossiers que vous suivez') }
+ end
+ end
+end
diff --git a/spec/workers/weekly_overview_worker_spec.rb b/spec/workers/weekly_overview_worker_spec.rb
new file mode 100644
index 000000000..e2bff3e80
--- /dev/null
+++ b/spec/workers/weekly_overview_worker_spec.rb
@@ -0,0 +1,44 @@
+require 'rails_helper'
+
+RSpec.describe WeeklyOverviewWorker, type: :worker do
+ describe 'perform' do
+ let!(:gestionnaire) { create(:gestionnaire) }
+ let(:overview) { double('overview') }
+ let(:mailer_double) { double('mailer', deliver_now: true) }
+
+ context 'if the feature is enabled' do
+ before { allow(Features).to receive(:weekly_overview).and_return(true) }
+
+ context 'with one gestionnaire with one overview' do
+ before :each do
+ expect_any_instance_of(Gestionnaire).to receive(:last_week_overview).and_return(overview)
+ allow(GestionnaireMailer).to receive(:last_week_overview).and_return(mailer_double)
+ WeeklyOverviewWorker.new.perform
+ end
+
+ it { expect(GestionnaireMailer).to have_received(:last_week_overview).with(gestionnaire, overview) }
+ it { expect(mailer_double).to have_received(:deliver_now) }
+ end
+
+ context 'with one gestionnaire with no overviews' do
+ before :each do
+ expect_any_instance_of(Gestionnaire).to receive(:last_week_overview).and_return(nil)
+ allow(GestionnaireMailer).to receive(:last_week_overview)
+ WeeklyOverviewWorker.new.perform
+ end
+
+ it { expect(GestionnaireMailer).not_to have_received(:last_week_overview) }
+ end
+ end
+
+ context 'if the feature is disabled' do
+ before { allow(Features).to receive(:weekly_overview).and_return(false) }
+ before :each do
+ allow(Gestionnaire).to receive(:all)
+ WeeklyOverviewWorker.new.perform
+ end
+
+ it { expect(Gestionnaire).not_to receive(:all) }
+ end
+ end
+end