Skip to content

Commit

Permalink
Wip sections seed/import
Browse files Browse the repository at this point in the history
  • Loading branch information
mtnstar committed Sep 25, 2024
1 parent fadac6e commit 08458a3
Show file tree
Hide file tree
Showing 7 changed files with 618 additions and 14 deletions.
75 changes: 61 additions & 14 deletions app/domain/sac_imports/csv_source.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
# https://github.com/hitobito/hitobito_sac_cas.

class SacImports::CsvSource
SOURCE_DIR = Rails.root.join("tmp", "sac_imports_src").freeze
NIL_VALUES = ["", "NULL", "null", "Null"].freeze
SOURCE_HEADERS = {
NAV1: {
Expand Down Expand Up @@ -43,6 +44,43 @@ class SacImports::CsvSource
navision_membership_years: "Vereinsmitgliederjahre"
},
# NAV3: {},
NAV6: {
navision_id: "NAV Sektions-ID",
level_1_id: "Level 1",
level_2_id: "Level 2",
level_3_id: "Level 3",
is_active: "Ist aktiv",
section_name: "Name",
address: "Adresse",
postbox: "Zusätzliche Adresszeile",
town: "Ort",
zip_code: "PLZ",
canton: "Kanton",
phone_nr: "Telefonnummer",
email: "Haupt-E-Mail",
has_jo: "Hat JO",
youth_homepage: "Homepage Jugend",
foundation_year: "Gründungsjahr",
self_registration_without_confirmation: "Mit Freigabeprozess",
termination_by_section_only: "Austritt nur durch Sektion",
language: "Sprache",
membership_configs: {
section_fee_adult: "Sektionsbeitrag Mitgliedschaft Einzel",
section_fee_family: "Sektionsbeitrag Mitgliedschaft Familie",
section_fee_youth: "Sektionsbeitrag Mitgliedschaft Jugend",
section_entry_fee_adult: "Eintrittsgebühr Mitgliedschaft Einzel",
section_entry_fee_family: "Eintrittsgebühr Mitgliedschaft Familie",
section_entry_fee_youth: "Eintrittsgebühr Mitgliedschaft Jugend",
bulletin_postage_abroad: "Porto Ausland Sektionsbulletin",
sac_fee_exemption_for_honorary_members: "Zentralverbandsgebührenerlass für Ehrenmitglieder",
section_fee_exemption_for_honorary_members: "Sektionsgebührenerlass für Ehrenmitglieder",
sac_fee_exemption_for_benefited_members: "Zentralverbandsgebührenerlass für Begünstigte",
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"
}
},
WSO21: {
wso2_legacy_password_hash: "UM_USER_PASSWORD",
wso2_legacy_password_salt: "UM_SALT_VALUE",
Expand Down Expand Up @@ -71,7 +109,8 @@ class SacImports::CsvSource

AVAILABLE_SOURCES = SOURCE_HEADERS.keys.freeze

def initialize(source_name)
def initialize(source_name, source_dir: SOURCE_DIR)
@source_dir = source_dir
@source_name = source_name
assert_available_source
end
Expand All @@ -88,31 +127,39 @@ def rows

def process_row(row)
row = row.to_h
hash = {}
headers.keys.each do |header_key|
value = row[headers[header_key]]
value = nil if NIL_VALUES.include?(value)

headers.each_with_object({}) do |(header_key, source_key), hash|
if source_key.is_a?(Hash)
sub_hash = source_key
value = process_sub_hash(sub_hash, row)
else
value = row[source_key]
value = clean_value(value)
end
hash[header_key] = value
end
hash
end

def process_sub_hash(sub_hash, row)
sub_hash.each_with_object({}) do |(sub_header_key, source_key), sub_hash|
sub_hash[sub_header_key] = clean_value(row[source_key])
end
end

def clean_value(value)
NIL_VALUES.include?(value) ? nil : value
end

def path
files = Dir.glob("#{source_dir}/#{@source_name}_*.csv")
raise("No source file #{@source_name}_*.csv found in #{source_dir}.") if files.empty?
files = Dir.glob("#{@source_dir}/#{@source_name}_*.csv")
raise("No source file #{@source_name}_*.csv found in #{@source_dir}.") if files.empty?

source_dir.join(files.last)
@source_dir.join(files.last)
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(", ")}"
Expand Down
173 changes: 173 additions & 0 deletions app/domain/sac_imports/sac_sections/group_entry.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
# 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 SacSections::GroupEntry
#PERSON_TYPES = {"1": "person", "2": "company"}.freeze
#DEFAULT_LANGUAGE = "de"

attr_reader :row

def initialize(row)
@row = row
end

def parent
@parent ||= fetch_parent
end

def group_type
parent.id != Group.root.id ? Group::Ortsgruppe : Group::Sektion
end

def group
@group ||= group_type.find_or_initialize_by(navision_id: navision_id).tap do |group|
assign_public_attributes(group)
end
end

def valid?
@valid ||= group.valid?
end

def errors
@errors ||= valid? ? [] : build_error_messages
end

def section_name
row[:section_name].gsub(/^#{navision_id}\s/, '')
end

def import!
group.save!
setup_self_registration
assign_membership_configs
archive_group! if row[:is_active] == "0"
end

private

def setup_self_registration
neuanmeldungen_group.update!(custom_self_registration_title: self_registration_title)
end

def neuanmeldungen_group
if row[:self_registration_without_confirmation] == "1"
Group::SektionsNeuanmeldungenNv.find_by(parent_id: group.id)
else
Group::SektionsNeuanmeldungenSektion.find_or_create_by(parent_id: group.id)
end
end

def self_registration_title
t(row, "groups/self_registration.new.title", group_name: group.name)
end

def navision_id
@navision_id ||= Integer(row[:navision_id]).to_s
end

def fetch_parent
if row[:level_3_id].present?
return Group::Sektion.find_by(navision_id: row[:level_3_id])
end

Group.root
end

def archive_group!
# we cannot use default archive function since this is not possible
# for groups with children
# so just setting archived_at for now
Group.where(layer_group_id: group.id).update_all(archived_at: Time.zone.now)
end

def parse_address
address = row[:address]
return if address.blank?

Address::Parser.new(address).parse
end

def assign_public_attributes(group) # rubocop:disable Metrics/AbcSize
group.parent = parent
group.name = section_name

group.postbox = row[:postbox]
group.street, group.housenumber = parse_address
group.zip_code = row[:zip_code]
group.town = row[:town]

group.foundation_year = row[:foundation_year]
group.section_canton = row[:canton]
group.language = language(row)
group.mitglied_termination_by_section_only = row[:termination_by_section_only] == "1"

set_youth_homepage(row, group)
end

def assign_private_attributes(group)
#if email.present?
#person.email = email
## Do not call person#confirm here as it persists the record.
## Instead we set confirmed_at manually.
#person.confirmed_at = Time.zone.at(0)
#end
end

def assign_membership_configs
CsvSource::SOURCE_HEADERS[:NAV6][:membership_configs].keys.each do |key|
membership_config.send("#{key}=", row[:membership_configs][key])
end
membership_config.save!
end

def membership_config
@membership_config ||=
group.sac_section_membership_configs.find_or_initialize_by(group_id: group.id, valid_from: 2024)
end

def phone_valid?(number)
number.present? && Phonelib.valid?(number)
end

def language(row)
row[:language][0..1].upcase
end

def set_youth_homepage(row, group)
has_jo = row[:has_jo] == "1"
return nil unless has_jo

group.social_accounts.where(label: "Homepage Jugend").destroy_all
group.social_accounts.build(name: row[:youth_homepage], label: "Homepage Jugend")
end


def build_phone_numbers(person)
# rubocop:disable Lint/SymbolConversion
phone_numbers = {
"Hauptnummer": row[:phone]
}.freeze
# rubocop:enable Lint/SymbolConversion

phone_numbers.each do |label, number|
person.phone_numbers.build(number: number, label: label) if phone_valid?(number)
end
end

#def build_error_messages
#[person.errors.full_messages, person.roles.first.errors.full_messages].flatten.compact.join(", ")
#end

def t(row, key, args)
I18n.with_locale(group.language.downcase) do
I18n.t(key, **args)
end
end
end
end
67 changes: 67 additions & 0 deletions app/domain/sac_imports/sac_sections_importer.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
# 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 SacSectionsImporter
# REPORT_HEADERS = [
#:navision_membership_number,
#:navision_name,
#:errors
#]

def initialize(output: $stdout)
@output = output
@source_dir = source_dir
@source_file = CsvSource.new(:NAV6, source_dir: @source_dir)
#@csv_report = CsvReport.new(:"1_people", REPORT_HEADERS)
end

def create
section_rows.each do |row|
process_row(row)
end

# ortsgruppe needs parent section to exist
ortsgruppen_rows.each do |row|
process_row(row)
end
#@csv_report.finalize(output: @output)
end

private

def source_dir
Pathname.new(HitobitoSacCas::Wagon.root.join("db", "seeds", "sac_sections"))
end

def data
@data ||= @source_file.rows
end

def section_rows
data.select do |row|
row[:level_3_id].blank?
end
end

def ortsgruppen_rows
data.select do |row|
row[:level_3_id].present?
end
end

def process_row(row)
@output.print("#{row[:section_name]}:")
entry = SacSections::GroupEntry.new(row)
entry_valid = entry.valid?
@output.print(entry_valid ? " ✅\n" : " ❌ #{entry.errors}\n")
if entry_valid
entry.import!
end
end
end
end
4 changes: 4 additions & 0 deletions db/seeds/groups.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
# or later. See the COPYING file at the top-level directory or at
# https://github.com/hitobito/hitobito_sac_cas.

require HitobitoSacCas::Wagon.root.join("db", "seeds", "sac_sections", "seeder")

def seed_magazin_abo(name, parent)
Group::AboMagazin.seed_once(:parent_id, :name) do |a|
a.parent_id = parent.id
Expand Down Expand Up @@ -34,3 +36,5 @@ def seed_magazin_abo(name, parent)
a.parent_id = abos.id
a.self_registration_role_type = "Group::AboBasicLogin::BasicLogin"
end

SacSections::Seeder.new.seed unless Rails.env.test?
Loading

0 comments on commit 08458a3

Please sign in to comment.