Skip to content

Commit

Permalink
Implement mailing list subscriber filter for invoice receiver, fixes #…
Browse files Browse the repository at this point in the history
  • Loading branch information
daniel-illi committed Nov 21, 2024
1 parent 9fd85fd commit 5897567
Show file tree
Hide file tree
Showing 8 changed files with 540 additions and 0 deletions.
51 changes: 51 additions & 0 deletions app/domain/person/filter/invoice_receiver.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
# frozen_string_literal: true

# Copyright (c) 2024, Schweizer Alpen-Club. This file is part of
# hitobito_sac_cas and licensed under the Affero General Public License version 3
# or later. See the COPYING file at the top-level directory or at
# https://github.com/hitobito/hitobito_sac_cas

class Person::Filter::InvoiceReceiver < Person::Filter::Base
VISIBLE_ATTRS = [:stammsektion, :zusatzsektion].freeze
self.permitted_args = [*VISIBLE_ATTRS, :group_id]

def apply(scope)
return scope if blank?

scope.where(id: invoice_receiver_scope)
end

def blank? = !(stammsektion || zusatzsektion) || group_id.blank?

private

def stammsektion = ActiveModel::Type::Boolean.new.cast(args[:stammsektion])

def zusatzsektion = ActiveModel::Type::Boolean.new.cast(args[:zusatzsektion])

def group_id = args[:group_id].presence

def group
raise "Group ID is required" unless args[:group_id].present?
Group.find(group_id)
end

def role_types
[].tap do |role_types|
role_types << Group::SektionsMitglieder::Mitglied.sti_name if stammsektion
role_types << Group::SektionsMitglieder::MitgliedZusatzsektion.sti_name if zusatzsektion
end
end

def base_scope
Person.joins(:roles).where(roles: {type: role_types}).then do |scope|
group.layer_group.is_a?(Group::SacCas) ? scope : scope.in_layer(group)
end
end

def invoice_receiver_scope
base_scope
.where.not(roles: {beitragskategorie: SacCas::Beitragskategorie::Calculator::CATEGORY_FAMILY})
.or(base_scope.where(sac_family_main_person: true))
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
-# Copyright (c) 2024, Schweizer Alpen-Club SAC. This file is part of
-# hitobito and licensed under the Affero General Public License version 3
-# or later. See the COPYING file at the top-level directory or at
-# https://github.com/hitobito/hitobito_sac_cas
- caption = t("people_filters.invoice_receiver.title", group_name: assigns["group"].layer_group.name)
= render(layout: 'people_filters/filter', locals: { entry: @mailing_list, type: :invoice_receiver, caption: }) do
- filter_args = entry.filter_chain[:invoice_receiver]&.args
= hidden_field_tag('filters[invoice_receiver][group_id]', assigns["group"].id)
- Person::Filter::InvoiceReceiver::VISIBLE_ATTRS.each do |attr|
- id = "filters_invoice_receiver_#{attr}"
= label_tag(nil, class: 'checkbox ', for: id) do
= check_box_tag("filters[invoice_receiver][#{attr}]", true, filter_args&.dig(attr), id: id)
= t(".invoice_receiver.#{attr}")
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
-# Copyright (c) 2024, Schweizer Alpen-Club SAC. This file is part of
-# hitobito and licensed under the Affero General Public License version 3
-# or later. See the COPYING file at the top-level directory or at
-# https://github.com/hitobito/hitobito_sac_cas
- if @mailing_list.filter_chain[:invoice_receiver].present?
- filter_args = @mailing_list.filter_chain[:invoice_receiver].args

- Person::Filter::InvoiceReceiver::VISIBLE_ATTRS.each do |attr|
- if filter_args&.dig(attr)
%li
= t("people_filters.filter.invoice_receiver.#{attr}")
8 changes: 8 additions & 0 deletions config/locales/wagon.de.yml
Original file line number Diff line number Diff line change
Expand Up @@ -1574,6 +1574,14 @@ de:
one: Anmeldung wurde abgelehnt
other: "%{count} Anmeldungen wurden abgelehnt"

people_filters:
invoice_receiver:
title: Rechnungsempfänger in %{group_name}
filter:
invoice_receiver:
stammsektion: Rechnungsempfänger SAC Mitgliedschaft
zusatzsektion: Rechnungsempfänger Zusatzsektion

roles:
beitragskategorie:
adult: Einzel
Expand Down
2 changes: 2 additions & 0 deletions lib/hitobito_sac_cas/wagon.rb
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ class Wagon < Rails::Engine
]
HitobitoLogEntry.categories += %w[neuanmeldungen rechnungen stapelverarbeitung]

MailingLists::Filter::Chain::TYPES << Person::Filter::InvoiceReceiver

# extend application classes here
CustomContent.prepend SacCas::CustomContent
Event.prepend SacCas::Event
Expand Down
159 changes: 159 additions & 0 deletions spec/domain/mailing_lists/subscribers_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
# frozen_string_literal: true

# Copyright (c) 2024, Schweizer Alpen-Club. This file is part of
# hitobito_sac_cas and licensed under the Affero General Public License version 3
# or later. See the COPYING file at the top-level directory or at
# https://github.com/hitobito/hitobito_sac_cas

