diff --git a/app/domain/sac_imports/csv_report.rb b/app/domain/sac_imports/csv_report.rb new file mode 100644 index 000000000..807589072 --- /dev/null +++ b/app/domain/sac_imports/csv_report.rb @@ -0,0 +1,48 @@ +# 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 SacImports::CsvReport + def initialize(sac_import_name, headers) + @timestamp = Time.zone.now.strftime("%Y-%m-%d-%H:%M") + @sac_import_name = sac_import_name + @headers = headers + csv_init + end + + def add_row(row) + csv_append(row) + end + + private + + def log_dir + @log_dir ||= create_log_dir + end + + def create_log_dir + log_dir = Rails.root.join("log", "sac_imports") + log_dir.mkpath + log_dir + end + + def csv_init + CSV.open(csv_file_path, "wb", col_sep: ";") do |csv| + csv << @headers + end + end + + def csv_append(row_content) + row_content = @headers.map { |header| row_content[header] } + CSV.open(csv_file_path, "ab", col_sep: ";") do |csv| + csv << row_content + end + end + + def csv_file_path + @csv_file_path ||= "#{log_dir}/#{@sac_import_name}_#{@timestamp}.csv" + end +end diff --git a/app/domain/sac_imports/csv_source_file.rb b/app/domain/sac_imports/csv_source_file.rb new file mode 100644 index 000000000..b006e54f7 --- /dev/null +++ b/app/domain/sac_imports/csv_source_file.rb @@ -0,0 +1,65 @@ +# frozen_string_literal: true + +class SacImports::CsvSourceFile + SOURCE_HEADERS = + {NAV1: {}, + NAV2: { + navision_id: "Mitgliedernummer", + household_key: "Familien-Nr.", + group_navision_id: "Sektion", + person_name: "Name", + navision_membership_years: "Vereinsmitgliederjahre" + }, + NAV3: {}, + WSO21: {}, + WSO22: {}}.freeze + + AVAILABLE_SOURCES = SOURCE_HEADERS.keys.freeze + + def initialize(source_name) + @source_name = source_name + assert_available_source + end + + def rows + data = [] + CSV.foreach(path, headers: true) do |row| + data << process_row(row) + end + data + end + + private + + def process_row(row) + row = row.to_h + hash = {} + headers.keys.each do |header_key| + hash[header_key] = row[headers[header_key]] + end + hash + end + + def path + files = Dir.glob("#{source_dir}/#{@source_name}_*.csv") + if files.empty? + raise("No source file #{@source_name}_*.csv found in RAILS_CORE_ROOT/tmp/sac_imports_src/.") + end + + source_dir.join(files.first) + end + + def headers + SOURCE_HEADERS[@source_name] + end + + def source_dir + Rails.root.join("tmp", "sac_imports_src") + end + + def assert_available_source + unless AVAILABLE_SOURCES.include?(@source_name) + raise "Invalid source name: #{@source_name}\navailable sources: #{AVAILABLE_SOURCES.map(&:to_s).join(", ")}" + end + end +end diff --git a/app/domain/import/huts/hut_chairman_row.rb b/app/domain/sac_imports/huts/hut_chairman_row.rb similarity index 98% rename from app/domain/import/huts/hut_chairman_row.rb rename to app/domain/sac_imports/huts/hut_chairman_row.rb index a2ef89f0d..46bba8128 100644 --- a/app/domain/import/huts/hut_chairman_row.rb +++ b/app/domain/sac_imports/huts/hut_chairman_row.rb @@ -5,7 +5,7 @@ # or later. See the COPYING file at the top-level directory or at # https://github.com/hitobito/hitobito_sac_cas. -module Import::Huts +module SacImports::Huts class HutChairmanRow include RemovingPlaceholderContactRole diff --git a/app/domain/import/huts/hut_chief_row.rb b/app/domain/sac_imports/huts/hut_chief_row.rb similarity index 98% rename from app/domain/import/huts/hut_chief_row.rb rename to app/domain/sac_imports/huts/hut_chief_row.rb index e6e998bd5..6f5879be2 100644 --- a/app/domain/import/huts/hut_chief_row.rb +++ b/app/domain/sac_imports/huts/hut_chief_row.rb @@ -5,7 +5,7 @@ # or later. See the COPYING file at the top-level directory or at # https://github.com/hitobito/hitobito_sac_cas. -module Import::Huts +module SacImports::Huts class HutChiefRow def self.can_process?(row) row[:verteilercode] == 4006 && role_type_for(row).present? diff --git a/app/domain/import/huts/hut_commission_row.rb b/app/domain/sac_imports/huts/hut_commission_row.rb similarity index 98% rename from app/domain/import/huts/hut_commission_row.rb rename to app/domain/sac_imports/huts/hut_commission_row.rb index c92b58003..1d60cd8a1 100644 --- a/app/domain/import/huts/hut_commission_row.rb +++ b/app/domain/sac_imports/huts/hut_commission_row.rb @@ -5,7 +5,7 @@ # or later. See the COPYING file at the top-level directory or at # https://github.com/hitobito/hitobito_sac_cas. -module Import::Huts +module SacImports::Huts class HutCommissionRow def self.can_process?(row) row[:verteilercode] == 4000 && diff --git a/app/domain/import/huts/hut_row.rb b/app/domain/sac_imports/huts/hut_row.rb similarity index 98% rename from app/domain/import/huts/hut_row.rb rename to app/domain/sac_imports/huts/hut_row.rb index f139e1011..260a57bdf 100644 --- a/app/domain/import/huts/hut_row.rb +++ b/app/domain/sac_imports/huts/hut_row.rb @@ -5,7 +5,7 @@ # or later. See the COPYING file at the top-level directory or at # https://github.com/hitobito/hitobito_sac_cas. -module Import::Huts +module SacImports::Huts class HutRow def self.can_process?(row) row[:verteilercode] == 4000 && hut_type(row).present? && diff --git a/app/domain/import/huts/hut_warden_partner_row.rb b/app/domain/sac_imports/huts/hut_warden_partner_row.rb similarity index 99% rename from app/domain/import/huts/hut_warden_partner_row.rb rename to app/domain/sac_imports/huts/hut_warden_partner_row.rb index 9eb671f55..e36c15784 100644 --- a/app/domain/import/huts/hut_warden_partner_row.rb +++ b/app/domain/sac_imports/huts/hut_warden_partner_row.rb @@ -5,7 +5,7 @@ # or later. See the COPYING file at the top-level directory or at # https://github.com/hitobito/hitobito_sac_cas. -module Import::Huts +module SacImports::Huts class HutWardenPartnerRow include RemovingPlaceholderContactRole diff --git a/app/domain/import/huts/hut_warden_row.rb b/app/domain/sac_imports/huts/hut_warden_row.rb similarity index 98% rename from app/domain/import/huts/hut_warden_row.rb rename to app/domain/sac_imports/huts/hut_warden_row.rb index 08e809c15..224423fb3 100644 --- a/app/domain/import/huts/hut_warden_row.rb +++ b/app/domain/sac_imports/huts/hut_warden_row.rb @@ -5,7 +5,7 @@ # or later. See the COPYING file at the top-level directory or at # https://github.com/hitobito/hitobito_sac_cas. -module Import::Huts +module SacImports::Huts class HutWardenRow def self.can_process?(row) row[:verteilercode] == 4005 && role_type_for(row).present? diff --git a/app/domain/import/huts/huts_row.rb b/app/domain/sac_imports/huts/huts_row.rb similarity index 98% rename from app/domain/import/huts/huts_row.rb rename to app/domain/sac_imports/huts/huts_row.rb index cb9645932..8b34397f0 100644 --- a/app/domain/import/huts/huts_row.rb +++ b/app/domain/sac_imports/huts/huts_row.rb @@ -5,7 +5,7 @@ # or later. See the COPYING file at the top-level directory or at # https://github.com/hitobito/hitobito_sac_cas. -module Import::Huts +module SacImports::Huts class HutsRow def self.can_process?(row) row[:verteilercode] == 4000 && group_type(row).present? && diff --git a/app/domain/import/huts/key_deposit_row.rb b/app/domain/sac_imports/huts/key_deposit_row.rb similarity index 99% rename from app/domain/import/huts/key_deposit_row.rb rename to app/domain/sac_imports/huts/key_deposit_row.rb index 507ba8c6a..72497aa5a 100644 --- a/app/domain/import/huts/key_deposit_row.rb +++ b/app/domain/sac_imports/huts/key_deposit_row.rb @@ -5,7 +5,7 @@ # or later. See the COPYING file at the top-level directory or at # https://github.com/hitobito/hitobito_sac_cas. -module Import::Huts +module SacImports::Huts class KeyDepositRow include RemovingPlaceholderContactRole diff --git a/app/domain/import/huts/removing_placeholder_contact_role.rb b/app/domain/sac_imports/huts/removing_placeholder_contact_role.rb similarity index 96% rename from app/domain/import/huts/removing_placeholder_contact_role.rb rename to app/domain/sac_imports/huts/removing_placeholder_contact_role.rb index 54ef1cab5..9dfa4712e 100644 --- a/app/domain/import/huts/removing_placeholder_contact_role.rb +++ b/app/domain/sac_imports/huts/removing_placeholder_contact_role.rb @@ -5,7 +5,7 @@ # or later. See the COPYING file at the top-level directory or at # https://github.com/hitobito/hitobito_sac_cas. -module Import::Huts +module SacImports::Huts module RemovingPlaceholderContactRole def remove_placeholder_contact_role(person) Group::ExterneKontakte::Kontakt diff --git a/app/domain/sac_imports/huts/unsupported_row.rb b/app/domain/sac_imports/huts/unsupported_row.rb new file mode 100644 index 000000000..a64a43844 --- /dev/null +++ b/app/domain/sac_imports/huts/unsupported_row.rb @@ -0,0 +1,22 @@ +# frozen_string_literal: true + +# Copyright (c) 2023, 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 Rails.root.join("lib", "import", "xlsx_reader.rb") + +module SacImports::Huts + class UnsupportedRow + def self.can_process?(row) + true + end + + def initialize(row) + end + + def import! + end + end +end diff --git a/app/domain/import/huts_importer.rb b/app/domain/sac_imports/huts_importer.rb similarity index 85% rename from app/domain/import/huts_importer.rb rename to app/domain/sac_imports/huts_importer.rb index 116d5c77e..23e4c135c 100644 --- a/app/domain/import/huts_importer.rb +++ b/app/domain/sac_imports/huts_importer.rb @@ -15,7 +15,7 @@ require_relative "huts/hut_chairman_row" require_relative "huts/key_deposit_row" -module Import +module SacImports class HutsImporter HEADERS = { contact_navision_id: "Kontaktnr.", @@ -29,14 +29,14 @@ class HutsImporter } IMPORTERS = [ - Import::Huts::HutCommissionRow, - Import::Huts::HutsRow, - Import::Huts::HutRow, - Import::Huts::HutChiefRow, - Import::Huts::HutWardenRow, - Import::Huts::HutWardenPartnerRow, - Import::Huts::HutChairmanRow, - Import::Huts::KeyDepositRow + SacImports::Huts::HutCommissionRow, + SacImports::Huts::HutsRow, + SacImports::Huts::HutRow, + SacImports::Huts::HutChiefRow, + SacImports::Huts::HutWardenRow, + SacImports::Huts::HutWardenPartnerRow, + SacImports::Huts::HutChairmanRow, + SacImports::Huts::KeyDepositRow ] def initialize(path) diff --git a/app/domain/sac_imports/membership_years_report.rb b/app/domain/sac_imports/membership_years_report.rb new file mode 100644 index 000000000..b3fc9cd63 --- /dev/null +++ b/app/domain/sac_imports/membership_years_report.rb @@ -0,0 +1,61 @@ +# 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 SacImports + class MembershipYearsReport + REPORT_HEADERS = [ + :membership_number, :person_name, + :navision_membership_years, :hitobito_membership_years, + :diff, :errors + ].freeze + + def initialize(output: $stdout) + @output = output + @source_file = CsvSourceFile.new(:NAV2) + @csv_report = CsvReport.new(:"6_membership_years_report", REPORT_HEADERS) + end + + def create + data = @source_file.rows + fetch_hitobito_people(data) + data.each do |row| + process_row(row) + end + end + + private + + def process_row(row) + person = @hitobito_people[row[:navision_id].to_i] + @csv_report.add_row( + {membership_number: row[:navision_id], + person_name: row[:person_name], + navision_membership_years: row[:navision_membership_years], + hitobito_membership_years: person&.membership_years, + diff: membership_years_diff(row[:navision_membership_years], person&.membership_years), + errors: errors_for(person)} + ) + end + + def fetch_hitobito_people(data) + people_ids = data.pluck(:navision_id).compact + @hitobito_people = Person.with_membership_years.where(id: people_ids).index_by(&:id) + end + + def membership_years_diff(navision_years, hitobito_years) + return nil if navision_years.blank? || hitobito_years.blank? + + navision_years.to_i - hitobito_years + end + + def errors_for(person) + [].tap do |errors| + errors << "Person not found in hitobito" unless person + end.join(", ").presence + end + end +end diff --git a/app/domain/import/people_importer.rb b/app/domain/sac_imports/people_importer.rb similarity index 97% rename from app/domain/import/people_importer.rb rename to app/domain/sac_imports/people_importer.rb index 08bbfdfd1..8d2c7ef46 100644 --- a/app/domain/import/people_importer.rb +++ b/app/domain/sac_imports/people_importer.rb @@ -7,7 +7,7 @@ require Rails.root.join("lib", "import", "xlsx_reader.rb") -module Import +module SacImports class PeopleImporter class_attribute :headers, default: { navision_id: "Mitgliedernummer", @@ -92,7 +92,7 @@ def skip?(row) end def import_row(row) - entry = ::Import::PersonEntry.new(row, group: contact_role_group, emails: existing_emails) + entry = SacImports::PersonEntry.new(row, group: contact_role_group, emails: existing_emails) if entry.valid? import_person(entry) diff --git a/app/domain/import/person_entry.rb b/app/domain/sac_imports/person_entry.rb similarity index 99% rename from app/domain/import/person_entry.rb rename to app/domain/sac_imports/person_entry.rb index ba3d84dfd..610b831f9 100644 --- a/app/domain/import/person_entry.rb +++ b/app/domain/sac_imports/person_entry.rb @@ -5,7 +5,7 @@ # or later. See the COPYING file at the top-level directory or at # https://github.com/hitobito/hitobito_sac_cas. -module Import +module SacImports class PersonEntry attr_reader :row diff --git a/app/domain/import/sektion/additional_membership.rb b/app/domain/sac_imports/sektion/additional_membership.rb similarity index 98% rename from app/domain/import/sektion/additional_membership.rb rename to app/domain/sac_imports/sektion/additional_membership.rb index 660dd414e..d162aac46 100644 --- a/app/domain/import/sektion/additional_membership.rb +++ b/app/domain/sac_imports/sektion/additional_membership.rb @@ -5,7 +5,7 @@ # or later. See the COPYING file at the top-level directory or at # https://github.com/hitobito/hitobito_sac_cas. -module Import +module SacImports module Sektion class AdditionalMembership < Membership TARGET_ROLE_TYPE = Group::SektionsMitglieder::MitgliedZusatzsektion diff --git a/app/domain/import/sektion/additional_memberships_importer.rb b/app/domain/sac_imports/sektion/additional_memberships_importer.rb similarity index 93% rename from app/domain/import/sektion/additional_memberships_importer.rb rename to app/domain/sac_imports/sektion/additional_memberships_importer.rb index 2c54c2019..769e8c914 100644 --- a/app/domain/import/sektion/additional_memberships_importer.rb +++ b/app/domain/sac_imports/sektion/additional_memberships_importer.rb @@ -7,7 +7,7 @@ require Rails.root.join("lib", "import", "xlsx_reader.rb") -module Import +module SacImports module Sektion class AdditionalMembershipsImporter < MembershipsImporter self.headers = { @@ -24,7 +24,7 @@ class AdditionalMembershipsImporter < MembershipsImporter private def import_row(row) - membership = ::Import::Sektion::AdditionalMembership.new( + membership = SacImports::Sektion::AdditionalMembership.new( row, group: membership_group(row), current_ability: root_ability diff --git a/app/domain/import/sektion/membership.rb b/app/domain/sac_imports/sektion/membership.rb similarity index 99% rename from app/domain/import/sektion/membership.rb rename to app/domain/sac_imports/sektion/membership.rb index 2a66f82b4..f817f0fee 100644 --- a/app/domain/import/sektion/membership.rb +++ b/app/domain/sac_imports/sektion/membership.rb @@ -5,7 +5,7 @@ # or later. See the COPYING file at the top-level directory or at # https://github.com/hitobito/hitobito_sac_cas. -module Import +module SacImports module Sektion class Membership attr_reader :row, :placeholder_contact_group, :current_ability diff --git a/app/domain/import/sektion/memberships_importer.rb b/app/domain/sac_imports/sektion/memberships_importer.rb similarity index 95% rename from app/domain/import/sektion/memberships_importer.rb rename to app/domain/sac_imports/sektion/memberships_importer.rb index 81b5f5e4a..69fb809ea 100644 --- a/app/domain/import/sektion/memberships_importer.rb +++ b/app/domain/sac_imports/sektion/memberships_importer.rb @@ -7,9 +7,9 @@ require Rails.root.join("lib", "import", "xlsx_reader.rb") -module Import +module SacImports module Sektion - class MembershipsImporter < Import::PeopleImporter + class MembershipsImporter < SacImports::PeopleImporter self.headers = { navision_id: "Mitgliedernummer", household_key: "Familien-Nr.", @@ -57,7 +57,7 @@ def membership_group(row) end def import_row(row) - membership = ::Import::Sektion::Membership.new( + membership = SacImports::Sektion::Membership.new( row, group: membership_group(row), placeholder_contact_group: contact_role_group, diff --git a/app/domain/import/sektionen_importer.rb b/app/domain/sac_imports/sektionen_importer.rb similarity index 99% rename from app/domain/import/sektionen_importer.rb rename to app/domain/sac_imports/sektionen_importer.rb index 7caf0a93e..2a6327e56 100644 --- a/app/domain/import/sektionen_importer.rb +++ b/app/domain/sac_imports/sektionen_importer.rb @@ -7,7 +7,7 @@ require Rails.root.join("lib", "import", "xlsx_reader.rb") -module Import +module SacImports class SektionenImporter # rubocop:disable Metrics/ClassLength HEADERS = { navision_id: "Sektionscode", diff --git a/doc/import.md b/doc/import.md index 5a82485d2..73430886e 100644 --- a/doc/import.md +++ b/doc/import.md @@ -4,7 +4,7 @@ oc rsync tmp/xlsx delayed-job-db8bb7688-c6nrn-debug:/app-src/tmp ``` -## Source Files +## CSV Source Files | # | Export | |------|------------------------------------------------------| @@ -20,22 +20,32 @@ oc rsync tmp/xlsx delayed-job-db8bb7688-c6nrn-debug:/app-src/tmp details siehe SAC Jira HIT-490 -## Hitobito SAC Import 1: import:people +Siehe [SacImports::CsvSourceFile](../app/domain/sac_imports/csv_source_file.rb) + +## CSV Report + +Jeder Import erstellt einen CSV Report in RAILS_CORE_ROOT/log/sac_imports/. In diesem wird pro Import-Zeile eine Zeile im Report CSV erstellt. + +`$IMPORT_NAME_$TIMESTAMP.csv`, e.g. `1_people_2024-06-01-12:00.csv` + +Siehe [SacImports::CsvReport](../app/domain/sac_imports/csv_report.rb) + +## 1: sac_imports:1_people Diesen Import immer als erstes laufen lassen damit alle Personen in der DB vorhanden sind und entsprechend in andere Gruppen via Rollen assigned werden können. Importiert alle Navision Kontakte und legt diese Unter `Top-Layer > Navision Import` ab. -`rake import:people FILE=tmp/xlsx/personen.xlsx REIMPORT_ALL=true` +`rake sac_imports:1_people FILE=tmp/xlsx/personen.xlsx REIMPORT_ALL=true` Import Source File: **NAV1** -## Hitobito SAC Import 2: import:sektionen +## 2: sac_imports:2_sektionen Mit diesem Import werden alle Sektionen und Ortsgruppen importiert. Auf jeder Sektion/Ortsgruppe werden auch Attribute wie z.B. Kanton, Gründungsjahr usw. gesetzt -`rake import:sektionen` +`rake sac_imports:2_sektionen` file: $CORE_ROOT/tmp/xlsx/sektionen.xlsx @@ -43,32 +53,39 @@ file: $CORE_ROOT/tmp/xlsx/sektionen.xlsx Import Source File: **NAV6** -## Hitobito SAC Import 3: import:huts +## 3: sac_imports:3_huts Importiert alle Hütten und hängt diese unter den Sektionen entsprechend ein. Ausserdem werden die Hüttenfunktionärs-Rollen gleich mitangelegt. -`rake import:huts` +`rake sac_imports:huts` file: $CORE_ROOT/tmp/xlsx/huetten_beziehungen.xlsx Import Source File: **NAV5** -## Hitobito SAC Import 4: import:memberships +## 4: sac_imports:4_memberships Importiert alle aktiven und inaktiven Stammsektions-Mitglied-Rollen. -`rails import:memberships FILE=tmp/xlsx/mitglieder_aktive.xlsx REIMPORT_ALL=true)` +`rake sac_imports:memberships FILE=tmp/xlsx/mitglieder_aktive.xlsx REIMPORT_ALL=true)` Import Source File: **NAV2** -## Hitobito SAC Import 5: import:additional_memberships +## 5: sac_imports:5_additional_memberships Sicherstellen das Import Mitglieder Stammsektion bereits ausgeführt wurde. Eine Mitgliedschaft Zusatzsektion ist nur möglich falls bereits eine Mitglied Stammsektion Rolle vorhanden ist. -`rails import:additional_memberships FILE=tmp/xlsx/zusatzmitgliedschaften.xlsx REIMPORT_ALL=true)` +`rake sac_imports:5_additional_memberships FILE=tmp/xlsx/zusatzmitgliedschaften.xlsx REIMPORT_ALL=true)` Import Source File: **NAV3** +## 6: sac_imports:6_membership_years_report + +`rake sac_imports:6_membership_years_report` + +- Import Source File: **NAV2** +- CSV Report Output: `RAILS_CORE_ROOT/log/sac_imports/6_membership_years_report_2024-06-01-12:00.csv` + ## Delete all Sektions ```ruby diff --git a/lib/tasks/import.rake b/lib/tasks/sac_imports.rake similarity index 68% rename from lib/tasks/import.rake rename to lib/tasks/sac_imports.rake index b3c110453..b26230e71 100644 --- a/lib/tasks/import.rake +++ b/lib/tasks/sac_imports.rake @@ -5,34 +5,34 @@ # or later. See the COPYING file at the top-level directory or at # https://github.com/hitobito/hitobito_sac_cas. -namespace :import do +namespace :sac_imports do + desc "Import all people from a navision export xlsx" \ + " (options: FILE=tmp/xlsx/personen.xlsx REIMPORT_ALL=true)" + task "1_people": [:environment] do + SacImports::PeopleImporter.new( + Pathname(ENV["FILE"].to_s), + skip_existing: !["1", "true"].include?(ENV["REIMPORT_ALL"].to_s.downcase) + ).import! + end + desc "Import sections from a navision export (tmp/xlsx/sektionen.xlsx)" - task sektionen: [:environment] do + task "2_sektionen": [:environment] do import_file_path = "tmp/xlsx/sektionen.xlsx" sektionen_excel = Rails.root.join(import_file_path) - Import::SektionenImporter.new(sektionen_excel).import! + SacImports::SektionenImporter.new(sektionen_excel).import! end desc "Import huts from a navision export" - task huts: [:environment] do + task "3_huts": [:environment] do import_file_path = "tmp/xlsx/huetten_beziehungen.xlsx" hut_relations_excel = Rails.root.join(import_file_path) - Import::HutsImporter.new(hut_relations_excel).import! - end - - desc "Import all people from a navision export xlsx" \ - " (options: FILE=tmp/xlsx/personen.xlsx REIMPORT_ALL=true)" - task people: [:environment] do - Import::PeopleImporter.new( - Pathname(ENV["FILE"].to_s), - skip_existing: !["1", "true"].include?(ENV["REIMPORT_ALL"].to_s.downcase) - ).import! + SacImports::HutsImporter.new(hut_relations_excel).import! end desc "Import memberships from a navision export xlsx" \ " (options: FILE=tmp/xlsx/mitglieder_aktive.xlsx REIMPORT_ALL=true)" - task memberships: [:environment] do - Import::Sektion::MembershipsImporter.new( + task "4_memberships": [:environment] do + SacImports::Sektion::MembershipsImporter.new( Pathname(ENV["FILE"].to_s), skip_existing: !["1", "true"].include?(ENV["REIMPORT_ALL"].to_s.downcase) ).import! @@ -40,10 +40,15 @@ namespace :import do desc "Import additional memberships from a navision export xlsx" \ " (options: FILE=tmp/xlsx/zusatzmitgliedschaften.xlsx REIMPORT_ALL=true)" - task additonal_memberships: [:environment] do - Import::Sektion::AdditionalMembershipsImporter.new( + task "5_additonal_memberships": [:environment] do + SacImports::Sektion::AdditionalMembershipsImporter.new( Pathname(ENV["FILE"].to_s), skip_existing: !["1", "true"].include?(ENV["REIMPORT_ALL"].to_s.downcase) ).import! end + + desc "Analyse imported and calculated membership years and create report" + task "6_membership_years_report": [:environment] do + SacImports::MembershipYearsReport.new.create + end end diff --git a/spec/controllers/people/membership_invoices_controller_spec.rb b/spec/controllers/people/membership_invoices_controller_spec.rb index 801c7b520..86bcf045c 100644 --- a/spec/controllers/people/membership_invoices_controller_spec.rb +++ b/spec/controllers/people/membership_invoices_controller_spec.rb @@ -58,6 +58,7 @@ end it "cannot send abacus if address is incomplete" do + people(:mitglied).update!(zip_code: nil, town: nil) post :create, params: {group_id: groups(:bluemlisalp_mitglieder).id, person_id: person.id, date: "2015-03-01"} expect(response).to redirect_to(group_person_path(groups(:bluemlisalp_mitglieder).id, person.id)) diff --git a/spec/domain/invoices/abacus/membership_invoice_batcher_spec.rb b/spec/domain/invoices/abacus/membership_invoice_batcher_spec.rb index 3c46ceade..40cf4623c 100644 --- a/spec/domain/invoices/abacus/membership_invoice_batcher_spec.rb +++ b/spec/domain/invoices/abacus/membership_invoice_batcher_spec.rb @@ -30,7 +30,7 @@ SacMembershipConfig.update_all(valid_from: 2020) SacSectionMembershipConfig.update_all(valid_from: 2020) Role.update_all(delete_on: date.end_of_year) - Person.update_all(zip_code: 3600, town: "Thun") + Person.update_all(zip_code: 3600, street: nil, housenumber: nil, town: "Thun", country: nil) Invoices::Abacus::Config.instance_variable_set(:@config, {host: host, mandant: mandant}.stringify_keys) allow(abacus_client).to receive(:token).and_return("42") diff --git a/spec/domain/sac_imports/csv_report_spec.rb b/spec/domain/sac_imports/csv_report_spec.rb new file mode 100644 index 000000000..5225f5efe --- /dev/null +++ b/spec/domain/sac_imports/csv_report_spec.rb @@ -0,0 +1,29 @@ +# 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 SacImports::CsvReport do + let(:headers) { %i[membership_number sac_family_number name stammsektion] } + let(:csv_report) { described_class.new(:"4_import_memberships", headers) } + let(:report_file) { Rails.root.join("log", "sac_imports", "4_import_memberships_#{Time.zone.now.strftime("%Y-%m-%d-%H:%M")}.csv") } + let(:csv_content) { CSV.read(report_file, col_sep: ";") } + + it "creates csv log with headers and appends rows" do + freeze_time + csv_report.add_row({membership_number: 1234, + sac_family_number: "F42", + name: "John Doe", + stammsektion: "SAC Bern"}) + expect(File.exist?(report_file)).to be_truthy + expect(csv_content.first).to eq(headers.map(&:to_s)) + expect(csv_content.second).to eq(["1234", "F42", "John Doe", "SAC Bern"]) + + File.delete(report_file) + expect(File.exist?(report_file)).to be_falsey + end +end diff --git a/spec/domain/sac_imports/csv_source_file_spec.rb b/spec/domain/sac_imports/csv_source_file_spec.rb new file mode 100644 index 000000000..b2183b8cf --- /dev/null +++ b/spec/domain/sac_imports/csv_source_file_spec.rb @@ -0,0 +1,48 @@ +# 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 SacImports::CsvSourceFile do + let(:nav2_csv_fixture) { File.expand_path("../../../fixtures/files/sac_imports_src/NAV2_stammmitgliedschaften_2024-01-04.csv", __FILE__) } + let(:source_file) { described_class.new(@source_name) } + + it "throws error if unavailable source file referenced" do + @source_name = :NAV42 + expect do + source_file + end.to raise_error("Invalid source name: NAV42\navailable sources: #{SacImports::CsvSourceFile::AVAILABLE_SOURCES.map(&:to_s).join(", ")}") + end + + it "throws error if requested source file does not exist" do + @source_name = :NAV2 + expect(Dir) + .to receive(:glob) + .with(Rails.root.join("tmp", "sac_imports_src", "NAV2_*.csv").to_s) + .and_return([]) + + expect do + source_file.rows + end.to raise_error("No source file NAV2_*.csv found in RAILS_CORE_ROOT/tmp/sac_imports_src/.") + end + + it "converts csv content to hashes with key value pairs defined by header mapping" do + @source_name = :NAV2 + expect(Dir) + .to receive(:glob) + .with(Rails.root.join("tmp", "sac_imports_src", "NAV2_*.csv").to_s) + .and_return([nav2_csv_fixture]) + allow(Dir) + .to receive(:glob) + .and_call_original + + rows = source_file.rows + expect(rows.count).to eq(2) + expect(rows.first).to eq({person_name: "Montana Andreas", navision_id: "1000", household_key: nil, group_navision_id: "1500", navision_membership_years: "44"}) + expect(rows.second).to eq({person_name: "Hillary Edmund", navision_id: "600001", household_key: nil, group_navision_id: "1650", navision_membership_years: "9"}) + end +end diff --git a/spec/domain/import/huts/hut_chairman_row_spec.rb b/spec/domain/sac_imports/huts/hut_chairman_row_spec.rb similarity index 94% rename from spec/domain/import/huts/hut_chairman_row_spec.rb rename to spec/domain/sac_imports/huts/hut_chairman_row_spec.rb index c22b6dd1c..b988de968 100644 --- a/spec/domain/import/huts/hut_chairman_row_spec.rb +++ b/spec/domain/sac_imports/huts/hut_chairman_row_spec.rb @@ -7,11 +7,11 @@ require "spec_helper" -describe Import::Huts::HutChairmanRow do +describe SacImports::Huts::HutChairmanRow do let(:importer) { described_class.new(row) } let(:row) do - Import::HutsImporter::HEADERS.keys.index_with { |_symbol| nil }.merge( + SacImports::HutsImporter::HEADERS.keys.index_with { |_symbol| nil }.merge( contact_navision_id: "00003750", contact_name: "Bluemlisalphuette", verteilercode: "4007.0", diff --git a/spec/domain/import/huts/hut_commission_row_spec.rb b/spec/domain/sac_imports/huts/hut_commission_row_spec.rb similarity index 92% rename from spec/domain/import/huts/hut_commission_row_spec.rb rename to spec/domain/sac_imports/huts/hut_commission_row_spec.rb index e39554c6e..2bcccee80 100644 --- a/spec/domain/import/huts/hut_commission_row_spec.rb +++ b/spec/domain/sac_imports/huts/hut_commission_row_spec.rb @@ -7,11 +7,11 @@ require "spec_helper" -describe Import::Huts::HutCommissionRow do +describe SacImports::Huts::HutCommissionRow do let(:importer) { described_class.new(row) } let(:row) do - Import::HutsImporter::HEADERS.keys.index_with { |_symbol| nil }.merge( + SacImports::HutsImporter::HEADERS.keys.index_with { |_symbol| nil }.merge( contact_navision_id: "99993750", contact_name: "3750 SAC Blüemlisalp", hut_category: "SAC Clubhütte", diff --git a/spec/domain/import/huts/hut_row_spec.rb b/spec/domain/sac_imports/huts/hut_row_spec.rb similarity index 93% rename from spec/domain/import/huts/hut_row_spec.rb rename to spec/domain/sac_imports/huts/hut_row_spec.rb index 5a9b27490..6c2fab48e 100644 --- a/spec/domain/import/huts/hut_row_spec.rb +++ b/spec/domain/sac_imports/huts/hut_row_spec.rb @@ -7,11 +7,11 @@ require "spec_helper" -describe Import::Huts::HutRow do +describe SacImports::Huts::HutRow do let(:importer) { described_class.new(row) } let(:row) do - Import::HutsImporter::HEADERS.keys.index_with { |_symbol| nil }.merge( + SacImports::HutsImporter::HEADERS.keys.index_with { |_symbol| nil }.merge( contact_navision_id: "99993750", contact_name: "3750 SAC Blüemlisalp", hut_category: "SAC Clubhütte", diff --git a/spec/domain/import/huts/hut_warden_partner_row_spec.rb b/spec/domain/sac_imports/huts/hut_warden_partner_row_spec.rb similarity index 94% rename from spec/domain/import/huts/hut_warden_partner_row_spec.rb rename to spec/domain/sac_imports/huts/hut_warden_partner_row_spec.rb index 04fa03947..0f20c184e 100644 --- a/spec/domain/import/huts/hut_warden_partner_row_spec.rb +++ b/spec/domain/sac_imports/huts/hut_warden_partner_row_spec.rb @@ -7,11 +7,11 @@ require "spec_helper" -describe Import::Huts::HutWardenPartnerRow do +describe SacImports::Huts::HutWardenPartnerRow do let(:importer) { described_class.new(row) } let(:row) do - Import::HutsImporter::HEADERS.keys.index_with { |_symbol| nil }.merge( + SacImports::HutsImporter::HEADERS.keys.index_with { |_symbol| nil }.merge( contact_navision_id: "00003750", contact_name: "Bluemlisalphuette", hut_category: "SAC Clubhütte", diff --git a/spec/domain/import/huts/huts_row_spec.rb b/spec/domain/sac_imports/huts/huts_row_spec.rb similarity index 93% rename from spec/domain/import/huts/huts_row_spec.rb rename to spec/domain/sac_imports/huts/huts_row_spec.rb index 28b7cdec1..8979ecdcb 100644 --- a/spec/domain/import/huts/huts_row_spec.rb +++ b/spec/domain/sac_imports/huts/huts_row_spec.rb @@ -7,11 +7,11 @@ require "spec_helper" -describe Import::Huts::HutsRow do +describe SacImports::Huts::HutsRow do let(:importer) { described_class.new(row) } let(:row) do - Import::HutsImporter::HEADERS.keys.index_with { |_symbol| nil }.merge( + SacImports::HutsImporter::HEADERS.keys.index_with { |_symbol| nil }.merge( contact_navision_id: "99993750", contact_name: "3750 SAC Blüemlisalp", hut_category: "SAC Clubhütte", diff --git a/spec/domain/import/huts/key_deposit_row_spec.rb b/spec/domain/sac_imports/huts/key_deposit_row_spec.rb similarity index 95% rename from spec/domain/import/huts/key_deposit_row_spec.rb rename to spec/domain/sac_imports/huts/key_deposit_row_spec.rb index 9db155dd1..7d8ad0173 100644 --- a/spec/domain/import/huts/key_deposit_row_spec.rb +++ b/spec/domain/sac_imports/huts/key_deposit_row_spec.rb @@ -7,11 +7,11 @@ require "spec_helper" -describe Import::Huts::KeyDepositRow do +describe SacImports::Huts::KeyDepositRow do let(:importer) { described_class.new(row) } let(:row) do - Import::HutsImporter::HEADERS.keys.index_with { |_symbol| nil }.merge( + SacImports::HutsImporter::HEADERS.keys.index_with { |_symbol| nil }.merge( contact_navision_id: "00003750", contact_name: "Bluemlisalphuette", hut_category: "SAC Clubhütte", diff --git a/spec/domain/sac_imports/membership_years_report_spec.rb b/spec/domain/sac_imports/membership_years_report_spec.rb new file mode 100644 index 000000000..1e9d45b09 --- /dev/null +++ b/spec/domain/sac_imports/membership_years_report_spec.rb @@ -0,0 +1,35 @@ +# 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 SacImports::MembershipYearsReport do + let(:nav2_csv_fixture) { File.expand_path("../../../fixtures/files/sac_imports_src/NAV2_stammmitgliedschaften_2024-01-04.csv", __FILE__) } + let(:report) { described_class.new } + let(:report_file) { Rails.root.join("log", "sac_imports", "6_membership_years_report_2024-01-23-11:42.csv") } + let(:report_headers) { %w[membership_number person_name navision_membership_years hitobito_membership_years diff errors] } + let(:csv_report) { CSV.read(report_file, col_sep: ";") } + + it "creates report for members in source file" do + expect(Dir) + .to receive(:glob) + .with(Rails.root.join("tmp", "sac_imports_src", "NAV2_*.csv").to_s) + .and_return([nav2_csv_fixture]) + + travel_to DateTime.new(2024, 1, 23, 10, 42) + + report.create + + expect(File.exist?(report_file)).to be_truthy + expect(csv_report.first).to eq(report_headers) + expect(csv_report.second).to eq(["1000", "Montana Andreas", "44", nil, nil, "Person not found in hitobito"]) + expect(csv_report.third).to eq(["600001", "Hillary Edmund", "9", "1", "8", nil]) + + File.delete(report_file) + expect(File.exist?(report_file)).to be_falsey + end +end diff --git a/spec/domain/import/people_importer_integration_spec.rb b/spec/domain/sac_imports/people_importer_integration_spec.rb similarity index 98% rename from spec/domain/import/people_importer_integration_spec.rb rename to spec/domain/sac_imports/people_importer_integration_spec.rb index 02223bf2a..a700b7757 100644 --- a/spec/domain/import/people_importer_integration_spec.rb +++ b/spec/domain/sac_imports/people_importer_integration_spec.rb @@ -7,7 +7,7 @@ require "spec_helper" -describe Import::PeopleImporter do +describe SacImports::PeopleImporter do let(:file) { file_fixture("kontakte.xlsx") } let(:importer) { described_class.new(file, output: double(puts: nil)) } diff --git a/spec/domain/import/people_importer_spec.rb b/spec/domain/sac_imports/people_importer_spec.rb similarity index 97% rename from spec/domain/import/people_importer_spec.rb rename to spec/domain/sac_imports/people_importer_spec.rb index 72522de1a..d4fc19677 100644 --- a/spec/domain/import/people_importer_spec.rb +++ b/spec/domain/sac_imports/people_importer_spec.rb @@ -7,13 +7,13 @@ require "spec_helper" -describe Import::PeopleImporter do +describe SacImports::PeopleImporter do let(:root) { Fabricate(:person, email: Settings.root_email) } let(:group) { groups(:bluemlisalp) } def attrs(**attrs) @navision_id ||= 123 - Import::PeopleImporter.headers.keys.map { |symbol| [symbol, nil] }.to_h.merge( + SacImports::PeopleImporter.headers.keys.map { |symbol| [symbol, nil] }.to_h.merge( navision_id: attrs[:navision_id] || @navision_id += 1, birthday: 40.years.ago.to_date, language: :DES, diff --git a/spec/domain/import/person_entry_spec.rb b/spec/domain/sac_imports/person_entry_spec.rb similarity index 97% rename from spec/domain/import/person_entry_spec.rb rename to spec/domain/sac_imports/person_entry_spec.rb index 6e483b184..ed2e89ed3 100644 --- a/spec/domain/import/person_entry_spec.rb +++ b/spec/domain/sac_imports/person_entry_spec.rb @@ -7,11 +7,11 @@ require "spec_helper" -describe Import::PersonEntry do +describe SacImports::PersonEntry do let(:emails) { [] } let(:group) { Group::ExterneKontakte.new(id: 1) } let(:row) do - Import::PeopleImporter.headers.keys.index_with { |_symbol| nil }.merge( + SacImports::PeopleImporter.headers.keys.index_with { |_symbol| nil }.merge( navision_id: 123, first_name: "Max", last_name: "Muster", diff --git a/spec/domain/import/sektion/additional_membership_importer_integration_spec.rb b/spec/domain/sac_imports/sektion/additional_membership_importer_integration_spec.rb similarity index 95% rename from spec/domain/import/sektion/additional_membership_importer_integration_spec.rb rename to spec/domain/sac_imports/sektion/additional_membership_importer_integration_spec.rb index 00dbecdde..6715561d6 100644 --- a/spec/domain/import/sektion/additional_membership_importer_integration_spec.rb +++ b/spec/domain/sac_imports/sektion/additional_membership_importer_integration_spec.rb @@ -7,7 +7,7 @@ require "spec_helper" -describe Import::Sektion::AdditionalMembershipsImporter do +describe SacImports::Sektion::AdditionalMembershipsImporter do let(:file) { file_fixture("zusatzmitgliedschaften.xlsx") } let(:importer) { described_class.new(file, output: double(puts: nil)) } diff --git a/spec/domain/import/sektion/additional_membership_importer_spec.rb b/spec/domain/sac_imports/sektion/additional_membership_importer_spec.rb similarity index 96% rename from spec/domain/import/sektion/additional_membership_importer_spec.rb rename to spec/domain/sac_imports/sektion/additional_membership_importer_spec.rb index 054007436..53b8cf8a7 100644 --- a/spec/domain/import/sektion/additional_membership_importer_spec.rb +++ b/spec/domain/sac_imports/sektion/additional_membership_importer_spec.rb @@ -7,7 +7,7 @@ require "spec_helper" -describe Import::Sektion::AdditionalMembershipsImporter do +describe SacImports::Sektion::AdditionalMembershipsImporter do let(:group) { groups(:bluemlisalp) } let(:membership_group) { groups(:bluemlisalp_mitglieder) } @@ -108,7 +108,7 @@ def attrs(create_person: true, **attrs) end it "assigns beitragskategorie from file" do - Import::Sektion::Membership::BEITRAGSKATEGORIEN.each do |key, value| + SacImports::Sektion::Membership::BEITRAGSKATEGORIEN.each do |key, value| expect(importer).to receive(:each_row).and_yield(attrs(beitragskategorie: key)) expect { importer.import! }.to change { Role.count }.by(1) expect(Role.last.beitragskategorie).to eq value.to_s diff --git a/spec/domain/import/sektion/membership_importer_integration_spec.rb b/spec/domain/sac_imports/sektion/membership_importer_integration_spec.rb similarity index 98% rename from spec/domain/import/sektion/membership_importer_integration_spec.rb rename to spec/domain/sac_imports/sektion/membership_importer_integration_spec.rb index a9c85e155..b732bc6e3 100644 --- a/spec/domain/import/sektion/membership_importer_integration_spec.rb +++ b/spec/domain/sac_imports/sektion/membership_importer_integration_spec.rb @@ -7,7 +7,7 @@ require "spec_helper" -describe Import::Sektion::MembershipsImporter do +describe SacImports::Sektion::MembershipsImporter do let(:file) { file_fixture("mitglieder_aktive.xlsx") } let(:importer) { described_class.new(file, output: double(puts: nil)) } diff --git a/spec/domain/import/sektion/membership_importer_spec.rb b/spec/domain/sac_imports/sektion/membership_importer_spec.rb similarity index 98% rename from spec/domain/import/sektion/membership_importer_spec.rb rename to spec/domain/sac_imports/sektion/membership_importer_spec.rb index 9ef262e85..96ea1673c 100644 --- a/spec/domain/import/sektion/membership_importer_spec.rb +++ b/spec/domain/sac_imports/sektion/membership_importer_spec.rb @@ -7,7 +7,7 @@ require "spec_helper" -describe Import::Sektion::MembershipsImporter do +describe SacImports::Sektion::MembershipsImporter do let(:group) { groups(:bluemlisalp) } def attrs(**attrs) @@ -54,7 +54,7 @@ def attrs(**attrs) expect(importer).to receive(:each_row).and_yield(attrs(last_exit_date: nil)) expect { importer.import! }.to change { Role.count }.by(1) - expect(Role.last.delete_on).to eq Import::Sektion::Membership::DEFAULT_DELETE_ON + expect(Role.last.delete_on).to eq SacImports::Sektion::Membership::DEFAULT_DELETE_ON end it "sets correct deleted_at for terminated membership" do diff --git a/spec/domain/import/sektion/membership_spec.rb b/spec/domain/sac_imports/sektion/membership_spec.rb similarity index 98% rename from spec/domain/import/sektion/membership_spec.rb rename to spec/domain/sac_imports/sektion/membership_spec.rb index 22ebad5b2..b78d4564b 100644 --- a/spec/domain/import/sektion/membership_spec.rb +++ b/spec/domain/sac_imports/sektion/membership_spec.rb @@ -7,7 +7,7 @@ require "spec_helper" -describe Import::Sektion::Membership do +describe SacImports::Sektion::Membership do let(:navision_id) { 123 } let(:group) { groups(:bluemlisalp_mitglieder) } let(:attrs) do diff --git a/spec/domain/import/sektionen_importer_spec.rb b/spec/domain/sac_imports/sektionen_importer_spec.rb similarity index 99% rename from spec/domain/import/sektionen_importer_spec.rb rename to spec/domain/sac_imports/sektionen_importer_spec.rb index 599ef3a63..a28aca63a 100644 --- a/spec/domain/import/sektionen_importer_spec.rb +++ b/spec/domain/sac_imports/sektionen_importer_spec.rb @@ -7,7 +7,7 @@ require "spec_helper" -describe Import::SektionenImporter do +describe SacImports::SektionenImporter do let(:file) { file_fixture("sektionen.xlsx") } let(:importer) { described_class.new(file, output: double(puts: nil)) } let(:bluemlisalp) { Group::Sektion.find_by!(navision_id: 1650) } diff --git a/spec/fixtures/files/sac_imports_src/NAV2_stammmitgliedschaften_2024-01-04.csv b/spec/fixtures/files/sac_imports_src/NAV2_stammmitgliedschaften_2024-01-04.csv new file mode 100644 index 000000000..e23cb7542 --- /dev/null +++ b/spec/fixtures/files/sac_imports_src/NAV2_stammmitgliedschaften_2024-01-04.csv @@ -0,0 +1,3 @@ +Adressnummer,Mitgliedernummer,Mitgliederart,PUK-Code,Mitgliederart Statistik,Sektion,Letztes Eintrittsdatum,Letztes Austrittsdatum,Geburtsdatum,Familien-Nr.,Letzter Austrittscode,Letztes Kündigungsdatum,Kategorie,Sonderregelung,Gruppe für Fakturierung,Rabatt-% Mitgliederbeitrag,Anzahl für Fakturierung,Verbandsbeitrag,Beitrag Fakturaelemente,Beitrag PR,Beitrag Fachgruppe,Beitrag Sektion,Kommentar,Code ABC,Nächstes Rechnungsdatum,Rechnungsart,Beitrag Zusatz1,Letztes Rechnungsdatum,Letzte Rechnungsnummer,Letzte Rechnungsart,Beitrag Zusatz2,Name,Adresszusatz,Adresse,Postfach,PLZ,Ort,Länder-/Regionscode,Telefon,Sprachcode,Saldo,Kreditor,AHV Nummer,Sozialversicherungsnr.,Todesdatum,Nationalität,Jahr Abschluss,Heimatort,Geburtsname,Eintrittscode,Eintrittscode Bezeichnung,Statistikcode 1,Statistikcode 2,Statistikcode 3,Statistikcode 4,Statistikcode 5,Statistikcode 6,Statistikcode 7,Statistikcode 8,Statistikcode 9,Statistikcode 10,Nur Abonnent,Rech. an Deb.-Nr.,Im Wizard-Erstellungsprozess,Kanton,Anzahl Option 1,Anzahl Option 2,Anzahl Alle Optionen,Sektionstext,Austrittscodetext,Fakturierungsgruppetext,CodeABC Text,Kategorietext,Anzahl Bereich leer,Tagesfakturen vorhanden,Stornos vorhanden,Erfasst von,Erfasst am,Erfasst um,Aktualisiert von,Aktualisiert am,Aktualisiert um,Bemerkungen,Art,Vorname,Vorname 2,Nachname,Titel,Mobiltelefon,Anredecode,Ehrenmitglied SAC,Ehrenmitglied Sektion,Begünstigter Sektion,Anzahl Mitgliederjahre,Eintrittsjahr,Vereinsmitgliederjahre,Anerkannter Tourenleiter,TL-Portal History vorhanden,Mitglied einer erlaubten Sektion,Sistierter Tourenleiter,Verteiler Aktivstatus,Aktive Sektionen,E-Mail,Contact E-Mail,Contact E-mail Privat,Geplanter Austritt,Mahnstufe,Letzter Sektionswechsel am,Ersteintritt,Letzter Kategoriewechsel am,Letzte Kategorie,Hat Inaktives SKB Element,Briefanrede,Telefon direkt,Telefon Privat,Set Adressaufbereitung,Personentyp,Postleitzahl Id,Aufbereitete Namenzeile,Strasse Id,Gültige Strassen Id,Gültige Post Code Id,Hausnummer,Gültige Hausnummer,Adressfelder tauschen,Strassen Name,Gültige Adresse,Zweitname,Zweitvorname,Anredecode 2,Briefanrede 2,Geschlecht +1000,1000,Aktiv,zM42FmYADP,,1500,25/07/2022,,1/01/1946,,,,EINZEL,Nein,,0,0,Nein,Nein,Nein,Nein,Nein,,,,Normal,Nein,,,Rechnung,Nein,Montana Andreas,,Bergstutz 42,,3920,Zermatt,,,DES,0,Nein,,,,,0,,,,,,,,,,,,,,,Nein,4242,Nein,BE,0,0,0,1500 SAC Bern,,,,Einzelmitglied,0,Nein,Nein,,,,SAC\ADMINISTRATOR,30/11/2023,15:07:00.287,,Hauptadresse,Andreas,,Montana,,,HERR,Nein,Nein,Nein,44,1973,44,Nein,Nein,Ja,Nein,Nein,1,,,,,0,,1/01/1973,25/07/2022,EINZEL,Ja,Sehr geehrter Herr Montana,,,STD,natürlich,2098,,61171,Ja,Ja,42,Ja,Nein,Bergstutz,Ja,,,,,Männlich +600001,600001,Aktiv,,,1650,01/01/2015,,01/01/2000,,,,EINZEL,Nein,,0,0,Nein,Nein,Nein,Nein,Nein,,,,Normal,Nein,,,Rechnung,Nein,Hillary Edmund,,Ophovenerstrasse 79a,,2843,Neu Carlscheid,,,DES,0,Nein,,,,,0,,,,,,,,,,,,,,,Nein,4241,Nein,GE,0,0,0,1650 SAC Blüemlisalp,,,,Einzelmitglied,0,Nein,Nein,,,,SAC\ADMINISTRATOR,3/4/2020,17:07:00.337,,Hauptadresse,Edmund,,Hillary,,,HERR,Nein,Nein,Nein,9,2015,9,Nein,Nein,Ja,Nein,Nein,1,,,,,0,,01/01/15,,,Ja,Sehr geehrter Herr Hillary,,,STD,natürlich,4242,,135323,Ja,Ja,79a,Ja,Nein,Ophovenerstrasse,Ja,,,,,Männlich diff --git a/spec/fixtures/people.yml b/spec/fixtures/people.yml index 04e07c49f..19fc93058 100644 --- a/spec/fixtures/people.yml +++ b/spec/fixtures/people.yml @@ -23,6 +23,11 @@ mitglied: id: 600_001 first_name: Edmund last_name: Hillary + street: Ophovenerstrasse + housenumber: 79a + zip_code: 2843 + town: Neu Carlscheid + country: CH email: e.hillary@hitobito.example.com primary_group: bluemlisalp_mitglieder birthday: <%= Date.new(2000, 1,1) %>