Commit 0105f357 authored by David F.'s avatar David F.
Browse files

Merge branch '86-stats-admin-saison' into 'master'

Resolve "[Admin] Archivage des adhésions par saison sportive"

See merge request CDSA33/OLIGAA!94
parents 20627052 4e510f0e
...@@ -65,6 +65,7 @@ ...@@ -65,6 +65,7 @@
@import "emails"; @import "emails";
@import "partners"; @import "partners";
@import "events"; @import "events";
@import "platform";
.danger { .danger {
color: $oligaa-red; color: $oligaa-red;
......
...@@ -44,29 +44,27 @@ form#search_contacts_form { ...@@ -44,29 +44,27 @@ form#search_contacts_form {
} }
} }
aside#subscriptions { div#internal, div#external, div#subscriptions-by-club, div#subscriptions-by-org {
div { padding: 0 1em;
padding: 0 1em;
a.expendable { a.expendable {
display: block; display: block;
} }
ul { ul {
padding: 0.5em 0; padding: 0.5em 0;
li.subscription { li.subscription {
span { span {
padding: 0 0.5em; padding: 0 0.5em;
&.billed { @include button-color($oligaa-green); } &.billed { @include button-color($oligaa-green); }
&.not-billed { @include button-color; } &.not-billed { @include button-color; }
&.platform-number { font: caption;} &.platform-number { font: caption;}
&.activities { &.activities {
display: none; display: none;
}
} }
i.fa-info-circle:hover + span.activities { display: block;}
} }
i.fa-info-circle:hover + span.activities { display: block;}
} }
} }
} }
form#season-selector {
margin: 0.5em auto;
text-align: center;
label {
display: inline-block;
}
}
div#admin-platform {
h3 a {
color: inherit;
}
}
...@@ -23,16 +23,19 @@ class PlatformController < ApplicationController ...@@ -23,16 +23,19 @@ class PlatformController < ApplicationController
before_action :authorize before_action :authorize
def index def index
@collaborating_clubs = Member.of_member_groups(settings.platform_collaborating_clubs).by_name if session[:season] = params[:season]
@orgs_in_db_by_name = Member.of_member_groups(settings.platform_medicosocial_orgs).by_name @season = Season.from_short_label(params[:season])
@orgs_in_db = {} @collaborating_clubs = Member.of_member_groups(settings.platform_collaborating_clubs).by_name
@orgs_in_db_by_name.each do |org| @orgs_in_db_by_name = Member.of_member_groups(settings.platform_medicosocial_orgs).by_name
subscriptions = Subscription.of_medicosocial_org(org).by_adherent_name @orgs_in_db = {}
@orgs_in_db[org] = subscriptions unless subscriptions.empty? @orgs_in_db_by_name.each do |org|
end subscriptions = Subscription.for_season(@season).of_medicosocial_org(org).by_adherent_name.all
@orgs_not_in_db = {} @orgs_in_db[org] = subscriptions unless subscriptions.empty?
Adherent.where.not(other_medicosocial_org: nil).group(:other_medicosocial_org).order(:other_medicosocial_org).count.each do |org_name, result| end
@orgs_not_in_db[Member.new({name: org_name})] = Subscription.joins(:adherent).where(adherents: {other_medicosocial_org: org_name}).by_adherent_name.all @orgs_not_in_db = {}
Adherent.where.not(other_medicosocial_org: nil).group(:other_medicosocial_org).order(:other_medicosocial_org).count.each do |org_name, result|
@orgs_not_in_db[Member.new({name: org_name})] = Subscription.for_season(@season).joins(:adherent).where(adherents: {other_medicosocial_org: org_name}).by_adherent_name.all
end
end end
end end
end end
...@@ -118,7 +118,7 @@ class SubscriptionsController < ApplicationController ...@@ -118,7 +118,7 @@ class SubscriptionsController < ApplicationController
def toggle_billing def toggle_billing
@subscription.toggle_billing @subscription.toggle_billing
redirect_to platform_path, notice: "L'adhésion a bien été #{@subscription.billed_at ? '' : 'dé'}facturée." redirect_to platform_path(season: session[:season]), notice: "L'adhésion a bien été #{@subscription.billed_at ? '' : 'dé'}facturée."
end end
private private
......
...@@ -21,7 +21,7 @@ ...@@ -21,7 +21,7 @@
# along with OLIGAA. If not, see <http://www.gnu.org/licenses/>. # along with OLIGAA. If not, see <http://www.gnu.org/licenses/>.
# #
class Adherent < ApplicationRecord class Adherent < ApplicationRecord
has_many :subscriptions, dependent: :destroy has_many :subscriptions
belongs_to :medico_social_org, class_name: 'Member', optional: true belongs_to :medico_social_org, class_name: 'Member', optional: true
validates :last_name, :first_name, :born_on, :permit_number, presence: true validates :last_name, :first_name, :born_on, :permit_number, presence: true
......
...@@ -24,6 +24,16 @@ class Season ...@@ -24,6 +24,16 @@ class Season
FIRST_MONTH = 8 FIRST_MONTH = 8
FIRST_DAY = 15 FIRST_DAY = 15
attr_reader :beginning
attr_reader :end
def initialize(date)
year = (date < Season.birthdate.change(year: date.year) ? date.year-1 : date.year)
@beginning = Season.birthdate.change(year: year)
@end = @beginning + 1.year - 1.day
return self
end
def self.default_birthdate def self.default_birthdate
Date.new(1970,FIRST_MONTH, FIRST_DAY) Date.new(1970,FIRST_MONTH, FIRST_DAY)
end end
...@@ -32,6 +42,19 @@ class Season ...@@ -32,6 +42,19 @@ class Season
Settings.instance.reload.season_birthdate || self.default_birthdate Settings.instance.reload.season_birthdate || self.default_birthdate
end end
def self.all(klass, date_field=:begin_at)
min_year = klass.send(:minimum, date_field).try(:year)
max_year = klass.send(:maximum, date_field).try(:year)
return [] unless min_year && max_year
[].tap do |years|
(min_year..max_year).each do |year|
season = self.new(self.birthdate.change(year: year))
years << season.short_label
end
end
end
def self.all_for(items, date_field=:begin_at) def self.all_for(items, date_field=:begin_at)
result = {} result = {}
items.each do |item| items.each do |item|
...@@ -45,18 +68,24 @@ class Season ...@@ -45,18 +68,24 @@ class Season
result.sort.reverse result.sort.reverse
end end
def initialize(date) def self.from_short_label(label)
year = (date < Season.birthdate.change(year: date.year) ? date.year-1 : date.year) self.new(self.birthdate.change(year: label.split('-').first.to_i))
@begining = Season.birthdate.change(year: year) end
return self
def self.from_label(label)
self.from_short_label(label.gsub(/Saison /,''))
end end
def shorten def shorten
shorten_year = @begining.year.% 100 shorten_year = @beginning.year.% 100
"#{shorten_year}#{shorten_year+1}" "#{shorten_year}#{shorten_year+1}"
end end
def short_label
"#{@beginning.year}-#{@beginning.year+1}"
end
def label def label
"Saison #{@begining.year}-#{@begining.year+1}" "Saison #{short_label}"
end end
end end
...@@ -22,8 +22,8 @@ ...@@ -22,8 +22,8 @@
# #
class Statistics::Billing::Global class Statistics::Billing::Global
def initialize(members) def initialize(members, season)
@member_units = members.map { |member| Statistics::Billing::Unit.new(member) } @member_units = members.map { |member| Statistics::Billing::Unit.new(member, season) }
end end
def total def total
......
...@@ -22,19 +22,20 @@ ...@@ -22,19 +22,20 @@
# #
class Statistics::Billing::Unit class Statistics::Billing::Unit
def initialize(member) def initialize(member, season)
@member = member @member = member
@season = season
end end
def total def total
check_collaboration_or_return(0) do check_collaboration_or_return(0) do
@member.subscriptions.with_multiactivities_pass.length @member.subscriptions.for_season(@season).with_multiactivities_pass.length
end end
end end
def billed def billed
check_collaboration_or_return(0) do check_collaboration_or_return(0) do
@member.subscriptions.billed.count @member.subscriptions.for_season(@season).billed.count
end end
end end
......
...@@ -22,8 +22,8 @@ ...@@ -22,8 +22,8 @@
# #
class Statistics::Pass::Global class Statistics::Pass::Global
def initialize(members) def initialize(members, season)
@member_units = members.map { |member| Statistics::Pass::Unit.new(member) } @member_units = members.map { |member| Statistics::Pass::Unit.new(member, season) }
end end
def total def total
......
...@@ -22,15 +22,16 @@ ...@@ -22,15 +22,16 @@
# #
class Statistics::Pass::Unit class Statistics::Pass::Unit
def initialize(member) def initialize(member, season)
@member = member @member = member
@season = season
end end
def total def total
return_values = { return_values = {
none: 0, none: 0,
club: @member.subscriptions.count, club: @member.subscriptions.for_season(@season).count,
medicosocial_org: Subscription.of_medicosocial_org(@member).count medicosocial_org: Subscription.for_season(@season).of_medicosocial_org(@member).count
} }
check_collaboration_or_return(return_values) check_collaboration_or_return(return_values)
end end
...@@ -38,8 +39,8 @@ class Statistics::Pass::Unit ...@@ -38,8 +39,8 @@ class Statistics::Pass::Unit
def multi def multi
return_values = { return_values = {
none: 0, none: 0,
club: @member.subscriptions.with_multiactivities_pass.length, club: @member.subscriptions.for_season(@season).with_multiactivities_pass.length,
medicosocial_org: Subscription.of_medicosocial_org(@member).with_multiactivities_pass.length medicosocial_org: Subscription.for_season(@season).of_medicosocial_org(@member).with_multiactivities_pass.length
} }
check_collaboration_or_return(return_values) check_collaboration_or_return(return_values)
end end
......
...@@ -22,17 +22,19 @@ ...@@ -22,17 +22,19 @@
# #
class Subscription < ApplicationRecord class Subscription < ApplicationRecord
belongs_to :member belongs_to :member
belongs_to :adherent, dependent: :destroy belongs_to :adherent
accepts_nested_attributes_for :adherent accepts_nested_attributes_for :adherent
has_many :performance_subscriptions, dependent: :destroy has_many :performance_subscriptions, dependent: :destroy
has_many :performances, through: :performance_subscriptions has_many :performances, through: :performance_subscriptions
after_create :set_platform_number after_create :set_platform_number
before_destroy :destroy_adherent_if_necessary
scope :for_performances, ->(performance_ids) { joins(:performances).where(performance_subscriptions: {performance_id: performance_ids}).distinct } scope :for_performances, ->(performance_ids) { joins(:performances).where(performance_subscriptions: {performance_id: performance_ids}).distinct }
scope :by_adherent_name, -> { joins(:adherent).order('adherents.first_name','adherents.last_name') } scope :by_adherent_name, -> { joins(:adherent).order('adherents.first_name','adherents.last_name') }
scope :billed, -> { where.not(billed_at: nil) } scope :billed, -> { where.not(billed_at: nil) }
scope :of_medicosocial_org, ->(member) { joins(:adherent).where(adherents: {medico_social_org: member}) } scope :of_medicosocial_org, ->(member) { joins(:adherent).where(adherents: {medico_social_org: member}) }
scope :for_season, ->(season) { where(created_at: (season.beginning..season.end) )}
def self.with_multiactivities_pass def self.with_multiactivities_pass
all.reject { |sub| !sub.multipass? } all.reject { |sub| !sub.multipass? }
...@@ -69,4 +71,8 @@ class Subscription < ApplicationRecord ...@@ -69,4 +71,8 @@ class Subscription < ApplicationRecord
def set_platform_number def set_platform_number
self.update_attribute(:platform_number, SubscriptionNumber.new(self).label) self.update_attribute(:platform_number, SubscriptionNumber.new(self).label)
end end
def destroy_adherent_if_necessary
adherent.destroy if Subscription.where(adherent: self.adherent).count == 1
end
end end
...@@ -35,12 +35,12 @@ ...@@ -35,12 +35,12 @@
<%- end %> <%- end %>
<h2> <h2>
Nos adhérents Nos adhérents
<span><%= Statistics::Pass::Unit.new(@member).label %></span>
</h2> </h2>
<div id="internal"> <div id="internal">
<%- @seasoned_internal_subscriptions.each do |season, subscriptions| %> <%- @seasoned_internal_subscriptions.each do |season, subscriptions| %>
<% season_label = season.downcase.gsub(/\s/, '_') + "_int" %> <% season_label = season.downcase.gsub(/\s/, '_') + "_int" %>
<%= toggle_link "#{ season } (#{ subscriptions.length })", "##{season_label}" %> <%= toggle_link "#{ season } #{Statistics::Pass::Unit.new(@member, Season.from_label(season)).label}", "##{season_label}" %>
<%= %>
<ul id="<%= season_label %>" style="display:none;"> <ul id="<%= season_label %>" style="display:none;">
<% subscriptions.each do |subscription| %> <% subscriptions.each do |subscription| %>
<li class="subscription"> <li class="subscription">
......
...@@ -22,7 +22,14 @@ ...@@ -22,7 +22,14 @@
%> %>
<% title "Plateforme Sports et Troubles psychiques" %> <% title "Plateforme Sports et Troubles psychiques" %>
<div class="tabs"> <%= form_tag platform_path, method: :get, id: "season-selector" do %>
<%= label_tag :season, "Saison" %>
<%= select_tag :season, options_for_select(Season.all(Subscription, :created_at).reverse, params[:season]) %>
<%= submit_tag "Afficher" %>
<% end %>
<% if @season %>
<div id="admin-platform" class="tabs">
<ul> <ul>
<li><a href="#subscriptions-by-club">Adhésions par club</a></li> <li><a href="#subscriptions-by-club">Adhésions par club</a></li>
<li><a href="#subscriptions-by-org">Adhésions par structure</a></li> <li><a href="#subscriptions-by-org">Adhésions par structure</a></li>
...@@ -30,17 +37,17 @@ ...@@ -30,17 +37,17 @@
<div id="subscriptions-by-club"> <div id="subscriptions-by-club">
<h2> <h2>
Liste des adhésions par club partenaire Liste des adhésions par club partenaire
<span><%= Statistics::Pass::Global.new(@collaborating_clubs.to_a).label %></span> <span><%= Statistics::Pass::Global.new(@collaborating_clubs.to_a, @season).label %></span>
<span><%= Statistics::Billing::Global.new(@collaborating_clubs.to_a).label %></span> <span><%= Statistics::Billing::Global.new(@collaborating_clubs.to_a, @season).label %></span>
</h2> </h2>
<%- @collaborating_clubs.each do |club| %> <%- @collaborating_clubs.each do |club| %>
<h3> <h3>
<%= club.name %> <%= link_to club.name, club %>
<span><%= Statistics::Pass::Unit.new(club).label %></span> <span><%= Statistics::Pass::Unit.new(club, @season).label %></span>
<span><%= Statistics::Billing::Unit.new(club).label %></span> <span><%= Statistics::Billing::Unit.new(club, @season).label %></span>
</h3> </h3>
<ul id="member-<%= club.id %>"> <ul id="member-<%= club.id %>">
<%- club.subscriptions.by_adherent_name.each do |subscription| %> <%- club.subscriptions.for_season(@season).by_adherent_name.each do |subscription| %>
<li class="subscription"> <li class="subscription">
<%= custom_edit_link edit_member_subscription_path(club, subscription), :short, class: %w(tight) %> <%= custom_edit_link edit_member_subscription_path(club, subscription), :short, class: %w(tight) %>
<%= custom_bill_link toggle_billing_member_subscription_path(club, subscription), :short, class: ['tight', subscription.billing_status] if subscription.multipass? %> <%= custom_bill_link toggle_billing_member_subscription_path(club, subscription), :short, class: ['tight', subscription.billing_status] if subscription.multipass? %>
...@@ -54,13 +61,13 @@ ...@@ -54,13 +61,13 @@
<div id="subscriptions-by-org"> <div id="subscriptions-by-org">
<h2> <h2>
Liste des adhésions par structure Liste des adhésions par structure
<span><%= Statistics::Pass::Global.new(@orgs.to_a).label %></span> <span><%= Statistics::Pass::Global.new(@orgs.to_a, @season).label %></span>
</h2> </h2>
<h3>Structures référencées</h3> <h3>Structures référencées</h3>
<%- @orgs_in_db.each do |org, subscriptions| %> <%- @orgs_in_db.each do |org, subscriptions| %>
<h4> <h4>
<%= org.name %> <%= link_to org.name, org %>
<span><%= Statistics::Pass::Unit.new(org).label %></span> <span><%= Statistics::Pass::Unit.new(org, @season).label %></span>
</h4> </h4>
<ul id="member-<%= org.id %>"> <ul id="member-<%= org.id %>">
<%= render partial: 'subscription', collection: subscriptions %> <%= render partial: 'subscription', collection: subscriptions %>
...@@ -70,7 +77,7 @@ ...@@ -70,7 +77,7 @@
<%- @orgs_not_in_db.each do |org, subscriptions| %> <%- @orgs_not_in_db.each do |org, subscriptions| %>
<h4> <h4>
<%= org.name %> <%= org.name %>
<span><%= Statistics::Pass::Unit.new(org).label %></span> <span><%= Statistics::Pass::Unit.new(org, @season).label %></span>
</h4> </h4>
<ul id="member-<%= org.name.crypt('name').gsub('/','') %>"> <ul id="member-<%= org.name.crypt('name').gsub('/','') %>">
<%= render partial: 'subscription', collection: subscriptions %> <%= render partial: 'subscription', collection: subscriptions %>
...@@ -78,3 +85,4 @@ ...@@ -78,3 +85,4 @@
<%- end %> <%- end %>
</div> </div>
</div> </div>
<% end %>
...@@ -150,6 +150,14 @@ feature "Manage subscriptions" do ...@@ -150,6 +150,14 @@ feature "Manage subscriptions" do
within "nav#admin_links" do within "nav#admin_links" do
click_link "Plateforme" click_link "Plateforme"
end end
expect(page).not_to have_selector("div#subscriptions-by-club")
within "form#season-selector" do
select "2017-2018", from: "Saison"
click_button "Afficher"
end
expect(current_path).to eq platform_path
click_link "Adhésions par club" click_link "Adhésions par club"
expect(page).to have_selector("h2", text: "Liste des adhésions par club partenaire") expect(page).to have_selector("h2", text: "Liste des adhésions par club partenaire")
...@@ -184,7 +192,8 @@ feature "Manage subscriptions" do ...@@ -184,7 +192,8 @@ feature "Manage subscriptions" do
nb_club2_mono = 4.times { create :subscription, performances: [perf1], member_id: club2.id } nb_club2_mono = 4.times { create :subscription, performances: [perf1], member_id: club2.id }
nb_club2_multi = 6.times { create :subscription, performances: [perf1, perf2], member_id: club2.id } nb_club2_multi = 6.times { create :subscription, performances: [perf1, perf2], member_id: club2.id }
visit platform_path visit platform_path(season: "2017-2018")
expect(current_path).to eq platform_path
within "h3", text: "USG" do within "h3", text: "USG" do
expect(page).to have_selector("span", text: "(3 multi, 5 mono sur 8)") expect(page).to have_selector("span", text: "(3 multi, 5 mono sur 8)")
end end
...@@ -204,10 +213,13 @@ feature "Manage subscriptions" do ...@@ -204,10 +213,13 @@ feature "Manage subscriptions" do
perf2 = create :performance, member: usg perf2 = create :performance, member: usg
jean_dupont = build :adherent, last_name: "Dupont", first_name: "Jean" jean_dupont = build :adherent, last_name: "Dupont", first_name: "Jean"
pascal_durand = build :adherent, last_name: "Durand", first_name: "Pascal" pascal_durand = build :adherent, last_name: "Durand", first_name: "Pascal"
create :subscription, adherent: jean_dupont, performances: [perf1, perf2], member_id: usg.id create :subscription, adherent: jean_dupont, performances: [perf1, perf2], member_id: usg.id, created_at: "15/09/2017"
create :subscription, adherent: pascal_durand, performances: [perf1], member_id: usg.id create :subscription, adherent: pascal_durand, performances: [perf1], member_id: usg.id, created_at: "15/09/2017"
visit platform_path(season: "2017-2018")
expect(current_path).to eq platform_path
visit platform_path click_link "Adhésions par club"
within "h2", text: "Liste des adhésions par club partenaire" do within "h2", text: "Liste des adhésions par club partenaire" do
expect(page).to have_selector("span", text: "(€ : 0 / 1)") expect(page).to have_selector("span", text: "(€ : 0 / 1)")
end end
...@@ -270,15 +282,12 @@ feature "Manage subscriptions" do ...@@ -270,15 +282,12 @@ feature "Manage subscriptions" do
pascal_durand = build :adherent, last_name: "Durand", first_name: "Pascal", medico_social_org: ime_machin pascal_durand = build :adherent, last_name: "Durand", first_name: "Pascal", medico_social_org: ime_machin
arthur_latrouille = build :adherent, last_name: "Latrouille", first_name: "Arthur", medico_social_org: nil, other_medicosocial_org: "IME Bidule" arthur_latrouille = build :adherent, last_name: "Latrouille", first_name: "Arthur", medico_social_org: nil, other_medicosocial_org: "IME Bidule"
igor_jovovitch = build :adherent, last_name: "Jovovitch", first_name: "Igor", medico_social_org: nil, other_medicosocial_org: "IME Bidule" igor_jovovitch = build :adherent, last_name: "Jovovitch", first_name: "Igor", medico_social_org: nil, other_medicosocial_org: "IME Bidule"
create :subscription, adherent: jean_dupont, performances: [perf1, perf2], member_id: usg.id create :subscription, adherent: jean_dupont, performances: [perf1, perf2], member_id: usg.id, created_at: "15/09/2017"
create :subscription, adherent: pascal_durand, performances: [perf1], member_id: usg.id create :subscription, adherent: pascal_durand, performances: [perf1], member_id: usg.id, created_at: "15/09/2017"
create :subscription, adherent: arthur_latrouille, performances: [perf1, perf2], member_id: usg.id create :subscription, adherent: arthur_latrouille, performances: [perf1, perf2], member_id: usg.id, created_at: "15/09/2017"
create :subscription, adherent: igor_jovovitch, performances: [perf2], member_id: usg.id create :subscription, adherent: igor_jovovitch, performances: [perf2], member_id: usg.id, created_at: "15/09/2017"
visit root_path visit platform_path(season: "2017-2018")
within "nav#admin_links" do
click_link "Plateforme"
end
click_link "Adhésions par structure" click_link "Adhésions par structure"
expect(page).to have_selector("h2", text: "Liste des adhésions par structure")