require "spec_helper"

describe MailingLists::Subscribers do
include Subscriptions::SpecHelper

let!(:list) {
Fabricate(:mailing_list,
group:,
subscribable_for: "configured",
subscribable_mode: "opt_out")
}
let!(:subscription) do
Fabricate(:subscription,
mailing_list: list,
subscriber: group,
role_types: [Mitglied, MitgliedZusatzsektion, Schreibrecht])
end

let(:test_person) { create_person(30) }

subject(:entries) { MailingLists::Subscribers.new(list).people }

def group_id = group.id

def set_filter(filter)
list.update!(filter_chain: filter)
end

def create_person(age = 30, **attrs) = Fabricate(:person, birthday: age.years.ago, **attrs)

def create_role(type, group, person = test_person, **attrs)
Fabricate(type.sti_name, group: groups(group), person: person, **attrs)
end

Mitglied = Group::SektionsMitglieder::Mitglied
MitgliedZusatzsektion = Group::SektionsMitglieder::MitgliedZusatzsektion
Schreibrecht = Group::SektionsMitglieder::Schreibrecht

context "invoice_receiver filter" do
context "with list in top layer" do
let(:group) { groups(:root) }

context "with invoice_receiver stammsektion filter" do
before { set_filter(invoice_receiver: {stammsektion: true, group_id:}) }

it "includes member in a sektion" do
create_role(Mitglied, :bluemlisalp_mitglieder)
expect(entries).to include(test_person)
end

it "excludes person with non-member role" do
create_role(Schreibrecht, :bluemlisalp_mitglieder)
expect(entries).not_to include(test_person)
end
end

context "with invoice_receiver zusatzsektion filter" do
before { set_filter(invoice_receiver: {zusatzsektion: true, group_id:}) }

it "includes member in a zusatzsektion" do
create_role(Mitglied, :bluemlisalp_mitglieder)
create_role(MitgliedZusatzsektion, :matterhorn_mitglieder)
end

it "excludes member without zusatzsektion" do
create_role(Mitglied, :bluemlisalp_mitglieder)
expect(entries).not_to include(test_person)
end
end

context "with both invoice_receiver filters stammsektion and zusatzsektion" do
before { set_filter(invoice_receiver: {stammsektion: true, zusatzsektion: true, group_id:}) }

it "includes member in a sektion" do
create_role(Mitglied, :bluemlisalp_mitglieder)
expect(entries).to include(test_person)
end

it "includes member in a zusatzsektion" do
create_role(Mitglied, :bluemlisalp_mitglieder)
create_role(MitgliedZusatzsektion, :matterhorn_mitglieder)
expect(entries).to include(test_person)
end

it "excludes person with non-member role" do
create_role(Schreibrecht, :bluemlisalp_mitglieder)
expect(entries).not_to include(test_person)
end
end
end

context "with list in sublayer" do
let(:group) { groups(:bluemlisalp) }

context "with invoice_receiver stammsektion filter" do
before { set_filter(invoice_receiver: {stammsektion: true, group_id:}) }

it "includes member in same layer" do
create_role(Mitglied, :bluemlisalp_mitglieder)
expect(entries).to include(test_person)
end

it "excludes member in a lower layer" do
create_role(Mitglied, :bluemlisalp_ortsgruppe_ausserberg_mitglieder)
expect(entries).not_to include(test_person)
end

it "excludes member in a different layer" do
create_role(Mitglied, :matterhorn_mitglieder)
expect(entries).not_to include(test_person)
end
end

context "with invoice_receiver zusatzsektion filter" do
before { set_filter(invoice_receiver: {zusatzsektion: true, group_id:}) }

it "includes zusatzsektion member in same layer" do
create_role(Mitglied, :matterhorn_mitglieder)
create_role(MitgliedZusatzsektion, :bluemlisalp_mitglieder)
expect(entries).to include(test_person)
end

it "excludes zusatzsektion member in a lower layer" do
create_role(Mitglied, :matterhorn_mitglieder)
create_role(MitgliedZusatzsektion, :bluemlisalp_ortsgruppe_ausserberg_mitglieder)
expect(entries).not_to include(test_person)
end

it "excludes zusatzsektion member in a different layer" do
create_role(Mitglied, :bluemlisalp_mitglieder)
create_role(MitgliedZusatzsektion, :matterhorn_mitglieder)
expect(entries).not_to include(test_person)
end
end

context "with both invoice_receiver filters stammsektion and zusatzsektion" do
before { set_filter(invoice_receiver: {stammsektion: true, zusatzsektion: true, group_id:}) }

it "includes member in same layer" do
create_role(Mitglied, :bluemlisalp_mitglieder)
expect(entries).to include(test_person)
end

it "includes zusatzsektion member in same layer" do
create_role(Mitglied, :matterhorn_mitglieder)
create_role(MitgliedZusatzsektion, :bluemlisalp_mitglieder)
expect(entries).to include(test_person)
end
end
end
end
end
Loading

0 comments on commit 5897567

Please sign in to comment.