commit
21ad1f40d9
25 changed files with 336 additions and 48 deletions
26
app/controllers/api/v2/dossiers_controller.rb
Normal file
26
app/controllers/api/v2/dossiers_controller.rb
Normal file
|
@ -0,0 +1,26 @@
|
|||
class API::V2::DossiersController < API::V2::BaseController
|
||||
before_action :ensure_dossier_present
|
||||
|
||||
def pdf
|
||||
@include_infos_administration = true
|
||||
render(file: 'dossiers/show', formats: [:pdf])
|
||||
end
|
||||
|
||||
def geojson
|
||||
send_data dossier.to_feature_collection.to_json,
|
||||
type: 'application/json',
|
||||
filename: "dossier-#{dossier.id}-features.json"
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def ensure_dossier_present
|
||||
if dossier.blank?
|
||||
head :unauthorized
|
||||
end
|
||||
end
|
||||
|
||||
def dossier
|
||||
@dossier ||= GlobalID::Locator.locate_signed(params[:id].to_s, for: 'api_v2')
|
||||
end
|
||||
end
|
|
@ -12,6 +12,8 @@ class RootController < ApplicationController
|
|||
return redirect_to manager_root_path
|
||||
end
|
||||
|
||||
@stat = Stat.first
|
||||
|
||||
render 'landing'
|
||||
end
|
||||
|
||||
|
|
|
@ -4,23 +4,35 @@ class StatsController < ApplicationController
|
|||
MEAN_NUMBER_OF_CHAMPS_IN_A_FORM = 24.0
|
||||
|
||||
def index
|
||||
stat = Stat.first
|
||||
|
||||
procedures = Procedure.publiees_ou_closes
|
||||
dossiers = Dossier.state_not_brouillon
|
||||
|
||||
@procedures_numbers = procedures_numbers(procedures)
|
||||
@dossiers_numbers = dossiers_numbers(dossiers)
|
||||
|
||||
@dossiers_numbers = dossiers_numbers(
|
||||
stat.dossiers_not_brouillon,
|
||||
stat.dossiers_depose_avant_30_jours,
|
||||
stat.dossiers_deposes_entre_60_et_30_jours
|
||||
)
|
||||
|
||||
@satisfaction_usagers = satisfaction_usagers
|
||||
|
||||
@contact_percentage = contact_percentage
|
||||
|
||||
@dossiers_states = dossiers_states
|
||||
@dossiers_states_for_pie = {
|
||||
"Brouillon" => stat.dossiers_brouillon,
|
||||
"En construction" => stat.dossiers_en_construction,
|
||||
"En instruction" => stat.dossiers_en_instruction,
|
||||
"Terminé" => stat.dossiers_termines
|
||||
}
|
||||
|
||||
@procedures_cumulative = cumulative_hash(procedures, :published_at)
|
||||
@procedures_in_the_last_4_months = last_four_months_hash(procedures, :published_at)
|
||||
|
||||
@dossiers_cumulative = cumulative_hash(dossiers, :en_construction_at)
|
||||
@dossiers_in_the_last_4_months = last_four_months_hash(dossiers, :en_construction_at)
|
||||
@dossiers_cumulative = stat.dossiers_cumulative
|
||||
@dossiers_in_the_last_4_months = stat.dossiers_in_the_last_4_months
|
||||
|
||||
if administration_signed_in?
|
||||
@dossier_instruction_mean_time = Rails.cache.fetch("dossier_instruction_mean_time", expires_in: 1.day) do
|
||||
|
@ -96,10 +108,7 @@ class StatsController < ApplicationController
|
|||
}
|
||||
end
|
||||
|
||||
def dossiers_numbers(dossiers)
|
||||
total = dossiers.count
|
||||
last_30_days_count = dossiers.where(en_construction_at: 1.month.ago..Time.zone.now).count
|
||||
previous_count = dossiers.where(en_construction_at: 2.months.ago..1.month.ago).count
|
||||
def dossiers_numbers(total, last_30_days_count, previous_count)
|
||||
if previous_count != 0
|
||||
evolution = (((last_30_days_count.to_f / previous_count) - 1) * 100).round(0)
|
||||
else
|
||||
|
@ -114,15 +123,6 @@ class StatsController < ApplicationController
|
|||
}
|
||||
end
|
||||
|
||||
def dossiers_states
|
||||
{
|
||||
'Brouilllon' => Dossier.state_brouillon.count,
|
||||
'En construction' => Dossier.state_en_construction.count,
|
||||
'En instruction' => Dossier.state_en_instruction.count,
|
||||
'Terminé' => Dossier.state_termine.count
|
||||
}
|
||||
end
|
||||
|
||||
def satisfaction_usagers
|
||||
legend = {
|
||||
Feedback.ratings.fetch(:unhappy) => "Mécontents",
|
||||
|
|
|
@ -55,7 +55,7 @@ interface Champ {
|
|||
|
||||
type ChampDescriptor {
|
||||
"""
|
||||
Description des champs d'un bloc répétable.
|
||||
Description des champs d’un bloc répétable.
|
||||
"""
|
||||
champDescriptors: [ChampDescriptor!]
|
||||
|
||||
|
@ -71,7 +71,7 @@ type ChampDescriptor {
|
|||
label: String!
|
||||
|
||||
"""
|
||||
List des options d'un champ avec selection.
|
||||
List des options d’un champ avec selection.
|
||||
"""
|
||||
options: [String!]
|
||||
|
||||
|
@ -246,7 +246,7 @@ type Demarche {
|
|||
datePublication: ISO8601DateTime!
|
||||
|
||||
"""
|
||||
L'état de dossier pour une démarche déclarative
|
||||
L’état de dossier pour une démarche déclarative
|
||||
"""
|
||||
declarative: DossierDeclarativeState
|
||||
|
||||
|
@ -256,7 +256,7 @@ type Demarche {
|
|||
description: String!
|
||||
|
||||
"""
|
||||
Liste de tous les dossiers d'une démarche.
|
||||
Liste de tous les dossiers d’une démarche.
|
||||
"""
|
||||
dossiers(
|
||||
"""
|
||||
|
@ -290,7 +290,7 @@ type Demarche {
|
|||
last: Int
|
||||
|
||||
"""
|
||||
L'ordre des dossiers.
|
||||
L’ordre des dossiers.
|
||||
"""
|
||||
order: Order = ASC
|
||||
|
||||
|
@ -317,7 +317,7 @@ type Demarche {
|
|||
service: Service!
|
||||
|
||||
"""
|
||||
L'état de la démarche.
|
||||
L’état de la démarche.
|
||||
"""
|
||||
state: DemarcheState!
|
||||
|
||||
|
@ -380,6 +380,11 @@ Un dossier
|
|||
type Dossier {
|
||||
annotations: [Champ!]!
|
||||
archived: Boolean!
|
||||
|
||||
"""
|
||||
L’URL de l’attestation au format PDF.
|
||||
"""
|
||||
attestation: File
|
||||
avis: [Avis!]!
|
||||
champs: [Champ!]!
|
||||
|
||||
|
@ -403,6 +408,11 @@ type Dossier {
|
|||
"""
|
||||
dateTraitement: ISO8601DateTime
|
||||
demandeur: Demandeur!
|
||||
|
||||
"""
|
||||
L’URL du GeoJSON contenant les données cartographiques du dossier.
|
||||
"""
|
||||
geojson: File
|
||||
groupeInstructeur: GroupeInstructeur!
|
||||
id: ID!
|
||||
instructeurs: [Profile!]!
|
||||
|
@ -414,10 +424,15 @@ type Dossier {
|
|||
Le numero du dossier.
|
||||
"""
|
||||
number: Int!
|
||||
|
||||
"""
|
||||
L’URL du dossier au format PDF.
|
||||
"""
|
||||
pdf: File
|
||||
revision: Revision!
|
||||
|
||||
"""
|
||||
L'état du dossier.
|
||||
L’état du dossier.
|
||||
"""
|
||||
state: DossierState!
|
||||
usager: Profile!
|
||||
|
@ -754,7 +769,7 @@ type Entreprise {
|
|||
dateCreation: ISO8601Date!
|
||||
|
||||
"""
|
||||
effectif moyen d'une année
|
||||
effectif moyen d’une année
|
||||
"""
|
||||
effectifAnnuel: Effectif
|
||||
|
||||
|
@ -829,7 +844,7 @@ Un groupe instructeur avec ces dossiers
|
|||
"""
|
||||
type GroupeInstructeurWithDossiers {
|
||||
"""
|
||||
Liste de tous les dossiers d'une démarche.
|
||||
Liste de tous les dossiers d’une démarche.
|
||||
"""
|
||||
dossiers(
|
||||
"""
|
||||
|
@ -858,7 +873,7 @@ type GroupeInstructeurWithDossiers {
|
|||
last: Int
|
||||
|
||||
"""
|
||||
L'ordre des dossiers.
|
||||
L’ordre des dossiers.
|
||||
"""
|
||||
order: Order = ASC
|
||||
|
||||
|
@ -1107,7 +1122,7 @@ type Query {
|
|||
): Demarche!
|
||||
|
||||
"""
|
||||
Informations sur un dossier d'une démarche.
|
||||
Informations sur un dossier d’une démarche.
|
||||
"""
|
||||
dossier(
|
||||
"""
|
||||
|
|
|
@ -14,8 +14,8 @@ module Types
|
|||
field :description, String, "Description du champ.", null: true
|
||||
field :required, Boolean, "Est-ce que le champ est obligatoire ?", null: false, method: :mandatory?
|
||||
|
||||
field :champ_descriptors, [Types::ChampDescriptorType], "Description des champs d'un bloc répétable.", null: true
|
||||
field :options, [String], "List des options d'un champ avec selection.", null: true
|
||||
field :champ_descriptors, [Types::ChampDescriptorType], "Description des champs d’un bloc répétable.", null: true
|
||||
field :options, [String], "List des options d’un champ avec selection.", null: true
|
||||
|
||||
def champ_descriptors
|
||||
if object.repetition?
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
module Types::Champs
|
||||
class PieceJustificativeChampType < Types::BaseObject
|
||||
include Rails.application.routes.url_helpers
|
||||
implements Types::ChampType
|
||||
|
||||
field :file, Types::File, null: true, extensions: [
|
||||
|
|
|
@ -20,8 +20,8 @@ module Types
|
|||
field :number, Int, "Le numero de la démarche.", null: false, method: :id
|
||||
field :title, String, "Le titre de la démarche.", null: false, method: :libelle
|
||||
field :description, String, "Description de la démarche.", null: false
|
||||
field :state, DemarcheState, "L'état de la démarche.", null: false
|
||||
field :declarative, DossierDeclarativeState, "L'état de dossier pour une démarche déclarative", null: true, method: :declarative_with_state
|
||||
field :state, DemarcheState, "L’état de la démarche.", null: false
|
||||
field :declarative, DossierDeclarativeState, "L’état de dossier pour une démarche déclarative", null: true, method: :declarative_with_state
|
||||
|
||||
field :date_creation, GraphQL::Types::ISO8601DateTime, "Date de la création.", null: false, method: :created_at
|
||||
field :date_publication, GraphQL::Types::ISO8601DateTime, "Date de la publication.", null: false, method: :published_at
|
||||
|
@ -32,8 +32,8 @@ module Types
|
|||
field :groupe_instructeurs, [Types::GroupeInstructeurType], null: false
|
||||
field :service, Types::ServiceType, null: false
|
||||
|
||||
field :dossiers, Types::DossierType.connection_type, "Liste de tous les dossiers d'une démarche.", null: false do
|
||||
argument :order, Types::Order, default_value: :asc, required: false, description: "L'ordre des dossiers."
|
||||
field :dossiers, Types::DossierType.connection_type, "Liste de tous les dossiers d’une démarche.", null: false do
|
||||
argument :order, Types::Order, default_value: :asc, required: false, description: "L’ordre des dossiers."
|
||||
argument :created_since, GraphQL::Types::ISO8601DateTime, required: false, description: "Dossiers déposés depuis la date."
|
||||
argument :updated_since, GraphQL::Types::ISO8601DateTime, required: false, description: "Dossiers mis à jour depuis la date."
|
||||
argument :state, Types::DossierType::DossierState, required: false, description: "Dossiers avec statut."
|
||||
|
|
|
@ -10,7 +10,7 @@ module Types
|
|||
|
||||
global_id_field :id
|
||||
field :number, Int, "Le numero du dossier.", null: false, method: :id
|
||||
field :state, DossierState, "L'état du dossier.", null: false
|
||||
field :state, DossierState, "L’état du dossier.", null: false
|
||||
|
||||
field :date_passage_en_construction, GraphQL::Types::ISO8601DateTime, "Date de dépôt.", null: false, method: :en_construction_at
|
||||
field :date_passage_en_instruction, GraphQL::Types::ISO8601DateTime, "Date de passage en instruction.", null: true, method: :en_instruction_at
|
||||
|
@ -24,6 +24,10 @@ module Types
|
|||
{ Extensions::Attachment => { attachment: :justificatif_motivation } }
|
||||
]
|
||||
|
||||
field :pdf, Types::File, "L’URL du dossier au format PDF.", null: true
|
||||
field :geojson, Types::File, "L’URL du GeoJSON contenant les données cartographiques du dossier.", null: true
|
||||
field :attestation, Types::File, "L’URL de l’attestation au format PDF.", null: true
|
||||
|
||||
field :usager, Types::ProfileType, null: false
|
||||
field :groupe_instructeur, Types::GroupeInstructeurType, null: false
|
||||
field :revision, Types::RevisionType, null: false
|
||||
|
@ -81,6 +85,30 @@ module Types
|
|||
Loaders::Association.for(object.class, :champs_private).load(object)
|
||||
end
|
||||
|
||||
def pdf
|
||||
sgid = object.to_sgid(expires_in: 1.hour, for: 'api_v2')
|
||||
{
|
||||
filename: "dossier-#{object.id}.pdf",
|
||||
content_type: 'application/pdf',
|
||||
url: Rails.application.routes.url_helpers.api_v2_dossier_pdf_url(id: sgid)
|
||||
}
|
||||
end
|
||||
|
||||
def geojson
|
||||
sgid = object.to_sgid(expires_in: 1.hour, for: 'api_v2')
|
||||
{
|
||||
filename: "dossier-#{object.id}-features.json",
|
||||
content_type: 'application/json',
|
||||
url: Rails.application.routes.url_helpers.api_v2_dossier_geojson_url(id: sgid)
|
||||
}
|
||||
end
|
||||
|
||||
def attestation
|
||||
if object.termine? && object.procedure.attestation_template&.activated?
|
||||
Loaders::Association.for(object.class, attestation: { pdf_attachment: :blob }).load(object).then(&:pdf)
|
||||
end
|
||||
end
|
||||
|
||||
def self.authorized?(object, context)
|
||||
authorized_demarche?(object.procedure, context)
|
||||
end
|
||||
|
|
|
@ -7,7 +7,11 @@ module Types
|
|||
field :content_type, String, null: false
|
||||
|
||||
def url
|
||||
if object.is_a?(Hash)
|
||||
object[:url]
|
||||
else
|
||||
object.service_url
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -2,8 +2,8 @@ module Types
|
|||
class GroupeInstructeurWithDossiersType < GroupeInstructeurType
|
||||
description "Un groupe instructeur avec ces dossiers"
|
||||
|
||||
field :dossiers, Types::DossierType.connection_type, "Liste de tous les dossiers d'une démarche.", null: false do
|
||||
argument :order, Types::Order, default_value: :asc, required: false, description: "L'ordre des dossiers."
|
||||
field :dossiers, Types::DossierType.connection_type, "Liste de tous les dossiers d’une démarche.", null: false do
|
||||
argument :order, Types::Order, default_value: :asc, required: false, description: "L’ordre des dossiers."
|
||||
argument :created_since, GraphQL::Types::ISO8601DateTime, required: false, description: "Dossiers déposés depuis la date."
|
||||
argument :updated_since, GraphQL::Types::ISO8601DateTime, required: false, description: "Dossiers mis à jour depuis la date."
|
||||
argument :state, Types::DossierType::DossierState, required: false, description: "Dossiers avec statut."
|
||||
|
|
|
@ -16,7 +16,7 @@ module Types
|
|||
field :siret_siege_social, String, null: false
|
||||
field :code_effectif_entreprise, String, null: true
|
||||
field :effectif_mensuel, EffectifType, null: true, description: "effectif pour un mois donné"
|
||||
field :effectif_annuel, EffectifType, null: true, description: "effectif moyen d'une année"
|
||||
field :effectif_annuel, EffectifType, null: true, description: "effectif moyen d’une année"
|
||||
field :date_creation, GraphQL::Types::ISO8601Date, null: false
|
||||
field :nom, String, null: false
|
||||
field :prenom, String, null: false
|
||||
|
|
|
@ -4,7 +4,7 @@ module Types
|
|||
argument :number, Int, "Numéro de la démarche.", required: true
|
||||
end
|
||||
|
||||
field :dossier, DossierType, null: false, description: "Informations sur un dossier d'une démarche." do
|
||||
field :dossier, DossierType, null: false, description: "Informations sur un dossier d’une démarche." do
|
||||
argument :number, Int, "Numéro du dossier.", required: true
|
||||
end
|
||||
|
||||
|
|
7
app/jobs/update_stats_job.rb
Normal file
7
app/jobs/update_stats_job.rb
Normal file
|
@ -0,0 +1,7 @@
|
|||
class UpdateStatsJob < CronJob
|
||||
self.schedule_expression = "every 1 hour"
|
||||
|
||||
def perform(*args)
|
||||
Stat.update_stats
|
||||
end
|
||||
end
|
|
@ -286,7 +286,7 @@ class Dossier < ApplicationRecord
|
|||
end
|
||||
|
||||
scope :for_procedure, -> (procedure) { includes(:user, :groupe_instructeur).where(groupe_instructeurs: { procedure: procedure }) }
|
||||
scope :for_api_v2, -> { includes(procedure: [:administrateurs], etablissement: [], individual: [], traitements: []) }
|
||||
scope :for_api_v2, -> { includes(procedure: [:administrateurs, :attestation_template], etablissement: [], individual: [], traitements: []) }
|
||||
|
||||
scope :with_notifications, -> do
|
||||
joins(:follows)
|
||||
|
|
93
app/models/stat.rb
Normal file
93
app/models/stat.rb
Normal file
|
@ -0,0 +1,93 @@
|
|||
# == Schema Information
|
||||
#
|
||||
# Table name: stats
|
||||
#
|
||||
# id :bigint not null, primary key
|
||||
# administrations_partenaires :bigint default(0)
|
||||
# dossiers_brouillon :bigint default(0)
|
||||
# dossiers_cumulative :jsonb not null
|
||||
# dossiers_depose_avant_30_jours :bigint default(0)
|
||||
# dossiers_deposes_entre_60_et_30_jours :bigint default(0)
|
||||
# dossiers_en_construction :bigint default(0)
|
||||
# dossiers_en_instruction :bigint default(0)
|
||||
# dossiers_in_the_last_4_months :jsonb not null
|
||||
# dossiers_not_brouillon :bigint default(0)
|
||||
# dossiers_termines :bigint default(0)
|
||||
# created_at :datetime not null
|
||||
# updated_at :datetime not null
|
||||
#
|
||||
class Stat < ApplicationRecord
|
||||
class << self
|
||||
def update_stats
|
||||
states = dossiers_states
|
||||
stat = Stat.first || Stat.new
|
||||
|
||||
stat.update(
|
||||
dossiers_en_construction: states['en_construction'],
|
||||
dossiers_en_instruction: states['en_instruction'],
|
||||
dossiers_brouillon: states['brouillon'],
|
||||
dossiers_depose_avant_30_jours: states['dossiers_depose_avant_30_jours'],
|
||||
dossiers_deposes_entre_60_et_30_jours: states['dossiers_deposes_entre_60_et_30_jours'],
|
||||
dossiers_not_brouillon: states['not_brouillon'],
|
||||
dossiers_termines: states['termines'],
|
||||
dossiers_cumulative: cumulative_hash(Dossier.state_not_brouillon, :en_construction_at),
|
||||
dossiers_in_the_last_4_months: last_four_months_hash(Dossier.state_not_brouillon, :en_construction_at),
|
||||
administrations_partenaires: AdministrateursProcedure.joins(:procedure).merge(Procedure.publiees_ou_closes).select('distinct administrateur_id').count
|
||||
)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def dossiers_states
|
||||
query = <<-EOF
|
||||
SELECT
|
||||
COUNT(*) FILTER ( WHERE state != 'brouillon' ) AS "not_brouillon",
|
||||
COUNT(*) FILTER ( WHERE state != 'brouillon' and en_construction_at BETWEEN :one_month_ago AND :now ) AS "dossiers_depose_avant_30_jours",
|
||||
COUNT(*) FILTER ( WHERE state != 'brouillon' and en_construction_at BETWEEN :two_months_ago AND :one_month_ago ) AS "dossiers_deposes_entre_60_et_30_jours",
|
||||
COUNT(*) FILTER ( WHERE state = 'brouillon' ) AS "brouillon",
|
||||
COUNT(*) FILTER ( WHERE state = 'en_construction' ) AS "en_construction",
|
||||
COUNT(*) FILTER ( WHERE state = 'en_instruction' ) AS "en_instruction",
|
||||
COUNT(*) FILTER ( WHERE state in ('accepte', 'refuse', 'sans_suite') ) AS "termines"
|
||||
FROM dossiers
|
||||
WHERE hidden_at IS NULL
|
||||
EOF
|
||||
|
||||
sanitized_query = ActiveRecord::Base.sanitize_sql([
|
||||
query,
|
||||
now: Time.zone.now,
|
||||
one_month_ago: 1.month.ago,
|
||||
two_months_ago: 2.months.ago
|
||||
])
|
||||
|
||||
Dossier.connection.select_all(sanitized_query).first
|
||||
end
|
||||
|
||||
def last_four_months_hash(association, date_attribute)
|
||||
min_date = 3.months.ago.beginning_of_month.to_date
|
||||
|
||||
association
|
||||
.where(date_attribute => min_date..max_date)
|
||||
.group("DATE_TRUNC('month', #{date_attribute})")
|
||||
.count
|
||||
.to_a
|
||||
.sort_by { |a| a[0] }
|
||||
.map { |e| [I18n.l(e.first, format: "%B %Y"), e.last] }
|
||||
end
|
||||
|
||||
def cumulative_hash(association, date_attribute)
|
||||
sum = 0
|
||||
association
|
||||
.where("#{date_attribute} < ?", max_date)
|
||||
.group("DATE_TRUNC('month', #{date_attribute})")
|
||||
.count
|
||||
.to_a
|
||||
.sort_by { |a| a[0] }
|
||||
.map { |x, y| { x => (sum += y) } }
|
||||
.reduce({}, :merge)
|
||||
end
|
||||
|
||||
def max_date
|
||||
Time.zone.now.beginning_of_month - 1.second
|
||||
end
|
||||
end
|
||||
end
|
|
@ -19,6 +19,6 @@
|
|||
propre à votre démarche.
|
||||
|
||||
= f.label :api_entreprise_token, "Jeton"
|
||||
= f.password_field :api_entreprise_token, class: 'form-control'
|
||||
= f.password_field :api_entreprise_token, value: @procedure.read_attribute(:api_entreprise_token), class: 'form-control'
|
||||
.text-right
|
||||
= f.button 'Enregistrer', class: 'button primary send'
|
||||
|
|
|
@ -77,7 +77,7 @@
|
|||
Choix du service administratif
|
||||
.card-admin-action
|
||||
- if @procedure.service.present?
|
||||
= link_to 'Modifier', edit_admin_service_path(@procedure.service), class: 'button'
|
||||
= link_to 'Modifier', edit_admin_service_path(@procedure.service, procedure_id: @procedure.id), class: 'button'
|
||||
- elsif current_administrateur.services.present?
|
||||
= link_to 'Choisir', admin_services_path(procedure_id: @procedure.id), class: 'button'
|
||||
- else
|
||||
|
|
|
@ -43,14 +43,14 @@
|
|||
%ul.numbers
|
||||
%li.number
|
||||
.number-value
|
||||
= number_with_delimiter(AdministrateursProcedure.joins(:procedure).merge(Procedure.publiees_ou_closes).select('distinct administrateur_id').count, :locale => :fr)
|
||||
= number_with_delimiter(@stat&.administrations_partenaires, :locale => :fr)
|
||||
.number-label<
|
||||
administrations
|
||||
%br<>
|
||||
partenaires
|
||||
%li.number
|
||||
.number-value
|
||||
= number_with_delimiter(Dossier.state_not_brouillon.count, :locale => :fr)
|
||||
= number_with_delimiter(@stat&.dossiers_not_brouillon, :locale => :fr)
|
||||
.number-label<
|
||||
dossiers
|
||||
%br<>
|
||||
|
|
|
@ -55,7 +55,7 @@
|
|||
|
||||
.chart-container
|
||||
.chart
|
||||
= pie_chart @dossiers_states,
|
||||
= pie_chart @dossiers_states_for_pie,
|
||||
colors: ["rgba(222, 238, 265, 1)", "rgba(191, 220, 249, 1)", "rgba(113, 176, 239, 1)", "rgba(61, 149, 236, 1)"]
|
||||
|
||||
.stat-card.stat-card-half.pull-left
|
||||
|
|
|
@ -222,6 +222,8 @@ Rails.application.routes.draw do
|
|||
|
||||
namespace :v2 do
|
||||
post :graphql, to: "graphql#execute"
|
||||
get 'dossiers/pdf/:id', format: :pdf, to: "dossiers#pdf", as: :dossier_pdf
|
||||
get 'dossiers/geojson/:id', to: "dossiers#geojson", as: :dossier_geojson
|
||||
end
|
||||
end
|
||||
|
||||
|
|
19
db/migrate/20201002124154_create_stats.rb
Normal file
19
db/migrate/20201002124154_create_stats.rb
Normal file
|
@ -0,0 +1,19 @@
|
|||
class CreateStats < ActiveRecord::Migration[6.0]
|
||||
def change
|
||||
create_table :stats do |t|
|
||||
t.bigint :dossiers_not_brouillon, default: 0
|
||||
t.bigint :dossiers_brouillon, default: 0
|
||||
t.bigint :dossiers_en_construction, default: 0
|
||||
t.bigint :dossiers_en_instruction, default: 0
|
||||
t.bigint :dossiers_termines, default: 0
|
||||
t.bigint :dossiers_depose_avant_30_jours, default: 0
|
||||
t.bigint :dossiers_deposes_entre_60_et_30_jours, default: 0
|
||||
t.bigint :administrations_partenaires, default: 0
|
||||
|
||||
t.jsonb :dossiers_cumulative, null: false, default: '{}'
|
||||
t.jsonb :dossiers_in_the_last_4_months, null: false, default: '{}'
|
||||
|
||||
t.timestamps
|
||||
end
|
||||
end
|
||||
end
|
17
db/schema.rb
17
db/schema.rb
|
@ -10,7 +10,7 @@
|
|||
#
|
||||
# It's strongly recommended that you check this file into your version control system.
|
||||
|
||||
ActiveRecord::Schema.define(version: 2020_09_30_143755) do
|
||||
ActiveRecord::Schema.define(version: 2020_10_02_124154) do
|
||||
|
||||
# These are extensions that must be enabled in order to support this database
|
||||
enable_extension "plpgsql"
|
||||
|
@ -586,6 +586,21 @@ ActiveRecord::Schema.define(version: 2020_09_30_143755) do
|
|||
t.index ["administrateur_id"], name: "index_services_on_administrateur_id"
|
||||
end
|
||||
|
||||
create_table "stats", force: :cascade do |t|
|
||||
t.bigint "dossiers_not_brouillon", default: 0
|
||||
t.bigint "dossiers_brouillon", default: 0
|
||||
t.bigint "dossiers_en_construction", default: 0
|
||||
t.bigint "dossiers_en_instruction", default: 0
|
||||
t.bigint "dossiers_termines", default: 0
|
||||
t.bigint "dossiers_depose_avant_30_jours", default: 0
|
||||
t.bigint "dossiers_deposes_entre_60_et_30_jours", default: 0
|
||||
t.bigint "administrations_partenaires", default: 0
|
||||
t.jsonb "dossiers_cumulative", default: "{}", null: false
|
||||
t.jsonb "dossiers_in_the_last_4_months", default: "{}", null: false
|
||||
t.datetime "created_at", precision: 6, null: false
|
||||
t.datetime "updated_at", precision: 6, null: false
|
||||
end
|
||||
|
||||
create_table "task_records", id: false, force: :cascade do |t|
|
||||
t.string "version", null: false
|
||||
end
|
||||
|
|
11
lib/tasks/deployment/20201006123842_setup_first_stats.rake
Normal file
11
lib/tasks/deployment/20201006123842_setup_first_stats.rake
Normal file
|
@ -0,0 +1,11 @@
|
|||
namespace :after_party do
|
||||
desc 'Deployment task: setup_first_stats'
|
||||
task setup_first_stats: :environment do
|
||||
Stat.update_stats
|
||||
|
||||
# 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: AfterParty::TaskRecorder.new(__FILE__).timestamp
|
||||
end
|
||||
end
|
38
spec/controllers/api/v2/dossiers_controller_spec.rb
Normal file
38
spec/controllers/api/v2/dossiers_controller_spec.rb
Normal file
|
@ -0,0 +1,38 @@
|
|||
describe API::V2::DossiersController do
|
||||
let(:dossier) { create(:dossier, :accepte, :with_attestation) }
|
||||
let(:sgid) { dossier.to_sgid(expires_in: 1.hour, for: 'api_v2') }
|
||||
|
||||
describe 'fetch pdf' do
|
||||
subject { get :pdf, params: { id: sgid } }
|
||||
|
||||
it 'should get' do
|
||||
expect(subject.status).to eq(200)
|
||||
expect(subject.body).not_to be_nil
|
||||
end
|
||||
|
||||
context 'error' do
|
||||
let(:sgid) { 'yolo' }
|
||||
|
||||
it 'should error' do
|
||||
expect(subject.status).to eq(401)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'fetch geojson' do
|
||||
subject { get :geojson, params: { id: sgid } }
|
||||
|
||||
it 'should get' do
|
||||
expect(subject.status).to eq(200)
|
||||
expect(subject.body).not_to be_nil
|
||||
end
|
||||
|
||||
context 'error' do
|
||||
let(:sgid) { 'yolo' }
|
||||
|
||||
it 'should error' do
|
||||
expect(subject.status).to eq(401)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -436,6 +436,35 @@ describe API::V2::GraphqlController do
|
|||
end
|
||||
end
|
||||
|
||||
context "with links" do
|
||||
let(:dossier) { create(:dossier, :accepte, :with_attestation, procedure: procedure) }
|
||||
let(:query) do
|
||||
"{
|
||||
dossier(number: #{dossier.id}) {
|
||||
id
|
||||
number
|
||||
pdf {
|
||||
url
|
||||
}
|
||||
geojson {
|
||||
url
|
||||
}
|
||||
attestation {
|
||||
url
|
||||
}
|
||||
}
|
||||
}"
|
||||
end
|
||||
|
||||
it "urls should be returned" do
|
||||
expect(gql_errors).to eq(nil)
|
||||
|
||||
expect(gql_data[:dossier][:pdf][:url]).not_to be_nil
|
||||
expect(gql_data[:dossier][:geojson][:url]).not_to be_nil
|
||||
expect(gql_data[:dossier][:attestation][:url]).not_to be_nil
|
||||
end
|
||||
end
|
||||
|
||||
context "when there are missing data" do
|
||||
before do
|
||||
dossier.etablissement.update!(entreprise_code_effectif_entreprise: nil, entreprise_capital_social: nil,
|
||||
|
|
Loading…
Reference in a new issue