-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Implement mailing list subscriber filter for invoice receiver, fixes #…
- Loading branch information
1 parent
9fd85fd
commit 5897567
Showing
8 changed files
with
540 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
14 changes: 14 additions & 0 deletions
14
app/views/subscriber/filter/_filter_form_invoice_receiver.html.haml
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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}") |
12 changes: 12 additions & 0 deletions
12
app/views/subscriber/filter/_filter_show_invoice_receiver.html.haml
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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}") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
Oops, something went wrong.