Commit 47634225 authored by David F.'s avatar David F.

Merge branch '59-list-subscriptions-by-medicosocial-org' into 'master'

Resolve "Listing des Adhérents de la plateforme par Structures Sanitaires/MédicoSociale partenaires"

See merge request !67
parents 64e8ee8d 333a7ec5
......@@ -92,8 +92,12 @@ class MembersController < ApplicationController
member = Member.includes(:contacts).where(id: params[:id]).first
if !member.nil? && member.published? || member == current_member || admin?
@member = member
@internal_subscriptions = @member.subscriptions
@external_subscriptions = Subscription.for_performances(@member.performance_ids) - @internal_subscriptions
if @member.collaborating_club?
@internal_subscriptions = @member.subscriptions
@external_subscriptions = Subscription.for_performances(@member.performance_ids) - @internal_subscriptions
elsif @member.collaborating_medicosocial_org?
@internal_subscriptions = Subscription.of_medicosocial_org(@member).by_adherent_name
end
else
authorize
end
......
......@@ -24,5 +24,10 @@ class PlatformController < ApplicationController
def index
@collaborating_clubs = Member.of_member_groups(settings.platform_collaborating_clubs).by_name
@orgs_in_db = Member.of_member_groups(settings.platform_medicosocial_orgs).by_name
@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.joins(:adherent).where(adherents: {other_medicosocial_org: org_name}).by_adherent_name.all
end
end
end
......@@ -22,16 +22,20 @@
#
module AuthorizationsHelper
def can_manage_performances?(member)
admin_or_collaborator?(member)
admin_or_collaborating_club?(member)
end
def can_manage_susbscriptions?(member)
admin_or_collaborator?(member)
admin_or_collaborating_club?(member)
end
def can_see_subscriptions?(member)
admin? || (member.collaborating_medicosocial_org? && member == current_member)
end
private
def admin_or_collaborator?(member)
member.collaborator? && (admin? || member == current_member)
def admin_or_collaborating_club?(member)
admin? || (member.collaborating_club? && member == current_member)
end
end
class BillingStatistics
def initialize(members)
@members = (members.is_a?(Array) ? members : [members])
end
def total
check_collaboration_or_return do
sum = 0
@members.each do |member|
number = member.collaborator? ? member.subscriptions.with_multiactivities_pass.length : nil
sum += number if number
end
sum
end
end
def billed
check_collaboration_or_return do
sum = 0
@members.each do |member|
number = member.collaborator? ? member.subscriptions.billed.count : nil
sum += number if number
end
sum
end
end
def label
check_collaboration_or_return do
"(€ : #{billed} / #{total})"
end
end
private
def check_collaboration_or_return
return nil if @members.all? { |member| !member.collaborator? }
yield
end
end
......@@ -91,12 +91,24 @@ class Member < ApplicationRecord
self.update_column(:longitude, nil)
end
def collaborator?
def collaborating_club?
Settings.instance.reload.platform_collaborating_clubs.any? do |member_group|
self.member_groups.include?(member_group)
end
end
def collaborating_medicosocial_org?
Settings.instance.reload.platform_collaborating_medicosocial_orgs.any? do |member_group|
self.member_groups.include?(member_group)
end
end
def medicosocial_org?
Settings.instance.reload.platform_medicosocial_orgs.any? do |member_group|
self.member_groups.include?(member_group)
end
end
# Presenters
def admin_label
......
class PassStatistics
def initialize(members)
@members = (members.is_a?(Array) ? members : [members])
end
def total
check_collaboration_or_return do
sum = 0
@members.each do |member|
number = member.collaborator? ? member.subscriptions.count : nil
sum += number if number
end
sum
end
end
def multi
check_collaboration_or_return do
sum = 0
@members.each do |member|
number = member.collaborator? ? member.subscriptions.with_multiactivities_pass.length : nil
sum += number if number
end
sum
end
end
def mono
check_collaboration_or_return do
total && multi ? total - multi : nil
end
end
def label
check_collaboration_or_return do
"(#{multi} multi, #{mono} mono sur #{total})"
end
end
private
def check_collaboration_or_return
return nil if @members.all? { |member| !member.collaborator? }
yield
end
end
class Statistics::Billing::Global
def initialize(members)
@member_units = members.map { |member| Statistics::Billing::Unit.new(member) }
end
def total
@member_units.map(&:total).sum
end
def billed
@member_units.map(&:billed).sum
end
def label
@member_units.map(&:label).all? { |label| label.nil? } ? nil : "(€ : #{billed} / #{total})"
end
end
class Statistics::Billing::Unit
def initialize(member)
@member = member
end
def total
check_collaboration_or_return(0) do
@member.subscriptions.with_multiactivities_pass.length
end
end
def billed
check_collaboration_or_return(0) do
@member.subscriptions.billed.count
end
end
def label
check_collaboration_or_return(nil) do
"(€ : #{billed} / #{total})"
end
end
private
def check_collaboration_or_return(value)
return value unless @member.collaborating_club?
yield
end
end
class Statistics::Pass::Global
def initialize(members)
@member_units = members.map { |member| Statistics::Pass::Unit.new(member) }
end
def total
@member_units.map(&:total).sum
end
def multi
@member_units.map(&:multi).sum
end
def mono
total - multi
end
def label
@member_units.map(&:label).all? { |label| label.nil? } ? nil : "(#{multi} multi, #{mono} mono sur #{total})"
end
end
class Statistics::Pass::Unit
def initialize(member)
@member = member
end
def total
return_values = {
none: 0,
club: @member.subscriptions.count,
medicosocial_org: Subscription.of_medicosocial_org(@member).count
}
check_collaboration_or_return(return_values)
end
def multi
return_values = {
none: 0,
club: @member.subscriptions.with_multiactivities_pass.length,
medicosocial_org: Subscription.of_medicosocial_org(@member).with_multiactivities_pass.length
}
check_collaboration_or_return(return_values)
end
def mono
total - multi
end
def label
return_values = {
none: nil,
club: "(#{multi} multi, #{mono} mono sur #{total})",
medicosocial_org: "(#{multi} multi, #{mono} mono sur #{total})"
}
check_collaboration_or_return(return_values)
end
private
def check_collaboration_or_return(values)
if @member.collaborating_club?
values[:club]
elsif @member.medicosocial_org?
values[:medicosocial_org]
else
values[:none]
end
end
end
......@@ -8,6 +8,7 @@ class Subscription < ApplicationRecord
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 :billed, -> { where.not(billed_at: nil) }
scope :of_medicosocial_org, ->(member) { joins(:adherent).where(adherents: {medico_social_org: member}) }
def self.with_multiactivities_pass
all.reject { |sub| !sub.multipass? }
......
......@@ -29,10 +29,7 @@ class SubscriptionOption
private
def org_is_collaborator?
return false if @medicosocial_org.nil?
platform_collaborating_medicosocial_org_groups = Settings.instance.reload.platform_collaborating_medicosocial_orgs.to_a
medicosocial_org_groups = @medicosocial_org.member_groups.to_a
!(platform_collaborating_medicosocial_org_groups & medicosocial_org_groups).empty?
@medicosocial_org.nil? ? false : @medicosocial_org.collaborating_medicosocial_org?
end
def several_activities?
......
......@@ -20,15 +20,17 @@
# You should have received a copy of the GNU Affero General Public License
# along with OLIGAA. If not, see <http://www.gnu.org/licenses/>.
%>
<%- if can_manage_susbscriptions?(@member) %>
<%- if can_manage_susbscriptions?(@member) || can_see_subscriptions?(@member) %>
<aside class="card-block" id="subscriptions">
<h1>Adhésions. <small>Non visibles par un simple visiteur.</small></h1>
<%- if can_manage_susbscriptions?(@member) %>
<p class="AdminCard-globalActions">
<%= custom_add_link "Nouvelle adhésion", new_member_subscription_path(@member) %>
</p>
<%- end %>
<h2>
Nos adhérents
<span><%= PassStatistics.new(@member).label %></span>
<span><%= Statistics::Pass::Unit.new(@member).label %></span>
</h2>
<ul id="internal">
<% @internal_subscriptions.each do |subscription| %>
......@@ -41,6 +43,7 @@
</li>
<%- end %>
</ul>
<%- unless @member.collaborating_medicosocial_org? %>
<h2>Adhérents extérieurs</h2>
<ul id="external">
<% @external_subscriptions.each do |subscription| %>
......@@ -49,5 +52,6 @@
</li>
<%- end %>
</ul>
<%- end %>
</aside>
<%- end %>
......@@ -25,19 +25,20 @@
<div class="tabs">
<ul>
<li><a href="#subscriptions">Adhésions</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>
</ul>
<div id="subscriptions">
<div id="subscriptions-by-club">
<h2>
Liste des adhésions
<span><%= PassStatistics.new(@collaborating_clubs.to_a).label %></span>
<span><%= BillingStatistics.new(@collaborating_clubs.to_a).label %></span>
Liste des adhésions par club partenaire
<span><%= Statistics::Pass::Global.new(@collaborating_clubs.to_a).label %></span>
<span><%= Statistics::Billing::Global.new(@collaborating_clubs.to_a).label %></span>
</h2>
<%- @collaborating_clubs.each do |club| %>
<h3>
<%= club.name %>
<span><%= PassStatistics.new(club).label %></span>
<span><%= BillingStatistics.new(club).label %></span>
<span><%= Statistics::Pass::Unit.new(club).label %></span>
<span><%= Statistics::Billing::Unit.new(club).label %></span>
</h3>
<ul id="member-<%= club.id %>">
<%- club.subscriptions.by_adherent_name.each do |subscription| %>
......@@ -51,4 +52,42 @@
</ul>
<%- end %>
</div>
<div id="subscriptions-by-org">
<h2>
Liste des adhésions par structure
<span><%= Statistics::Pass::Global.new(@orgs.to_a).label %></span>
</h2>
<h3>Structures référencées</h3>
<%- @orgs_in_db.each do |org| %>
<h4>
<%= org.name %>
<span><%= Statistics::Pass::Unit.new(org).label %></span>
</h4>
<ul id="member-<%= org.id %>">
<%- Subscription.of_medicosocial_org(org).by_adherent_name.each do |subscription| %>
<li>
<%= custom_edit_link edit_member_subscription_path(subscription.member, subscription), :short, class: %w(tight) %>
<%= custom_delete_link member_subscription_path(subscription.member, subscription), :short, class: %w(tight) %>
<%= internal_subscription_label(subscription) %>
</li>
<%- end %>
</ul>
<%- end %>
<h3>Structures non référencées</h3>
<%- @orgs_not_in_db.each do |org, subscriptions| %>
<h4>
<%= org.name %>
<span><%= Statistics::Pass::Unit.new(org).label %></span>
</h4>
<ul id="member-<%= org.name.crypt('name').gsub('/','') %>">
<%- subscriptions.each do |subscription| %>
<li>
<%= custom_edit_link edit_member_subscription_path(subscription.member, subscription), :short, class: %w(tight) %>
<%= custom_delete_link member_subscription_path(subscription.member, subscription), :short, class: %w(tight) %>
<%= internal_subscription_label(subscription) %>
</li>
<%- end %>
</ul>
<%- end %>
</div>
</div>
This diff is collapsed.
require 'rails_helper'
RSpec.describe BillingStatistics, type: :model do
context "regading initialization" do
context "sets @members" do
it "as an array when array provided" do
members = []
2.times { members << create(:member) }
stats = BillingStatistics.new(members)
expect(stats.instance_variable_get(:@members)).to eq members
end
it "as an array when only one member provided" do
member = create(:member)
stats = BillingStatistics.new(member)
expect(stats.instance_variable_get(:@members)).to eq [member]
end
end
end
context "when one member provided" do
before do
@mg = create :member_group
@member = create :member, member_groups: [@mg]
perf1 = create :performance, member: @member
perf2 = create :performance, member: @member
3.times { create :subscription, performances: [perf1], member_id: @member.id }
5.times { create :subscription, performances: [perf1, perf2], member_id: @member.id }
@stats = BillingStatistics.new(@member)
end
context "and the member is not a collaborator" do
it "#total returns nil" do
expect(@stats.total).to be_nil
end
it "#billed returns nil" do
expect(@stats.billed).to be_nil
end
it "#label returns nil" do
expect(@stats.label).to be_nil
end
end
context "and the member is a collaborator" do
before { Settings.instance.reload.platform_collaborating_clubs << @mg }
context "multipass subscriptions not billed" do
it "#total returns the number of its multi activivities subscriptions" do
expect(@stats.total).to eq 5
end
it "#billed returns the number of its billed multi activities subscriptions" do
expect(@stats.billed).to eq 0
end
it "#label returns '(€ : 0 / 5)'" do
expect(@stats.label).to eq '(€ : 0 / 5)'
end
end
context "some multipass subscriptions billed" do
before do
@member.subscriptions.with_multiactivities_pass[0,3].each do |subscription|
subscription.toggle_billing
end
end
it "#total returns the number of its multi activivities subscriptions" do
expect(@stats.total).to eq 5
end
it "#billed returns the number of its billed multi activities subscriptions" do
expect(@stats.billed).to eq 3
end
it "#label returns '(€ : 3 / 5)'" do
expect(@stats.label).to eq '(€ : 3 / 5)'
end
end
end
end
context "when array of members provided" do
before do
@mg = create :member_group
@member1 = create :member, member_groups: [@mg]
@member2 = create :member, member_groups: [@mg]
member3 = create :member
perf1 = create :performance, member: @member1
perf2 = create :performance, member: @member2
5.times { create :subscription, performances: [perf1], member_id: @member1.id }
3.times { create :subscription, performances: [perf1, perf2], member_id: @member1.id }
2.times { create :subscription, performances: [perf1], member_id: @member2.id }
5.times { create :subscription, performances: [perf1, perf2], member_id: @member2.id }
3.times { create :subscription, performances: [perf1], member_id: member3.id }
2.times { create :subscription, performances: [perf1, perf2], member_id: member3.id }
@stats = BillingStatistics.new([@member1, @member2, member3])
end
context "and the members are not collaborators" do
it "#total returns nil" do
expect(@stats.total).to be_nil
end
it "#billed returns nil" do
expect(@stats.billed).to be_nil
end
it "#label returns nil" do
expect(@stats.label).to be_nil
end
end
context "and some members are collaborators" do
before { Settings.instance.reload.platform_collaborating_clubs << @mg }
context "multipass subscriptions not billed" do
it "#total returns the number of billable multi activivities subscriptions" do
expect(@stats.total).to eq 8
end
it "#billed returns the number of billed multi activities subscriptions" do
expect(@stats.billed).to eq 0
end
it "#label returns '(€ : 0 / 8)'" do
expect(@stats.label).to eq '(€ : 0 / 8)'
end
end
context "some multipass subscriptions billed" do
before do
@member1.subscriptions.with_multiactivities_pass.first.toggle_billing
@member2.subscriptions.with_multiactivities_pass[0,3].each do |subscription|
subscription.toggle_billing
end
end
it "#total returns the number of its multi activivities subscriptions" do
expect(@stats.total).to eq 8
end
it "#billed returns the number of its billed multi activities subscriptions" do
expect(@stats.billed).to eq 4
end
it "#label returns '(€ : 4 / 8)'" do
expect(@stats.label).to eq '(€ : 4 / 8)'
end
end
end
end
end
......@@ -181,12 +181,28 @@ describe Member do
expect(m.reload.contacts.first.contact_type.title).to eq("Nouvelle fonction")
end
it "#is_collaborator? returns true if member belong to platform collaborating groups" do
it "#collaborating_club? returns true if member belong to platform collaborating clubs groups" do
mg = create :member_group
m = create :member, member_groups: [mg]
expect(m).not_to be_collaborator
expect(m).not_to be_collaborating_club
Settings.instance.reload.platform_collaborating_clubs << mg
expect(m).to be_collaborator
expect(m).to be_collaborating_club
end
it "#collaborating_medicosocial_org? returns true if member belongs to platform collaborating medicosocial orgs groups" do
mg = create :member_group
m = create :member, member_groups: [mg]
expect(m).not_to be_collaborating_medicosocial_org
Settings.instance.reload.platform_collaborating_medicosocial_orgs << mg
expect(m).to be_collaborating_medicosocial_org
end
it "#medicosocial_org? returns true if member belongs to platform medicosocial orgs groups" do
mg = create :member_group
m = create :member, member_groups: [mg]
expect(m).not_to be_medicosocial_org
Settings.instance.reload.platform_medicosocial_orgs << mg
expect(m).to be_medicosocial_org
end
describe "password management" do
......
require 'rails_helper'
RSpec.describe PassStatistics, type: :model do
context "regading initialization" do
context "sets @members" do
it "as an array when array provided" do
members = []
2.times { members << create(:member) }
stats = PassStatistics.new(members)
expect(stats.instance_variable_get(:@members)).to eq members
end
it "as an array when only one member provided" do
member = create(:member)
stats = PassStatistics.new(member)
expect(stats.instance_variable_get(:@members)).to eq [member]
end
end
end
context "when one member provided" do
before do
@mg = create :member_group
member = create :member, member_groups: [@mg]
perf1 = create :performance, member: member
perf2 = create :performance, member: member
5.times { create :subscription, performances: [perf1], member_id: member.id }
3.times { create :subscription, performances: [perf1, perf2], member_id: member.id }
@stats = PassStatistics.new(member)
end
context "and the member is not a collaborator" do
it "#total returns nil" do
expect(@stats.total).to be_nil
end
it "#multi returns nil" do
expect(@stats.multi).to be_nil
end
it "#mono returns nil" do
expect(@stats.mono).to be_nil
end
it "#label returns nil" do
expect(@stats.label).to be_nil
end
end
context "and the member is a collaborator" do
before { Settings.instance.reload.platform_collaborating_clubs << @mg }
it "#total returns the number of its subscriptions" do
expect(@stats.total).to eq 8
end
it "#multi returns the number of its multi activities subscriptions" do
expect(@stats.multi).to eq 3
end
it "#mono returns the number of its mono activity subscriptions" do
expect(@stats.mono).to eq 5
end
it "#label returns '(3 multi, 5 mono sur 8)'" do
expect(@stats.label).to eq '(3 multi, 5 mono sur 8)'
end
end
end
context "when array of members provided" do
before do
@mg = create :member_group
member1 = create :member, member_groups: [@mg]
member2 = create :member, member_groups: [@mg]
member3 = create :member
perf1 = create :performance, member: member1
perf2 = create :performance, member: member2
5.times { create :subscription, performances: [perf1], member_id: member1.id }
3.times { create :subscription, performances: [perf1, perf2], member_id: member1.id }
2.times { create :subscription, performances: [perf1], member_id: member2.id }
5.times { create :subscription, performances: [perf1, perf2], member_id: member2.id }
3.times { create :subscription, performances: [perf1], member_id: member3.id }
2.times { create :subscription, performances: [perf1, perf2], member_id: member3.id }
@stats = PassStatistics.new([member1, member2, member3])
end
context "and the members are not collaborators" do
it "#total returns nil" do
expect(@stats.total).to be_nil
end
it "#multi returns the number of its multi activities subscriptions" do
expect(@stats.multi).to be_nil
end
it "#mono returns the number of its mono activity subscriptions" do
expect(@stats.mono).to be_nil
end