diff --git a/app/abilities/sac_section_membership_config_ability.rb b/app/abilities/sac_section_membership_config_ability.rb new file mode 100644 index 000000000..7a4c905cd --- /dev/null +++ b/app/abilities/sac_section_membership_config_ability.rb @@ -0,0 +1,16 @@ +# 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 SacSectionMembershipConfigAbility < AbilityDsl::Base + + include AbilityDsl::Constraints::Group + + on(SacSectionMembershipConfig) do + permission(:layer_and_below_full).may(:manage).in_same_layer_or_below + end + +end diff --git a/app/components/sac_membership_configs/field_rows_component.html.haml b/app/components/sac_membership_configs/field_rows_component.html.haml index 51f4f9d97..90cd5d869 100644 --- a/app/components/sac_membership_configs/field_rows_component.html.haml +++ b/app/components/sac_membership_configs/field_rows_component.html.haml @@ -2,7 +2,13 @@ - @attrs.each do |attr| .row .col-3.p-1 - = SacMembershipConfig.human_attribute_name(attr) + = human_attribute_name(attr) .col-3.p-1 .input-group.input-group-sm = @form.input_field attr + - if currency?(attr) + %span.input-group-text + = t('global.currency') + - if years?(attr) + %span.input-group-text + = t('global.years') diff --git a/app/components/sac_membership_configs/field_rows_component.rb b/app/components/sac_membership_configs/field_rows_component.rb index 5432f6da2..a1bd2513d 100644 --- a/app/components/sac_membership_configs/field_rows_component.rb +++ b/app/components/sac_membership_configs/field_rows_component.rb @@ -8,10 +8,26 @@ module SacMembershipConfigs class FieldRowsComponent < ApplicationComponent + delegate :entry, :model_class, :column_type, to: :helpers + def initialize(form:, attrs:) @form = form @attrs = attrs end + private + + def currency?(attr) + column_type(entry, attr) == :decimal + end + + def years?(attr) + attr.to_s.match?(/_age|_years/) + end + + def human_attribute_name(attr) + model_class.human_attribute_name(attr) + end + end end diff --git a/app/components/sac_membership_configs/valid_from_selector_component.html.haml b/app/components/sac_membership_configs/valid_from_selector_component.html.haml index eaaf22e63..2e35fe152 100644 --- a/app/components/sac_membership_configs/valid_from_selector_component.html.haml +++ b/app/components/sac_membership_configs/valid_from_selector_component.html.haml @@ -2,5 +2,5 @@ - @available_configs.each do |config| %li.page-item{ class: [active?(config) && 'active'] } = link_to_edit_config(config) - %li.page-item{ class: [@entry.new_record? && 'active'] } + %li.page-item{ class: [entry.new_record? && 'active'] } = link_new_config diff --git a/app/components/sac_membership_configs/valid_from_selector_component.rb b/app/components/sac_membership_configs/valid_from_selector_component.rb index 0e9b6d6b7..55a6fe98f 100644 --- a/app/components/sac_membership_configs/valid_from_selector_component.rb +++ b/app/components/sac_membership_configs/valid_from_selector_component.rb @@ -8,8 +8,9 @@ module SacMembershipConfigs class ValidFromSelectorComponent < ApplicationComponent - def initialize(entry:, available_configs:) - @entry = entry + delegate :entry, to: :helpers + + def initialize(available_configs:) @available_configs = available_configs end diff --git a/app/components/sac_section_membership_configs/reduction_field_rows_component.rb b/app/components/sac_section_membership_configs/reduction_field_rows_component.rb new file mode 100644 index 000000000..7fb4a201d --- /dev/null +++ b/app/components/sac_section_membership_configs/reduction_field_rows_component.rb @@ -0,0 +1,24 @@ +# 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 + +module SacSectionMembershipConfigs + class ReductionFieldRowsComponent < SacMembershipConfigs::FieldRowsComponent + + def initialize(form:, attrs: []) + super + @attrs = [:sac_fee_exemption_for_honorary_members, + :sac_section_fee_exemption_for_honorary_members, + :sac_fee_exemption_for_benefited_members, + :sac_section_fee_exemption_for_benefited_members, + :reduction_amount, + :reduction_required_membership_years, + :reduction_required_age] + + end + + end +end diff --git a/app/components/sac_section_membership_configs/valid_from_selector_component.html.haml b/app/components/sac_section_membership_configs/valid_from_selector_component.html.haml new file mode 100644 index 000000000..2e35fe152 --- /dev/null +++ b/app/components/sac_section_membership_configs/valid_from_selector_component.html.haml @@ -0,0 +1,6 @@ +%ul.pagination.pagination-sm + - @available_configs.each do |config| + %li.page-item{ class: [active?(config) && 'active'] } + = link_to_edit_config(config) + %li.page-item{ class: [entry.new_record? && 'active'] } + = link_new_config diff --git a/app/components/sac_section_membership_configs/valid_from_selector_component.rb b/app/components/sac_section_membership_configs/valid_from_selector_component.rb new file mode 100644 index 000000000..6678e6504 --- /dev/null +++ b/app/components/sac_section_membership_configs/valid_from_selector_component.rb @@ -0,0 +1,39 @@ +# 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 + +module SacSectionMembershipConfigs + class ValidFromSelectorComponent < ApplicationComponent + + delegate :entry, to: :helpers + + def initialize(available_configs:, sac_section_id:) + @available_configs = available_configs + @sac_section_id = sac_section_id + end + + private + + def active?(config) + config.id == params[:id].to_i + end + + def link_to_edit_config(config) + link_to(config.valid_from, + edit_group_sac_section_membership_config_path( + group_id: config.group_id, id: config.id), + class: 'page-link') + end + + def link_new_config + link_to(t('sac_section_membership_configs.global.link.add'), + new_group_sac_section_membership_config_path( + group_id: helpers.params[:group_id]), + class: 'page-link') + end + + end +end diff --git a/app/controllers/sac_membership_configs_controller.rb b/app/controllers/sac_membership_configs_controller.rb index 8a672193a..784b9eb46 100644 --- a/app/controllers/sac_membership_configs_controller.rb +++ b/app/controllers/sac_membership_configs_controller.rb @@ -45,6 +45,8 @@ class SacMembershipConfigsController < CrudController decorates :sac_membership_config helper_method :cancel_url, :available_configs + before_action :assert_root_layer + def index redirect_to latest_config_entry_path end @@ -99,10 +101,16 @@ def cancel_url end def available_configs - @available_configs ||= SacMembershipConfig.all.order(:valid_from) + @available_configs ||= SacMembershipConfig.order(:valid_from) end def latest_config available_configs.last end + + def assert_root_layer + return if params[:group_id].to_i == Group.root.id + + head :not_found + end end diff --git a/app/controllers/sac_section_membership_configs_controller.rb b/app/controllers/sac_section_membership_configs_controller.rb new file mode 100644 index 000000000..cd66f47e0 --- /dev/null +++ b/app/controllers/sac_section_membership_configs_controller.rb @@ -0,0 +1,98 @@ +# 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 SacSectionMembershipConfigsController < CrudController + self.nesting = Group + self.permitted_attrs =[:valid_from, + :sac_section_fee_adult, + :sac_section_fee_family, + :sac_section_fee_youth, + :entry_fee_adult, + :entry_fee_family, + :entry_fee_youth, + :bulletin_postage_abroad, + :sac_fee_exemption_for_honorary_members, + :sac_section_fee_exemption_for_honorary_members, + :sac_fee_exemption_for_benefited_members, + :sac_section_fee_exemption_for_benefited_members, + :reduction_amount, + :reduction_required_membership_years, + :reduction_required_age] + + decorates :sac_section_membership_config + helper_method :cancel_url, :available_configs, :sac_section + + before_action :assert_sac_section_or_ortsgruppe + + def index + redirect_to latest_config_entry_path + end + + def show + redirect_to edit_path(params[:id]) + end + + private + + def build_entry + if latest_config + attrs = latest_config.attributes + attrs.delete('id') + attrs[:valid_from] = latest_config.valid_from + 1 + else + attrs = { valid_from: Time.zone.now.year } + end + SacSectionMembershipConfig.new(attrs) + end + + def find_entry + SacSectionMembershipConfig.find(params[:id]) + end + + def latest_config_entry_path + if latest_config + edit_path(latest_config.id) + else + new_path + end + end + + def edit_path(id) + helpers.edit_group_sac_section_membership_config_path(group_id: sac_section.id, id: id) + end + + def new_path + helpers.new_group_sac_section_membership_config_path(group_id: sac_section.id) + end + + def cancel_url + group_path(id: sac_section.id) + end + + def available_configs + @available_configs ||= + SacSectionMembershipConfig.where(group_id: sac_section.id).order(:valid_from) + end + + def latest_config + available_configs.last + end + + def sac_section + @sac_section ||= fetch_sac_section + end + + def fetch_sac_section + Group.find_by(id: params[:group_id], type: model_class.group_types) + end + + def assert_sac_section_or_ortsgruppe + return if sac_section + + head :not_found + end +end diff --git a/app/decorators/sac_section_membership_config_decorator.rb b/app/decorators/sac_section_membership_config_decorator.rb new file mode 100644 index 000000000..7213df280 --- /dev/null +++ b/app/decorators/sac_section_membership_config_decorator.rb @@ -0,0 +1,15 @@ +# 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 SacSectionMembershipConfigDecorator < ApplicationDecorator + decorates SacSectionMembershipConfig + + def to_s + "#{@object.class.model_name.human} (#{valid_from})" + end + +end diff --git a/app/helpers/sac_cas/dropdown/group_edit.rb b/app/helpers/sac_cas/dropdown/group_edit.rb index edccea848..a8970e1c4 100644 --- a/app/helpers/sac_cas/dropdown/group_edit.rb +++ b/app/helpers/sac_cas/dropdown/group_edit.rb @@ -13,5 +13,19 @@ def initialize(template, group) template.group_sac_membership_configs_path( group_id: Group.root.id)) end + + if sac_section_or_ortsgruppe? && + template.can?(:index, SacSectionMembershipConfig) + add_item(translate(:sac_section_membership_configs), + template.group_sac_section_membership_configs_path( + group_id: group.id)) + end + end + + private + + def sac_section_or_ortsgruppe? + group_types = SacSectionMembershipConfig.group_types + group_types.one? {|t| group.is_a?(t) } end end diff --git a/app/helpers/sheet/sac_section_membership_config.rb b/app/helpers/sheet/sac_section_membership_config.rb new file mode 100644 index 000000000..23a975805 --- /dev/null +++ b/app/helpers/sheet/sac_section_membership_config.rb @@ -0,0 +1,12 @@ +# 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 + +module Sheet + class SacSectionMembershipConfig < Base + self.parent_sheet = Sheet::Group + end +end diff --git a/app/models/group/ortsgruppe.rb b/app/models/group/ortsgruppe.rb index 6c6551a76..042edac46 100644 --- a/app/models/group/ortsgruppe.rb +++ b/app/models/group/ortsgruppe.rb @@ -30,9 +30,7 @@ class Group::Ortsgruppe < ::Group { greater_or_equal_to: 1863, smaller_than: Time.zone.now.year + 2 } mounted_attr :section_canton, :string, enum: Cantons.short_name_strings.map(&:upcase) - mounted_attr :language, :string, enum: %w(DE FR IT), default: 'DE', null: false - mounted_attr :mitglied_termination_by_section_only, :boolean, default: false, null: false def sac_cas_self_registration_url(host) diff --git a/app/models/group/sektion.rb b/app/models/group/sektion.rb index ad346219e..83c9d11ba 100644 --- a/app/models/group/sektion.rb +++ b/app/models/group/sektion.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -# Copyright (c) 2012-2023, Schweizer Alpen-Club. This file is part of +# 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. @@ -30,13 +30,12 @@ class Group::Sektion < ::Group validates :foundation_year, numericality: { greater_or_equal_to: 1863, smaller_than: Time.zone.now.year + 2 } - mounted_attr :section_canton, :string, enum: Cantons.short_name_strings.map(&:upcase) - mounted_attr :language, :string, enum: %w(DE FR IT), default: 'DE', null: false - mounted_attr :mitglied_termination_by_section_only, :boolean, default: false, null: false + has_many :sektion_membership_configs + def sac_cas_self_registration_url(host) Groups::SektionSelfRegistrationLink.new(self, host).url end diff --git a/app/models/sac_membership_config.rb b/app/models/sac_membership_config.rb index e7e03a05b..8e7689016 100644 --- a/app/models/sac_membership_config.rb +++ b/app/models/sac_membership_config.rb @@ -1,9 +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 +# +# == Schema Information +# +# Table name: sac_membership_configs +# +# id :bigint not null, primary key +# valid_from :integer not null +# sac_fee_adult :decimal(5, 2) not null +# sac_fee_family :decimal(5, 2) not null +# sac_fee_youth :decimal(5, 2) not null +# entry_fee_adult :decimal(5, 2) not null +# entry_fee_family :decimal(5, 2) not null +# entry_fee_youth :decimal(5, 2) not null +# hut_solidarity_fee_with_hut_adult :decimal(5, 2) not null +# hut_solidarity_fee_with_hut_family :decimal(5, 2) not null +# hut_solidarity_fee_with_hut_youth :decimal(5, 2) not null +# hut_solidarity_fee_without_hut_adult :decimal(5, 2) not null +# hut_solidarity_fee_without_hut_family :decimal(5, 2) not null +# hut_solidarity_fee_without_hut_youth :decimal(5, 2) not null +# magazine_fee_adult :decimal(5, 2) not null +# magazine_fee_family :decimal(5, 2) not null +# magazine_fee_youth :decimal(5, 2) not null +# service_fee :decimal(5, 2) not null +# magazine_postage_abroad :decimal(5, 2) not null +# reduction_amount :decimal(5, 2) not null +# reduction_required_membership_years :integer +# discount_date_1 :string(255) +# discount_percent_1 :integer +# discount_date_2 :string(255) +# discount_percent_2 :integer +# discount_date_3 :string(255) +# discount_percent_3 :integer +# sac_fee_article_number :string(255) not null +# sac_entry_fee_article_number :string(255) not null +# hut_solidarity_fee_article_number :string(255) not null +# magazine_fee_article_number :string(255) not null +# section_bulletin_postage_abroad_article_number :string(255) not null +# service_fee_article_number :string(255) not null +# balancing_payment_article_number :string(255) not null +# course_fee_article_number :string(255) not null +# +# class SacMembershipConfig < ApplicationRecord validates_by_schema diff --git a/app/models/sac_section_membership_config.rb b/app/models/sac_section_membership_config.rb new file mode 100644 index 000000000..b69922513 --- /dev/null +++ b/app/models/sac_section_membership_config.rb @@ -0,0 +1,57 @@ +# frozen_string_literal: true + +# Copyright (c) 2012-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. + +# == Schema Information +# +# Table name: sac_section_membership_configs +# +# id :bigint not null, primary key +# valid_from :integer not null +# group_id :bigint +# sac_section_fee_adult :decimal(5, 2) not null +# sac_section_fee_family :decimal(5, 2) not null +# sac_section_fee_youth :decimal(5, 2) not null +# entry_fee_adult :decimal(5, 2) not null +# entry_fee_family :decimal(5, 2) not null +# entry_fee_youth :decimal(5, 2) not null +# bulletin_postage_abroad :decimal(5, 2) not null +# sac_fee_exemption_for_honorary_members :boolean default(FALSE), not null +# sac_section_fee_exemption_for_honorary_members :boolean default(FALSE), not null +# sac_fee_exemption_for_benefited_members :boolean default(FALSE), not null +# sac_section_fee_exemption_for_benefited_members :boolean default(FALSE), not null +# reduction_amount :decimal(5, 2) not null +# reduction_required_membership_years :integer +# reduction_required_age :integer +# + +class SacSectionMembershipConfig < ApplicationRecord + validates_by_schema + + attr_readonly :valid_from, :group_id + + belongs_to :group + + validate :assert_sac_section_or_ortsgruppe + + validates :valid_from, uniqueness: { scope: :group_id } + + def self.group_types + [Group::Sektion, Group::Ortsgruppe] + end + + def to_s + valid_from + end + + private + + def assert_sac_section_or_ortsgruppe + return if group && self.class.group_types.one? {|t| group.is_a?(t) } + + errors.add(:group, 'Group must be present and Sac Section or Ortsgruppe') + end +end diff --git a/app/views/sac_membership_configs/_form.html.haml b/app/views/sac_membership_configs/_form.html.haml index 2b722a051..67c5a5ac5 100644 --- a/app/views/sac_membership_configs/_form.html.haml +++ b/app/views/sac_membership_configs/_form.html.haml @@ -2,7 +2,7 @@ -# 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. -= render(SacMembershipConfigs::ValidFromSelectorComponent.new(entry: entry, available_configs: available_configs)) += render(SacMembershipConfigs::ValidFromSelectorComponent.new(available_configs: available_configs)) = entry_form(cancel_url: cancel_url, buttons_top: false) do |f| - if entry.new_record? diff --git a/app/views/sac_section_membership_configs/_form.html.haml b/app/views/sac_section_membership_configs/_form.html.haml new file mode 100644 index 000000000..205086548 --- /dev/null +++ b/app/views/sac_section_membership_configs/_form.html.haml @@ -0,0 +1,69 @@ +-# 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. + += render(SacSectionMembershipConfigs::ValidFromSelectorComponent.new(available_configs: available_configs, sac_section_id: sac_section.id)) + += entry_form(cancel_url: cancel_url, buttons_top: false) do |f| + - if entry.new_record? + = field_set_tag do + = render(SacMembershipConfigs::FieldRowsComponent.new(form: f, attrs: [:valid_from])) + + = field_set_tag(t('sac_section_membership_configs.form.fees')) do + .container.ml-0 + .row + .col-3.p-1 + .col-3.p-1 + = t('.membership_adult') + .col-3.p-1 + = t('.membership_family') + .col-3.p-1 + = t('.membership_youth') + .row + .col-3.p-1 + = t('.sac_section_fee') + .col-3.p-1 + .input-group.input-group-sm + = f.input_field :sac_section_fee_adult + %span.input-group-text + = t('global.currency') + .col-3.p-1 + .input-group.input-group-sm + = f.input_field :sac_section_fee_family + %span.input-group-text + = t('global.currency') + .col-3.p-1 + .input-group.input-group-sm + = f.input_field :sac_section_fee_youth + %span.input-group-text + = t('global.currency') + .row + .col-3.p-1 + = t('.entry_fee') + .col-3.p-1 + .input-group.input-group-sm + = f.input_field :entry_fee_adult + %span.input-group-text + = t('global.currency') + .col-3.p-1 + .input-group.input-group-sm + = f.input_field :entry_fee_family + %span.input-group-text + = t('global.currency') + .col-3.p-1 + .input-group.input-group-sm + = f.input_field :entry_fee_youth + %span.input-group-text + = t('global.currency') + .row.pt-5 + .col-3.p-1 + = SacSectionMembershipConfig.human_attribute_name(:bulletin_postage_abroad) + .col-3.p-1 + .input-group.input-group-sm + = f.input_field :bulletin_postage_abroad + %span.input-group-text + = t('global.currency') + + = field_set_tag(t('.reductions')) do + = render(SacSectionMembershipConfigs::ReductionFieldRowsComponent.new(form: f)) diff --git a/config/locales/wagon.de.yml b/config/locales/wagon.de.yml index 54a127af8..88f624ee7 100644 --- a/config/locales/wagon.de.yml +++ b/config/locales/wagon.de.yml @@ -4,6 +4,11 @@ # https://github.com/hitobito/hitobito_sac_cas. de: + global: + phone_placeholder: +41 77 123 45 67 + currency: CHF + years: Jahre + errors: messages: assert_old_enough: muss ein Geburtsdatum haben und mindestens %{minimum_years} Jahre alt sein @@ -262,6 +267,22 @@ de: discount_percent_2: Rabattprozent 2 discount_date_3: Rabattdatum 3 discount_percent_3: Rabattprozent 3 + sac_section_membership_config: + valid_from: Gültig ab Jahr + sac_section_fee_adult: Sektionsbeitrag, Mitgliedschaft Einzel + sac_section_fee_family: Sektionsbeitrag, Mitgliedschaft Familie + sac_section_fee_youth: Sektionsbeitrag, Mitgliedschaft Jugend + entry_fee_adult: Eintrittsgebühr, Mitgliedschaft Einzel + entry_fee_family: Eintrittsgebühr, Mitgliedschaft Familie + entry_fee_youth: Eintrittsgebühr, Mitgliedschaft Jugend + bulletin_postage_abroad: Porto Ausland Sektionsbulletin + sac_fee_exemption_for_honorary_members: Zentralverbandsgebührenerlass für Ehrenmitglieder + sac_section_fee_exemption_for_honorary_members: Sektionsgebührenerlass für Ehrenmitglieder + sac_fee_exemption_for_benefited_members: Zentralverbandsgebührenerlass für Begünstigte + sac_section_fee_exemption_for_benefited_members: Sektionsgebührenerlass für Begünstigte + reduction_amount: Reduktionsbetrag Mitgliedsjahre/Alter + reduction_required_membership_years: Reduktion ab Mitgliedsjahren + reduction_required_age: Reduktion ab Altersjahren errors: messages: @@ -307,6 +328,9 @@ de: sac_membership_config: one: Parameter für Mitgliedschaftsrechnungen other: Parameter für Mitgliedschaftsrechnungen + sac_section_membership_config: + one: Parameter für Mitgliedschaftsrechnungen + other: Parameter für Mitgliedschaftsrechnungen ### GROUPS group/sac_cas: @@ -505,6 +529,7 @@ de: dropdown/group_edit: sac_membership_configs: Parameter für Mitgliedschaftsrechnungen + sac_section_membership_configs: Parameter für Mitgliedschaftsrechnungen event: kinds: @@ -622,11 +647,6 @@ de: tour_guides_inactive: Inaktive Tourenleiter tour_guides_expired: Abgelaufene Tourenleiter - global: - phone_placeholder: +41 77 123 45 67 - currency: CHF - years: Jahre - mitglieder_exports: export_enqueued: "Export wird im Hintergrund gestartet und nach Fertigstellung heruntergeladen." @@ -847,3 +867,17 @@ de: global: link: add: Neu + + sac_section_membership_configs: + form: + fees: Gebühren + membership_adult: Mitgliedschaft Einzel + membership_family: Mitgliedschaft Familie + membership_youth: Mitgliedschaft Jugend + sac_section_fee: Sektionsbeitrag + entry_fee: Eintrittsgebühr + bulletin_fee: Abogebühr Sektionsbulletin + reductions: Reduktionen + global: + link: + add: Neu diff --git a/config/routes.rb b/config/routes.rb index 2116ea518..623ce0267 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -# Copyright (c) 2012-2023, Schweizer Alpen-Club. This file is part of +# Copyright (c) 2012-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. @@ -22,6 +22,7 @@ resources :groups, only: [] do post 'self_inscription/confirm' => 'groups/self_inscription#confirm' resources :sac_membership_configs, except: [:destroy] + resources :sac_section_membership_configs, except: [:destroy] resources :events, only: [] do scope module: 'event' do diff --git a/db/migrate/20240513070825_create_sac_section_membership_configs.rb b/db/migrate/20240513070825_create_sac_section_membership_configs.rb new file mode 100644 index 000000000..7e89f9db4 --- /dev/null +++ b/db/migrate/20240513070825_create_sac_section_membership_configs.rb @@ -0,0 +1,37 @@ +# frozen_string_literal: true + +# Copyright (c) 2012-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 CreateSacSectionMembershipConfigs < ActiveRecord::Migration[6.1] + + def change + create_table :sac_section_membership_configs do |t| + t.integer :valid_from, null: false, length: 4 + t.references :group + + # fees + t.decimal :sac_section_fee_adult, precision: 5, scale: 2, null: false + t.decimal :sac_section_fee_family, precision: 5, scale: 2, null: false + t.decimal :sac_section_fee_youth, precision: 5, scale: 2, null: false + t.decimal :entry_fee_adult, precision: 5, scale: 2, null: false + t.decimal :entry_fee_family, precision: 5, scale: 2, null: false + t.decimal :entry_fee_youth, precision: 5, scale: 2, null: false + t.decimal :bulletin_postage_abroad, precision: 5, scale: 2, null: false + + # reductions + t.boolean :sac_fee_exemption_for_honorary_members, null: false, default: false + t.boolean :sac_section_fee_exemption_for_honorary_members, null: false, default: false + t.boolean :sac_fee_exemption_for_benefited_members, null: false, default: false + t.boolean :sac_section_fee_exemption_for_benefited_members, null: false, default: false + t.decimal :reduction_amount, precision: 5, scale: 2, null: false + t.integer :reduction_required_membership_years, null: true + t.integer :reduction_required_age, null: true + end + + add_index :sac_section_membership_configs, [:group_id, :valid_from], unique: true + end + +end diff --git a/db/seeds/development/4_sac_section_membership_configs.rb b/db/seeds/development/4_sac_section_membership_configs.rb new file mode 100644 index 000000000..03c74c1ca --- /dev/null +++ b/db/seeds/development/4_sac_section_membership_configs.rb @@ -0,0 +1,26 @@ +# 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. + +Group::Sektion.all.each do |s| + SacSectionMembershipConfig.seed_once(:valid_from, :group_id, + group_id: s.id, + valid_from: '2024', + sac_section_fee_adult: 42, + sac_section_fee_family: 84, + sac_section_fee_youth: 21, + entry_fee_adult: 10, + entry_fee_family: 20, + entry_fee_youth: 5, + bulletin_postage_abroad: 13, + sac_fee_exemption_for_honorary_members: false, + sac_section_fee_exemption_for_honorary_members: true, + sac_fee_exemption_for_benefited_members: true, + sac_section_fee_exemption_for_benefited_members: false, + reduction_amount: 10, + reduction_required_membership_years: 50, + reduction_required_age: 42) +end diff --git a/db/seeds/development/sac_membership_configs.rb b/db/seeds/development/sac_membership_configs.rb deleted file mode 100644 index ac537137a..000000000 --- a/db/seeds/development/sac_membership_configs.rb +++ /dev/null @@ -1,42 +0,0 @@ -# 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. - -SacMembershipConfig.seed_once(:valid_from, - valid_from: '2024', - sac_fee_adult: 10, - sac_fee_family: 10, - sac_fee_youth: 10, - entry_fee_adult: 10, - entry_fee_family: 10, - entry_fee_youth: 10, - hut_solidarity_fee_with_hut_adult: 10, - hut_solidarity_fee_with_hut_family: 10, - hut_solidarity_fee_with_hut_youth: 10, - hut_solidarity_fee_without_hut_adult: 10, - hut_solidarity_fee_without_hut_family: 10, - hut_solidarity_fee_without_hut_youth: 10, - magazine_fee_adult: 10, - magazine_fee_family: 10, - magazine_fee_youth: 10, - service_fee: 10, - magazine_postage_abroad: 10, - reduction_amount: 10, - reduction_required_membership_years: 50, - discount_date_1: '1.1.', - discount_percent_1: 0, - discount_date_2: '1.7.', - discount_percent_2: 50, - discount_date_3: '1.10.', - discount_percent_3: 100, - sac_fee_article_number: 42, - sac_entry_fee_article_number: 43, - hut_solidarity_fee_article_number: 44, - magazine_fee_article_number: 45, - section_bulletin_postage_abroad_article_number: 46, - service_fee_article_number: 47, - balancing_payment_article_number: 48, - course_fee_article_number: 49) diff --git a/doc/naming.md b/doc/naming.md new file mode 100644 index 000000000..aa497bdb2 --- /dev/null +++ b/doc/naming.md @@ -0,0 +1,21 @@ +# Naming + +## Glossar + +| SAC Begriff DE | Technische Bezeichnung (EN/DE) | Ausnahmen | +|---------------------------|--------------------------------|-------------------------------| +| **Beitragskategorie** | Beitragskategorie | | +| Einzel | adult | | +| Familie | family | | +| Jugend | youth | | +| | | | +| **Gruppen** | | | +| Sektion | sac_section | Group::Sektion | +| Ortsgruppe | | Group::Ortsgruppe | +| | | | +| **Mitgliedschaft** | | | +| Ehrenmitglied | honorary_member | Group::Sektion::Ehrenmitglied | +| Begünstigt | benefited_member | Group::Sektion::Beguenstigt | +| Hüttensolidaritätsbeitrag | hut_solidarity_fee | | +| Zentralverbandsbeitrag | sac_fee | | +| Eintrittsgebühr | entry_fee | | diff --git a/lib/hitobito_sac_cas/wagon.rb b/lib/hitobito_sac_cas/wagon.rb index 5c4cdb011..aaad9cacb 100644 --- a/lib/hitobito_sac_cas/wagon.rb +++ b/lib/hitobito_sac_cas/wagon.rb @@ -65,6 +65,7 @@ class Wagon < Rails::Engine Ability.store.register CostUnitAbility Ability.store.register ExternalTrainingAbility Ability.store.register SacMembershipConfigAbility + Ability.store.register SacSectionMembershipConfigAbility PersonAbility.prepend SacCas::PersonAbility PersonReadables.prepend SacCas::PersonReadables RoleAbility.prepend SacCas::RoleAbility diff --git a/spec/abilities/sac_membership_config_ability_spec.rb b/spec/abilities/sac_membership_config_ability_spec.rb new file mode 100644 index 000000000..cfd5f7bfe --- /dev/null +++ b/spec/abilities/sac_membership_config_ability_spec.rb @@ -0,0 +1,41 @@ +# 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 SacMembershipConfigAbility do + + let(:config) { sac_membership_configs(:'2024') } + let(:admin) { people(:admin) } + let(:mitglied) { people(:mitglied) } + let(:mitarbeiter) do + Fabricate(Group::Geschaeftsstelle::Mitarbeiter.sti_name.to_sym, + group: groups(:geschaeftsstelle)).person + end + let(:mitgliederverwaltung_sektion) do + Fabricate(Group::SektionsFunktionaere::Mitgliederverwaltung.sti_name.to_sym, + group: groups(:bluemlisalp_funktionaere)).person + end + + context 'manage' do + it 'is permitted as admin' do + expect(Ability.new(admin)).to be_able_to(:manage, config) + end + + it 'is not permitted as mitarbeiter' do + expect(Ability.new(mitarbeiter)).not_to be_able_to(:manage, config) + end + + it 'is not permitted as mitglied' do + expect(Ability.new(mitglied)).not_to be_able_to(:manage, config) + end + + it 'is not permitted as mitgliederverwaltung sektion' do + expect(Ability.new(mitgliederverwaltung_sektion)).not_to be_able_to(:manage, config) + end + end +end diff --git a/spec/abilities/sac_section_membership_config_ability_spec.rb b/spec/abilities/sac_section_membership_config_ability_spec.rb new file mode 100644 index 000000000..659448095 --- /dev/null +++ b/spec/abilities/sac_section_membership_config_ability_spec.rb @@ -0,0 +1,49 @@ +# 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 SacSectionMembershipConfigAbility do + + let(:config) { sac_section_membership_configs(:'2024') } + let(:admin) { people(:admin) } + let(:mitgliederverwaltung_sektion) do + Fabricate(Group::SektionsFunktionaere::Mitgliederverwaltung.sti_name.to_sym, + group: groups(:bluemlisalp_funktionaere)).person + end + let(:mitglied) { people(:mitglied) } + + context 'manage' do + it 'is permitted as admin' do + expect(Ability.new(admin)).to be_able_to(:manage, config) + end + + it 'is permitted as mitgliederverwaltung sektion' do + expect(Ability.new(mitgliederverwaltung_sektion)).to be_able_to(:manage, config) + end + + it 'is permitted as mitgliederverwaltung sektion on ortsgruppe' do + ortsgruppen_config = config.dup + ortsgruppen_config.group = groups(:bluemlisalp_ortsgruppe_ausserberg) + ortsgruppen_config.save! + + expect(Ability.new(mitgliederverwaltung_sektion)).to be_able_to(:manage, ortsgruppen_config) + end + + it 'is not permitted for mitglied' do + expect(Ability.new(mitglied)).not_to be_able_to(:manage, config) + end + + it 'is not permitted for mitgliederverwaltung sektion for other sektion' do + other_sac_section_config = config.dup + other_sac_section_config.group = groups(:matterhorn) + other_sac_section_config.save! + + expect(Ability.new(mitgliederverwaltung_sektion)).not_to be_able_to(:manage, other_sac_section_config) + end + end +end diff --git a/spec/controllers/people/membership_controller_spec.rb b/spec/controllers/people/membership_controller_spec.rb index c1d02376c..b42a09652 100644 --- a/spec/controllers/people/membership_controller_spec.rb +++ b/spec/controllers/people/membership_controller_spec.rb @@ -17,7 +17,7 @@ group: groups(:bluemlisalp_mitglieder)) person end - let(:mitgliederdienst) do + let(:mitgliederverwaltung_sektion) do Fabricate(Group::SektionsFunktionaere::Mitgliederverwaltung.sti_name.to_sym, group: groups(:bluemlisalp_funktionaere)).person end @@ -31,7 +31,7 @@ end it 'is possible to download membership pass for writable person' do - sign_in(mitgliederdienst) + sign_in(mitgliederverwaltung_sektion) get :show, params: { id: member.id, format: 'pdf' } @@ -42,7 +42,7 @@ sign_in(member) expect do - get :show, params: { id: mitgliederdienst.id, format: 'pdf' } + get :show, params: { id: mitgliederverwaltung_sektion.id, format: 'pdf' } end.to raise_error(CanCan::AccessDenied) end diff --git a/spec/controllers/sac_membership_configs_controller_spec.rb b/spec/controllers/sac_membership_configs_controller_spec.rb index 72ef3679f..c2e37fb52 100644 --- a/spec/controllers/sac_membership_configs_controller_spec.rb +++ b/spec/controllers/sac_membership_configs_controller_spec.rb @@ -44,6 +44,12 @@ get :index, params: { group_id: Group.root.id } end.to raise_error(CanCan::AccessDenied) end + + it 'is unavailable if access by other group than root layer' do + get :index, params: { group_id: groups(:bluemlisalp) } + + expect(response).to be_not_found + end end context 'GET show' do diff --git a/spec/controllers/sac_section_membership_configs_controller_spec.rb b/spec/controllers/sac_section_membership_configs_controller_spec.rb new file mode 100644 index 000000000..88f02c920 --- /dev/null +++ b/spec/controllers/sac_section_membership_configs_controller_spec.rb @@ -0,0 +1,135 @@ +# 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 SacSectionMembershipConfigsController do + + let(:mitgliederverwaltung_sektion) do + Fabricate(Group::SektionsFunktionaere::Mitgliederverwaltung.sti_name.to_sym, + group: groups(:bluemlisalp_funktionaere)).person + end + let(:latest_config) { sac_section_membership_configs(:'2024') } + let!(:older_config) do + config = latest_config.dup + config.valid_from = 2023 + config.save! + config + end + let(:sektion) { groups(:bluemlisalp) } + + before { sign_in(mitgliederverwaltung_sektion) } + + context 'GET index' do + it 'redirects to latest config edit' do + get :index, params: { group_id: sektion.id } + + expect(response) + .to redirect_to(edit_group_sac_section_membership_config_path(group_id: sektion.id, id: latest_config.id)) + end + + it 'redirects to new if no previous config present' do + SacSectionMembershipConfig.destroy_all + + get :index, params: { group_id: sektion.id } + + expect(response) + .to redirect_to(new_group_sac_section_membership_config_path(group_id: sektion.id)) + end + + it 'cannot be accessed by non admin' do + sign_in(people(:mitglied)) + + expect do + get :index, params: { group_id: sektion.id } + end.to raise_error(CanCan::AccessDenied) + end + + it 'is unavailable if access on non sektion/ortsgruppe' do + get :index, params: { group_id: groups(:bluemlisalp_funktionaere) } + + expect(response).to be_not_found + end + end + + context 'GET show' do + it 'redirects to config edit' do + get :show, params: { group_id: sektion.id, id: older_config.id } + + expect(response) + .to redirect_to(edit_group_sac_section_membership_config_path(group_id: sektion.id, id: older_config.id)) + end + + it 'cannot be accessed by non mitglieder verwaltung' do + sign_in(people(:mitglied)) + + expect do + get :show, params: { group_id: sektion.id, id: older_config.id } + end.to raise_error(CanCan::AccessDenied) + end + end + + context 'GET edit' do + it 'renders config edit form' do + get :edit, params: { group_id: sektion.id, id: latest_config.id } + + expect(response).to be_successful + end + + it 'cannot be accessed by non mitglieder verwaltung' do + sign_in(people(:mitglied)) + + expect do + get :show, params: { group_id: sektion.id, id: latest_config.id } + end.to raise_error(CanCan::AccessDenied) + end + end + + context 'PATCH update' do + let(:updated_model_params) do + { sac_section_membership_config: { sac_section_fee_adult: 52 }} + end + + it 'updates config and redirects to show/edit form' do + patch :update, params: { group_id: sektion.id, id: latest_config.id }.merge(updated_model_params) + + expect(response) + .to redirect_to(group_sac_section_membership_config_path(group_id: sektion.id, id: latest_config.id)) + + latest_config.reload + expect(latest_config.sac_section_fee_adult).to eq(52) + end + + it 'cannot update valid_from' do + updated_model_params[:sac_section_membership_config][:valid_from] = 2020 + patch :update, params: { group_id: sektion.id, id: latest_config.id }.merge(updated_model_params) + + expect(response) + .to redirect_to(group_sac_section_membership_config_path(group_id: sektion.id, id: latest_config.id)) + + latest_config.reload + expect(latest_config.valid_from).to eq(2024) + end + + it 'cannot be accessed by non mitglieder verwaltung' do + sign_in(people(:mitglied)) + + expect do + patch :update, params: { group_id: sektion.id, id: latest_config.id }.merge(updated_model_params) + end.to raise_error(CanCan::AccessDenied) + end + end + + context 'DELETE destroy' do + it 'cannot be destroyed' do + expect do + delete :destroy, params: { group_id: sektion.id, id: older_config.id } + end.to raise_error(ActionController::UrlGenerationError) # aka 404 + end + end + +end diff --git a/spec/fixtures/sac_membership_configs.yml b/spec/fixtures/sac_membership_configs.yml index 0a333ecb5..14b88c31a 100644 --- a/spec/fixtures/sac_membership_configs.yml +++ b/spec/fixtures/sac_membership_configs.yml @@ -1,7 +1,48 @@ -# Copyright (c) 2024 Schweizer Alpen-Club. This file is part of +# 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 +# https://github.com/hitobito/hitobito_sac_cas. + +# == Schema Information +# +# Table name: sac_membership_configs +# +# id :bigint not null, primary key +# valid_from :integer not null +# sac_fee_adult :decimal(5, 2) not null +# sac_fee_family :decimal(5, 2) not null +# sac_fee_youth :decimal(5, 2) not null +# entry_fee_adult :decimal(5, 2) not null +# entry_fee_family :decimal(5, 2) not null +# entry_fee_youth :decimal(5, 2) not null +# hut_solidarity_fee_with_hut_adult :decimal(5, 2) not null +# hut_solidarity_fee_with_hut_family :decimal(5, 2) not null +# hut_solidarity_fee_with_hut_youth :decimal(5, 2) not null +# hut_solidarity_fee_without_hut_adult :decimal(5, 2) not null +# hut_solidarity_fee_without_hut_family :decimal(5, 2) not null +# hut_solidarity_fee_without_hut_youth :decimal(5, 2) not null +# magazine_fee_adult :decimal(5, 2) not null +# magazine_fee_family :decimal(5, 2) not null +# magazine_fee_youth :decimal(5, 2) not null +# service_fee :decimal(5, 2) not null +# magazine_postage_abroad :decimal(5, 2) not null +# reduction_amount :decimal(5, 2) not null +# reduction_required_membership_years :integer +# discount_date_1 :string(255) +# discount_percent_1 :integer +# discount_date_2 :string(255) +# discount_percent_2 :integer +# discount_date_3 :string(255) +# discount_percent_3 :integer +# sac_fee_article_number :string(255) not null +# sac_entry_fee_article_number :string(255) not null +# hut_solidarity_fee_article_number :string(255) not null +# magazine_fee_article_number :string(255) not null +# section_bulletin_postage_abroad_article_number :string(255) not null +# service_fee_article_number :string(255) not null +# balancing_payment_article_number :string(255) not null +# course_fee_article_number :string(255) not null +# '2024': valid_from: '2024' diff --git a/spec/fixtures/sac_section_membership_configs.yml b/spec/fixtures/sac_section_membership_configs.yml new file mode 100644 index 000000000..fef2bbcaa --- /dev/null +++ b/spec/fixtures/sac_section_membership_configs.yml @@ -0,0 +1,45 @@ +# 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. + +# == Schema Information +# +# Table name: sac_section_membership_configs +# +# id :bigint not null, primary key +# valid_from :integer not null +# group_id :bigint +# sac_section_fee_adult :decimal(5, 2) not null +# sac_section_fee_family :decimal(5, 2) not null +# sac_section_fee_youth :decimal(5, 2) not null +# entry_fee_adult :decimal(5, 2) not null +# entry_fee_family :decimal(5, 2) not null +# entry_fee_youth :decimal(5, 2) not null +# bulletin_postage_abroad :decimal(5, 2) not null +# sac_fee_exemption_for_honorary_members :boolean default(FALSE), not null +# sac_section_fee_exemption_for_honorary_members :boolean default(FALSE), not null +# sac_fee_exemption_for_benefited_members :boolean default(FALSE), not null +# sac_section_fee_exemption_for_benefited_members :boolean default(FALSE), not null +# reduction_amount :decimal(5, 2) not null +# reduction_required_membership_years :integer +# reduction_required_age :integer +# + +'2024': + group: bluemlisalp + valid_from: '2024' + sac_section_fee_adult: 42 + sac_section_fee_family: 84 + sac_section_fee_youth: 21 + entry_fee_adult: 10 + entry_fee_family: 20 + entry_fee_youth: 5 + bulletin_postage_abroad: 13 + sac_fee_exemption_for_honorary_members: false + sac_section_fee_exemption_for_honorary_members: true + sac_fee_exemption_for_benefited_members: true + sac_section_fee_exemption_for_benefited_members: false + reduction_amount: 10 + reduction_required_membership_years: 50 + reduction_required_age: 42 diff --git a/spec/models/sac_membership_config_spec.rb b/spec/models/sac_membership_config_spec.rb index 1905d3f6f..e6e076188 100644 --- a/spec/models/sac_membership_config_spec.rb +++ b/spec/models/sac_membership_config_spec.rb @@ -1,10 +1,51 @@ # frozen_string_literal: true - -# Copyright (c) 2012-2023, Schweizer Alpen-Club. This file is part of +# +# 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. +# == Schema Information +# +# Table name: sac_membership_configs +# +# id :bigint not null, primary key +# valid_from :integer not null +# sac_fee_adult :decimal(5, 2) not null +# sac_fee_family :decimal(5, 2) not null +# sac_fee_youth :decimal(5, 2) not null +# entry_fee_adult :decimal(5, 2) not null +# entry_fee_family :decimal(5, 2) not null +# entry_fee_youth :decimal(5, 2) not null +# hut_solidarity_fee_with_hut_adult :decimal(5, 2) not null +# hut_solidarity_fee_with_hut_family :decimal(5, 2) not null +# hut_solidarity_fee_with_hut_youth :decimal(5, 2) not null +# hut_solidarity_fee_without_hut_adult :decimal(5, 2) not null +# hut_solidarity_fee_without_hut_family :decimal(5, 2) not null +# hut_solidarity_fee_without_hut_youth :decimal(5, 2) not null +# magazine_fee_adult :decimal(5, 2) not null +# magazine_fee_family :decimal(5, 2) not null +# magazine_fee_youth :decimal(5, 2) not null +# service_fee :decimal(5, 2) not null +# magazine_postage_abroad :decimal(5, 2) not null +# reduction_amount :decimal(5, 2) not null +# reduction_required_membership_years :integer +# discount_date_1 :string(255) +# discount_percent_1 :integer +# discount_date_2 :string(255) +# discount_percent_2 :integer +# discount_date_3 :string(255) +# discount_percent_3 :integer +# sac_fee_article_number :string(255) not null +# sac_entry_fee_article_number :string(255) not null +# hut_solidarity_fee_article_number :string(255) not null +# magazine_fee_article_number :string(255) not null +# section_bulletin_postage_abroad_article_number :string(255) not null +# service_fee_article_number :string(255) not null +# balancing_payment_article_number :string(255) not null +# course_fee_article_number :string(255) not null +# + require 'spec_helper' describe SacMembershipConfig do diff --git a/spec/models/sac_section_membership_config_spec.rb b/spec/models/sac_section_membership_config_spec.rb new file mode 100644 index 000000000..ae488eb10 --- /dev/null +++ b/spec/models/sac_section_membership_config_spec.rb @@ -0,0 +1,60 @@ +# frozen_string_literal: true + +# == Schema Information +# +# Table name: sac_section_membership_configs +# +# id :bigint not null, primary key +# valid_from :integer not null +# group_id :bigint +# sac_section_fee_adult :decimal(5, 2) not null +# sac_section_fee_family :decimal(5, 2) not null +# sac_section_fee_youth :decimal(5, 2) not null +# entry_fee_adult :decimal(5, 2) not null +# entry_fee_family :decimal(5, 2) not null +# entry_fee_youth :decimal(5, 2) not null +# bulletin_postage_abroad :decimal(5, 2) not null +# sac_fee_exemption_for_honorary_members :boolean default(FALSE), not null +# sac_section_fee_exemption_for_honorary_members :boolean default(FALSE), not null +# sac_fee_exemption_for_benefited_members :boolean default(FALSE), not null +# sac_section_fee_exemption_for_benefited_members :boolean default(FALSE), not null +# reduction_amount :decimal(5, 2) not null +# reduction_required_membership_years :integer +# reduction_required_age :integer +# +# +# 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 SacSectionMembershipConfig do + + let(:config) { sac_section_membership_configs(:'2024') } + + context 'group' do + let(:new_config) { config.dup } + it 'cannot belong to top layer' do + new_config.group = groups(:root) + + expect(new_config).not_to be_valid + error_keys = new_config.errors.keys + expect(error_keys.count).to eq(1) + expect(error_keys).to include(:group) + end + + it 'can belong to sektion' do + new_config.group = groups(:matterhorn) + + expect(new_config).to be_valid + end + + it 'can belong to ortsgruppe' do + new_config.group = groups(:bluemlisalp_ortsgruppe_ausserberg) + + expect(new_config).to be_valid + end + end +end