--- /dev/null
+ IDENTIFICATION DIVISION.
+ PROGRAM-ID. vereincheck.
+ ***********************************************************
+ * Comilieren:
+ * cobc -x vereincheck.cbl ../src/fileutil.o
+ ***********************************************************
+ DATA DIVISION.
+ WORKING-STORAGE SECTION.
+ 01 action-par PIC X VALUE "A".
+ 01 data-val PIC X(9).
+ 01 ret-val PIC 99.
+
+ PROCEDURE DIVISION.
+
+ CALL "fileutil" USING action-par, data-val, ret-val
+ DISPLAY "ret-val: "ret-val
+ .
+++ /dev/null
-<?php
-
-// imports
-require_once 'GenericAdmin/DataTypes/EnumType.php';
-
-class Zahlweise extends EnumType {
-
- /** Zahlungsmethoden */
- const ZW_BAR = 0;
- const ZW_SELBST = 1;
- const ZW_EINZUG = 2;
-
- // (string representations of) defined values
- public static $defd_vals = array (
- self::ZW_BAR => 'Barzahler',
- self::ZW_SELBST => 'Selbstüberweise',
- self::ZW_EINZUG => 'Bankeinzug',
- );
-
- public function __construct($value) {
- $this->initInstance('Zahlweise', self::$defd_vals, $value);
- }
-}
+++ /dev/null
-<?php
-
-// imports
-require_once 'GenericAdmin/GenericAdmin.php';
-require_once 'util/Config.php';
-
-class MVAdmin extends GenericAdmin {
-
- function MVAdmin() {
- // Generic Administration configuration data
- require 'AWK/impl/GenadData.php';
- parent::setDscrData($mocd_tab, $atdc_tab);
- }
-}
+++ /dev/null
-<?php
-
-// imports
-require_once 'GenericAdmin/DataTypes/AttrProperty.php';
-
- // Generic Administration configuration data
- $mocd_tab = array (
- 1 => array (
- 'intern' => 'Stamm',
- 'extern' => 'Personenstamm'),
- 2 => array (
- 'intern' => 'Grundstuck',
- 'extern' => 'Grundstück'),
- 3 => array (
- 'intern' => 'Beitrage',
- 'extern' => 'Beiträge'),
-// 4 => array (
-// 'intern' => 'Werkzeug',
-// 'extern' => 'Werkzeug')
- );
-
- $atdc_tab = array (
-
- // Personenstamm
- array (
- 'intern' => 'nachname',
- 'extern' => 'Nachname',
- 'moc' => 'Stamm',
- 'props' => array (AttrProperty::AP_GET, AttrProperty::AP_SET)),
- array (
- 'intern' => 'vorname',
- 'extern' => 'Vorname',
- 'moc' => 'Stamm',
- 'props' => array (AttrProperty::AP_GET, AttrProperty::AP_SET)),
- array (
- 'intern' => 'stasse',
- 'extern' => 'Straße',
- 'moc' => 'Stamm',
- 'props' => array (AttrProperty::AP_GET, AttrProperty::AP_SET)),
- array (
- 'intern' => 'plz',
- 'extern' => 'PLZ',
- 'moc' => 'Stamm',
- 'props' => array (AttrProperty::AP_GET, AttrProperty::AP_SET)),
- array (
- 'intern' => 'ort',
- 'extern' => 'Ort',
- 'moc' => 'Stamm',
- 'props' => array (AttrProperty::AP_GET, AttrProperty::AP_SET)),
- array (
- 'intern' => 'zahlweise',
- 'extern' => 'Zahlweise',
- 'moc' => 'Stamm',
- 'props' => array (AttrProperty::AP_GET, AttrProperty::AP_SET),
- 'typ_cl' => 'Zahlweise'),
- array (
- 'intern' => 'iban',
- 'extern' => 'IBAN',
- 'moc' => 'Stamm',
- 'props' => array (AttrProperty::AP_GET, AttrProperty::AP_SET)),
- array (
- 'intern' => 'bic',
- 'extern' => 'BIC',
- 'moc' => 'Stamm',
- 'props' => array (AttrProperty::AP_GET, AttrProperty::AP_SET)),
- array (
- 'intern' => 'kommentar',
- 'extern' => 'Kommentar',
- 'moc' => 'Stamm',
- 'props' => array (AttrProperty::AP_GET, AttrProperty::AP_SET)),
- array (
- 'intern' => 'Grundstuck',
- 'extern' => 'Versicherte_Grundstücke',
- 'moc' => 'Stamm',
- 'props' => array (AttrProperty::AP_GET, AttrProperty::AP_SET, AttrProperty::AP_LIST, AttrProperty::AP_REL),
- 'rel_moc' => 2), //Grundstücke
- array (
- 'intern' => 'Beitrag',
- 'extern' => 'Zahlungen',
- 'moc' => 'Stamm',
- 'props' => array (AttrProperty::AP_GET, AttrProperty::AP_SET, AttrProperty::AP_LIST, AttrProperty::AP_REL),
- 'rel_moc' => 3), //Zahlungen
-
- // Grundstück
- array (
- 'intern' => 'wie_anschrift',
- 'extern' => 'wie_Anschrift',
- 'moc' => 'Grundstuck',
- 'props' => array (AttrProperty::AP_GET, AttrProperty::AP_SET, AttrProperty::AP_BOOL)),
- array (
- 'intern' => 'strasse',
- 'extern' => 'Straße',
- 'moc' => 'Grundstuck',
- 'props' => array (AttrProperty::AP_GET, AttrProperty::AP_SET)),
- array (
- 'intern' => 'plz',
- 'extern' => 'PLZ',
- 'moc' => 'Grundstuck',
- 'props' => array (AttrProperty::AP_GET, AttrProperty::AP_SET)),
- array (
- 'intern' => 'ort',
- 'extern' => 'Ort',
- 'moc' => 'Grundstuck',
- 'props' => array (AttrProperty::AP_GET, AttrProperty::AP_SET)),
- array (
- 'intern' => 'kommentar',
- 'extern' => 'Kommentar',
- 'moc' => 'Grundstuck',
- 'props' => array (AttrProperty::AP_GET, AttrProperty::AP_SET)),
-
- // Beiträge
- array (
- 'intern' => 'jahr',
- 'extern' => 'Jahr',
- 'moc' => 'Beitrage',
- 'props' => array (AttrProperty::AP_GET, AttrProperty::AP_INT)),
- array (
- 'intern' => 'zahlweise',
- 'extern' => 'Zahlweise',
- 'moc' => 'Beitrage',
- 'props' => array (AttrProperty::AP_GET),
- 'typ_cl' => 'Zahlweise'),
- array (
- 'intern' => 'kommentar',
- 'extern' => 'Kommentar',
- 'moc' => 'Beitrage',
- 'props' => array (AttrProperty::AP_GET, AttrProperty::AP_SET)),
- );
-
-?>
+++ /dev/null
-# Database driver
-propel.database = mysql
-
-# Project name
-propel.project = propel
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8"?>
-<config>
- <!-- Uncomment this if you have PEAR Log installed -->
- <!--log>
- <type>file</type>
- <name>/tmp/propel.log</name>
- <ident>AlarmManagement</ident>
- <level>7</level>
- </log-->
- <propel>
- <datasources default="svbal">
- <datasource id="svbal">
- <adapter>mysql</adapter> <!-- sqlite, mysql, myssql, oracle, or pgsql -->
- <connection>
- <dsn>mysql:host=localhost;dbname=svbal</dsn>
- <user>SVBaL</user>
- <password>SVBaL</password>
- <settings>
- <setting id="charset">utf8</setting>
- </settings>
- </connection>
- </datasource>
- </datasources>
- </propel>
-</config>
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8"?>
-<database name="svbal" defaultIdMethod="native">
- <table name="stamm">
- <column name="id" type="integer" required="true" primaryKey="true" autoIncrement="true"/>
- <column name="mod" type="integer" required="true"/>
- <column name="nachname" type="varchar" size="100" required="true"/>
- <column name="vorname" type="varchar" size="100" required="true"/>
- <column name="stasse" type="varchar" size="100" required="true"/>
- <column name="plz" type="char" size="10" required="true"/>
- <column name="ort" type="varchar" size="100" required="true"/>
- <column name="zahlweise" type="integer" required="true"/>
- <column name="iban" type="char" size="20" required="true"/>
- <column name="bic" type="char" size="10" required="true"/>
- </table>
- <table name="stamm_kommentar">
- <column name="id" type="integer" required="true" primaryKey="true" autoIncrement="true"/>
- <column name="erstellt_am" type="integer" required="true"/>
- <column name="kommentar" type="varchar" size="1000" required="true"/>
- <column name="stamm_id" type="integer" required="true"/>
- <foreign-key foreignTable="stamm" refPhpName="Grundstuck">
- <reference local="stamm_id" foreign="id"/>
- </foreign-key>
- </table>
- <table name="grundstuck">
- <column name="id" type="integer" required="true" primaryKey="true" autoIncrement="true"/>
- <column name="mod" type="integer" required="true"/>
- <column name="wie_anschrift" type="integer" required="true"/>
- <column name="strasse" type="varchar" size="100" required="true"/>
- <column name="plz" type="char" size="10" required="true"/>
- <column name="ort" type="varchar" size="100" required="true"/>
- <column name="kommentar" type="varchar" size="1000" required="true"/>
- <column name="stamm_id" type="integer" required="true"/>
- <foreign-key foreignTable="stamm" refPhpName="Grundstuck">
- <reference local="stamm_id" foreign="id"/>
- </foreign-key>
- </table>
- <table name="beitrage">
- <column name="id" type="integer" required="true" primaryKey="true" autoIncrement="true"/>
- <column name="mod" type="integer" required="true"/>
- <column name="jahr" type="integer" required="true"/>
- <column name="zahlweise" type="integer" required="true"/>
- <column name="kommentar" type="varchar" size="1000" required="true"/>
- <column name="stamm_id" type="integer" required="true"/>
- <foreign-key foreignTable="stamm" refPhpName="Beitrag">
- <reference local="stamm_id" foreign="id"/>
- </foreign-key>
- </table>
-</database>
+++ /dev/null
-<?php
-$configurationData = array (
-
- "gui::applications" => array ("Mitgliederverwaltung"),
- "autoloader" => array ("ClassLoader", "autoload"),
- "Mitgliederverwaltung::InterfaceClass" => "MVAdmin",
- "PropelClassPath" => "AWK/impl/data/build"
- );
+++ /dev/null
-<?php
-//phpinfo();
-
-// define user
-$user = getenv("USER");
-if ($user == "") putenv("USER=gui");
-
-// includes
-$path = preg_replace("/SVBaL.*/", "SVBaL", __FILE__);
-set_include_path($path . PATH_SEPARATOR . get_include_path());
-require_once 'util/Logger.php';
-require_once 'util/Config.php';
-require_once 'GenericAdmin/gui/control/GenadControl.php';
-
-// load configuration + class loader
-include 'gui/ConfigurationData.php';
-Config::setConfiguration($configurationData);
-
-// Logging
-$logger = Logger::getInstance();
-$requestMethod = $_SERVER["REQUEST_METHOD"];
-$logger->log(__FILE__, $requestMethod);
-$logger->log(__FILE__, "GET-Variabeles:");
-while ( list($key, $value) = each($_GET) ) {
- $logger->log(__FILE__, $key . " : " . $value);;
-}
-$logger->log(__FILE__, "POST-Variabeles:");
-while ( list($key, $value) = each($_POST) ) {
- $logger->log(__FILE__, $key . " : " . $value);;
-}
-
-// call implementation
-try {
- $control = new GenadControl();
- $control->doIt();
-}
-catch (Exception $e) {
- $logger->logException(__FILE__, $e);
- echo "<html><body>Error occurred!</body></html>";
-}
-
+++ /dev/null
-<?php
-$this->nameMap = array (
- "Back" => "Zurück",
- "Class Selection" => "Typ",
- "Create" => "Anlegen",
- "List" => "Liste",
- "Select" => "Auswählen",
- "Submit changes" => "Änderungen speichern",
- "zur_Zeit_bei" => "zur Zeit bei"
-);
+++ /dev/null
-/usr/share/php/GenericAdmin/gui/view/admin.css
\ No newline at end of file
+++ /dev/null
-/usr/share/php/mLohn/gui/view/gfx/
\ No newline at end of file
--- /dev/null
+SVBaL-Repository
+================
+- Erste Versuche mit GenericAdmin, am 10.1.2024 gelöscht.
+10.2.2024
+- Beginn mit Python-Werkzeug für den S-Verein-Deltaabgleich
+
--- /dev/null
+!|test.util.CallScript|
+|call script|!-rm -r ~/test |true-!|
+|call script|mkdir -p ~/test/python/eh_util/eh_app|
+|call script|cp ../python/eh_util/eh_app/tests.py ~/test/python/eh_util/eh_app/|
+|call script|cp ../python/eh_util/manage.py ~/test/python/eh_util/|
+|call script|cd ~/test/python/eh_util/; ./manage.py test|
--- /dev/null
+<?xml version="1.0"?>
+<properties>
+ <Edit>true</Edit>
+ <Files>true</Files>
+ <Properties>true</Properties>
+ <RecentChanges>true</RecentChanges>
+ <Refactor>true</Refactor>
+ <Search>true</Search>
+ <Test>true</Test>
+ <Versions>true</Versions>
+ <WhereUsed>true</WhereUsed>
+</properties>
--- /dev/null
+!contents -R2 -g -p -f -h
\ No newline at end of file
--- /dev/null
+<?xml version="1.0"?>
+<properties>
+ <Edit>true</Edit>
+ <Files>true</Files>
+ <Properties>true</Properties>
+ <RecentChanges>true</RecentChanges>
+ <Refactor>true</Refactor>
+ <Search>true</Search>
+ <Versions>true</Versions>
+ <WhereUsed>true</WhereUsed>
+</properties>
--- /dev/null
+#!/bin/bash
+
+if [ $# -lt 1 ]; then
+ echo "usage: create-test-export INPUT"
+ exit 1
+fi
+head -1 $1 > TestExport.csv
+grep 14962 $1 >> TestExport.csv
+grep 19603 $1 >> TestExport.csv
+grep 76491 $1 >> TestExport.csv
+grep 76441 $1 >> TestExport.csv
+grep 75987 $1 >> TestExport.csv
+grep 75723 $1 >> TestExport.csv
+grep 14965 $1 >> TestExport.csv
+grep 14964 $1 >> TestExport.csv
+grep 76736 $1 >> TestExport.csv
+
+# remove BOM
+sed -i $'1s/^\uFEFF//' TestExport.csv
--- /dev/null
+"Anrede";"Vorname";"Nachname";"Straße";"Zusatzadresse";"PLZ";"Ort";"Land";"Titel";"Geschlecht";"Familienstand";"Mitglieds-Nr";"Geburtsdatum";"Eintrittsdatum";"Austrittsdatum";"Austrittsgrund";"Zahlungsart";"IBAN";"BIC";"Kontonummer";"Bankleitzahl";"Kreditinstitut";"Kontoinhaber";"Mandatsreferenz";"Debitorenkonto-Nr";"Status";"Branche";"Notfallnummer";"Notfallkontakt";"KommE-Mail_P1";"KommFax_P1";"KommMobil_P1";"KommWeb_P1";"KommTelefon_P1";"KommSkype_P1";"Abteilung_1";"Abteilungseintritt_1";"Abteilungsaustritt_1";"Abteilungsstatus_1";"Abteilungsstatus DFB_1";"Abteilungsaustrittsgrund_1";"Abteilung_2";"Abteilungseintritt_2";"Abteilungsaustritt_2";"Abteilungsstatus_2";"Abteilungsstatus DFB_2";"Abteilungsaustrittsgrund_2";"Beitragsbezeichnung_1_1";"Beitragsstart_1_1";"Beitragsende_1_1";"BeitragBerechnetBis_1_1";"BeitragZahlweise_1_1";"BeitragFälligkeitsdatum_1_1";"BeitragVariabel_1_1";"BeitragFormel_1_1";"BeitragGrundbetrag1_1_1";"BeitragGB1Gesperrt_1_1";"BeitragGrundbetrag2_1_1";"BeitragGB2Gesperrt_1_1";"BeitragGrundbetrag3_1_1";"BeitragGB3Gesperrt_1_1";"BeitragGrundbetrag4_1_1";"BeitragGB4Gesperrt_1_1";"BeitragGrundbetrag5_1_1";"BeitragGB5Gesperrt_1_1";"BeitragZahlweiseGesperrt_1_1";"Freifeldname_1";"Freifeldwert_1";"Freifeldname_2";"Freifeldwert_2";"Freifeldname_3";"Freifeldwert_3";"NotizArt_1";"NotizPrio_1";"NotizBetreff_1";"NotizInhalt_1";"NotizDatum_1"
+Herr;Horsti;Acktu;"Blombergstr. 30";"";81825;München;Deutschland;;;;"14962";25.04.1948;01.01.1998;31.12.2050;;;DE24700202701780047001;HYVEDEMMXXX;"1780047000";"70020270";"UniCredit Bank - HypoVereinsbank";Acktun Horst;"10058";"10253";Aktiv;;;;;"";"";;"4317535";;Standard;01.01.1998;;Aktiv;;;;;;;;;Standard;01.01.1998;;;Jahr;;nein;;;;;;;;;;;;;;"";;"";Zeitung;"Ja";;;;;
+Herr;Horsti;Acktu;"Blombergstr. 30";"";81825;München;Deutschland;;;;"14963";25.04.1948;01.01.1998;31.12.2023;;;DE24700202701780047001;HYVEDEMMXXX;"1780047000";"70020270";"UniCredit Bank - HypoVereinsbank";Acktun Horst;"10058";"10253";Aktiv;;;;;"";"";;"4317535";;Standard;01.01.1998;;Aktiv;;;;;;;;;Standard;01.01.1998;;;Jahr;;nein;;;;;;;;;;;;;;"";;"";Zeitung;"Ja";;;;;
+Herr und Frau;Dr. Michael und Ingrid;Wagner;"Turfstr. 18 a";"";81929;München;Deutschland;;Jur. Person oder sächlich;;"14964";;01.04.2024;;;Lastschrift;DE54700905000004428285;GENODEF1S04;"4428285";"70090500";"Sparda-Bank München";Wagner Dr. Michael und Ingrid;"10255";"10255";Aktiv;;;;;;;;;;;;;;;;Zusatzgrundstück;01.04.2024;;Aktiv;;;;;;;;;;;;;;;;;;;;;;Partnernummer;"76736";VersichertesObjekt;"Gleiwitzer Str. 26, 81929 München";Zeitung;"Nein";;;;;
+Herr und Frau;Dr. Michael und Ingrid;Wagner;"Turfstr. 18 a";"";81929;München;Deutschland;;;;"14965";;01.04.2024;;;Lastschrift;DE54700905000004428285;GENODEF1S04;"4428285";"70090500";"Sparda-Bank München";Wagner Dr. Michael und Ingrid;"10256";"10256";Aktiv;;;;;;;;;;;;;;;;Zusatzgrundstück;01.04.2024;;Aktiv;;;;;;;;;;;;;;;;;;;;;;Partnernummer;"76736";VersichertesObjekt;"Finkenweg 5, 83556 Griesstätt";Zeitung;"Nein";;;;;
+Herr und Frau;Dr. Michael und Ingrid;Wagner;"Turfstr. 18 a";"";81929;München;Deutschland;;;;"76736";25.05.1965;01.12.2012;;;Lastschrift;DE54700905000004428285;GENODEF1S04;"4428285";"70090500";"Sparda-Bank München";Wagner Dr. Michael und Ingrid;"10218";"10218";Aktiv;;;;bonzius@vindelicia.de;"";"";;"99 75 94 94";;Standard;01.12.2012;;Aktiv;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"";VersichertesObjekt;"81929 München, Gleiwitzerstr. 28";Zeitung;"Ja";;;;;
+Frau;Elke;Söller;"Argula-von-Grumbach-Sr. 5";"";92345;Dietfurt;Deutschland;;;;"77912";08.05.1979;01.07.2008;;;;;;;;;;"10193";"10193";Aktiv;;;;;"";"";;"084 64 / 64 21 79";;Standard;01.07.2008;;Aktiv;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"";VersichertesObjekt;"92363 Breitenbrunn, Breitenegg 1 a";Zeitung;"Ja";;;;;
+Frau;Marianne;Söller;"Böhmerbrunnenstr. 27";"";92345;Dietfurt;Deutschland;;;;"76441";;01.01.1995;;;;DE98760520800570713611;BYLADEM1NMA;"570713610";"76052080";"Sparkasse Neumarkt i d OPf-Parsberg";Söllner2 Marianne;"10249";"10249";Aktiv;;;;;;;;;;;;;;;;Zusatzgrundstück;01.01.1995;;Aktiv;;;;;;;;;;;;;;;;;;;;;;Partnernummer;"75987";;"";Zeitung;"Nein";;;;;
+Frau;Marianne;Söller;"Böhmerbrunnenstr. 27";"";92354;Dietfurt;Deutschland;;;;"75987";;01.01.1985;;;;DE98760520800570713611;BYLADEM1NMA;"570713610";"76052080";"Sparkasse Neumarkt i d OPf-Parsberg";Söllner Marianne;"10194";"10194";Aktiv;;;;;"";"";;"084 64 / 15 42";;Standard;01.01.1985;;Aktiv;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"";VersichertesObjekt;"92345 Dietfurt 2, Böhmerbrunnenstr. 21";Zeitung;"Ja";;;;;
+Frau;Marianne;Söller;"Böhmerbrunnenstr. 27";"";92345;Dietfurt;Deutschland;;;;"76491";;01.09.1992;;;;DE98760520800570713611;BYLADEM1NMA;"570713610";"76052080";"Sparkasse Neumarkt i d OPf-Parsberg";Söllner3 Marianne;"10250";"10250";Aktiv;;;;;;;;;;;;;;;;Zusatzgrundstück;01.09.1992;;Aktiv;;;;;;;;;;;;;;;;;;;;;;Partnernummer;"75987";VersichertesObjekt;"92363 Breitbrunn, Tannenweg 6";Zeitung;"Nein";;;;;
--- /dev/null
+"Mitglieds-Nr";Nachname;Vorname;Anrede;"Straße";PLZ;Ort;Geburtsdatum;Eintrittsdatum;Austrittsdatum;Abteilungen;Zahlungsart;IBAN;BIC;Kontoinhaber;"Mandatsreferenz";Abweichender Zahler Mitglied;Abweichender Zahler IBAN;E-Mail;Postinfo;VersichertesObjekt;Zeitung
+"14962";Acktun;Horst;Herr;"Blombergstr. 30";81825;München;25.04.1948;01.01.1998;;Standard (01.01.1998 bis -);Lastschrift;DE24 7002 0270 1780 0470 00;HYVEDEMMXXX;Acktun Horst;"10058";;;;Nein;;Ja
+"* 19603";Bachmann;Sonja und Horst;Herr und Frau;"Kampenwandstr. 1a";81671;München;04.12.1954;01.04.2010;31.12.2024;Zusatzgrundstück (01.04.2010 bis 31.12.2024);Lastschrift (AZ: Bachmann, Horst und Sonja);;;;"";Bachmann, Horst und Sonja;DE47 7015 0000 0080 1337 39;;Nein;81671 München, Hachinger Bach-Str. 4 c;Nein
+"76491";Söllner;Marianne;Frau;"Böhmerbrunnenstr. 27";92345;Dietfurt;;01.09.1992;;Zusatzgrundstück (01.09.1992 bis -);Lastschrift (AZ: Söllner, Marianne);;;;"";Söllner, Marianne;DE98 7605 2080 0570 7136 10;;Nein;92363 Breitbrunn, Tannenweg 6;Nein
+"76441";Söllner;Marianne;Frau;"Böhmerbrunnenstr. 27";92345;Dietfurt;;01.01.1995;;Zusatzgrundstück (01.01.1995 bis -);Lastschrift (AZ: Söllner, Marianne);;;;"";Söllner, Marianne;DE98 7605 2080 0570 7136 10;;Nein;;Nein
+"75987";Söllner;Marianne;Frau;"Böhmerbrunnenstr. 27";92354;Dietfurt;;01.01.1985;;Standard (01.01.1985 bis -);Lastschrift;DE98 7605 2080 0570 7136 10;BYLADEM1NMA;Söllner Marianne;"10194";;;;Nein;92345 Dietfurt 2, Böhmerbrunnenstr. 21;Ja
+"75723";Tungl;Inge;Frau;"Sonnwendjochstr. 79";81825;München;;01.01.1960;;Standard (01.01.1960 bis -);Überweisung;;;Tungl Inge;"";;;;Nein;;Ja
+"14965";Wagner;Dr. Michael und Ingrid;;"Turfstr. 18 a";81929;München;;01.04.2024;;Zusatzgrundstück (01.04.2024 bis -);Lastschrift (AZ: Wagner, Dr. Michael und Ingrid);;;;"";Wagner, Dr. Michael und Ingrid;DE54 7009 0500 0004 4282 85;;Nein;Finkenweg 5, 83556 Griesstätt;Nein
+"14964";Wagner;Dr. Michael und Ingrid;Herr und Frau;"Turfstr. 18 a";81929;München;;01.04.2024;;Zusatzgrundstück (01.04.2024 bis -);Lastschrift (AZ: Wagner, Dr. Michael und Ingrid);;;;"";Wagner, Dr. Michael und Ingrid;DE54 7009 0500 0004 4282 85;;Nein;Gleiwitzer Str. 26, 81929 München;Nein
+"76736";Wagner;Dr. Michael und Ingrid;Herr und Frau;"Turfstr. 18 a";81929;München;25.05.1965;01.12.2012;;Standard (01.12.2012 bis -);Lastschrift;DE54 7009 0500 0004 4282 85;GENODEF1S04;Wagner Dr. Michael und Ingrid;"10218";;;bonzius@vindelicia.de;Nein;81929 München, Gleiwitzerstr. 28;Ja
--- /dev/null
+#!/bin/bash
+set -e
+
+if [ $# -ne 3 ]
+then
+ echo "invalid call: delete_vorlage.sh VEREIN VORLAGE"
+ exit 7
+fi
+
+verein=$1
+vorlage=$2
+
+echo "Delete $vorlage for $verein"
+rm eh_app/templates/$verein/$vorlage
--- /dev/null
+#!/bin/bash
+
+usage="ehapp-verein-check DATA_PATH"
+
+if [ -z "$1" ]; then
+ echo $usage
+ exit 7
+fi
+data_path=$1
+
+mkdir -p $data_path/quellen
+mkdir -p $data_path/upload
+mkdir -p $data_path/build
--- /dev/null
+#!/bin/bash
+set -e
+
+if [ $# -ne 4 ]
+then
+ echo "invalid call: install.sh VEREIN TGZDATEI WORKDIR"
+ exit 7
+fi
+
+verein=$1
+tgz=$2
+workdir=$3
+vorlage=${2%%.tgz}
+
+echo "Install $vorlage for $verein"
+
+mkdir -p $workdir
+mkdir -p eh_app/templates/$verein
+
+pushd $workdir >/dev/null
+ tar xf $workdir/upload/$2
+popd >/dev/null
+ln -sf $workdir/$vorlage/$vorlage.tex eh_app/templates/$verein/
--- /dev/null
+#/bin/bash
+set -e
+
+usage="pdferasteller DIR FILE"
+if [ $# -ne 2 ]; then
+ echo $usage
+ exit 7
+fi
+dir=$1
+file=$2
+ergebnis_dir="ergebnis/"
+
+cd $dir
+pdflatex $file
+
+# Schiebe Ergebnis in das Ergebnisverzeichnis
+erg_datei=${file%.tex}.pdf
+mv $erg_datei $ergebnis_dir
--- /dev/null
+svbal (0.1-%BUILD%) unstable; urgency=medium
+ * initial version: Ausweiserstellung, Kassenbrief
+ -- Michael Wagner <info@wagnertech.de> Sat, 06 Jun 2020 20:03:04 +0100
+
--- /dev/null
+compile_type=NONE
+target_type=DEB
--- /dev/null
+Source: svbal
+Section: main
+Priority: optional
+Maintainer: Michael Wagner <michael@wagnertech.de>
+Build-Depends: git, mbuild
+
+Package: eigenheimer-util
+Architecture: all
+Depends: texlive-latex-base, texlive-latex-recommended, texlive-lang-german, texlive-latex-extra, python3, apache2, libapache2-mod-wsgi-py3, python3-django
+Description: Mitgliederverwaltung Eigenheimerverband
+ .
+
--- /dev/null
+#!/bin/bash
+set -e
+
+mkdir -p $1/opt
+cp -r python/eh_app $1/opt/
+rm -r $1/opt/eh_app/templates/svbal 2>/dev/null |true
+
+mkdir -p $1/opt/eh_app/bin
+cp bin/* $1/opt/eh_app/bin/
--- /dev/null
+#!/bin/bash
+set -e
+
+ln -sf /opt/eh_app /opt/mysite/
+
+# add application to settings.py
+if ! grep "### EHUTIL ###" /opt/mysite/mysite/settings.py >/dev/null
+then
+ echo "add ehutil settings to settings.py"
+ cat << EOF >> /opt/mysite/mysite/settings.py
+### EHUTIL ###
+
+INSTALLED_APPS.append('eh_app.apps.EhAppConfig')
+
+### EHUTIL-END ###
+EOF
+fi
+
+# DB anlegen/migrieren
+/opt/mysite/manage.py migrate
+
+# add url routing
+if ! grep "### EHUTIL ###" /opt/mysite/mysite/urls.py >/dev/null
+then
+ echo "add url routing"
+ cat << EOF >> /opt/mysite/mysite/urls.py
+### EHUTIL ###
+
+from django.urls import include
+urlpatterns.append(path('eh-app/', include('eh_app.urls')))
+
+### EHUTIL-END ###
+EOF
+fi
+
+# prepare template dir
+chown www-data:www-data /opt/eh_app/templates
+
+# restart apache
+systemctl restart apache2
--- /dev/null
+Django
+======
+
+- Version
+python3 -m django --version
+
+- Projekt/Anwendung
+django-admin startproject mysite
+
+- Server starten
+manage.py runserver
+
+- Model-View-Control
+ x Model -> awk.py
+ x View -> templates + forms.py
+ x Control -> views.py
+++ /dev/null
-# Configuration for mKrimi Verleihnix Gui
- Alias /SVBaL "/usr/share/php/SVBaL/gui"
- <Directory /usr/share/php/SVBaL/gui>
- Options +FollowSymlinks
- RewriteEngine On
- RewriteBase /SVBaL/
- RewriteRule ^.*php$ index.php
- </Directory>
-
--- /dev/null
+WSGIScriptAlias /eh-app /opt/mysite/mysite/wsgi.py
--- /dev/null
+\documentclass{scrlttr2}
+\LoadLetterOption{ausweis}
+\setkomavar{date}{\vspace*{-6\baselineskip}\today}
+\begin{document}
+\begin{letter}{
+ %\today \par \vspace*{2\baselineskip}
+ \vspace*{4\baselineskip}[[Testdruck]]\\Michael Wagner\\Turfstr. 18a\\81929 München
+}
+\opening{\par \vspace*{3\baselineskip}Sehr geehrter Herr Wagner,}
+Hier steht der Text
+
+in mehreren Absätzen SDFG SDF SDFG SDFGHSDFGH SDFGH SDFGH SDF SDFG SDF SDSGH SDFG HGFTHs dfgsdf sdfg sdfg sdf sdfg dfsg sdfg s.
+
+Und ein dritter.
+\closing{Mit freundlichen Grüßen}
+\end{letter}
+\end{document}
--- /dev/null
+\ProvidesFile{testlco.lco}[2022/01/08 letter class option]
+\RequirePackage{ngerman} % Deutsche Sprache
+\RequirePackage{fix-cm}
+\RequirePackage[T1]{fontenc} % Ligaturschriften
+\RequirePackage[utf8]{inputenc} % Eingabezeichensatz
+\RequirePackage{graphicx} % Grafikpaket
+\RequirePackage{hyperref}
+\usepackage{wallpaper} % Hintergrundbilder
+\hypersetup{pdfpagemode=None}
+\KOMAoptions{
+ paper=a4,
+ pagenumber=false,
+% fromalign=right,
+% fromrule=afteraddress,
+% fromphone,
+% fromfax,
+ fromlogo,
+% fromurl,fromemail,
+% backaddress,
+ foldmarks,
+% headsepline,footsepline,
+ headsepline=true, % Linie unter dem Header der Folgeseite
+ enlargefirstpage,
+ parskip=half
+}
+\setkomavar{fromname}{SV Berg am Laim}
+\setkomavar{fromaddress}{Turfstr. 18a\\81929~München}
+\setkomavar{firsthead}{}
+%\setkomavar{fromphone}{+49\,(0)\,555\,12345}
+%\setkomavar{fromfax}{+49\,(0)\,555\,12345}
+%\setkomavar{fromemail}{joachim@example.org}
+\setkomavar*{emailseparator}{mailto}
+\setkomavar{emailseparator}{:}
+%\setkomavar{fromurl}{\url{//www.schlosser.info}}
+\setkomavar*{urlseparator}{}
+\setkomavar{urlseparator}{}
+\setkomavar{frombank}{Eine Bank\\IBAN~123\,45\,678}
+\setkomavar{place}{München}
+\setkomavar{signature}{Michael Wagner\\1.Vorsitzender}
+%\setkomavar{fromlogo}{\parbox[b]{8cm}{\usekomafont{fromaddress}%
+% {\mbox{\LARGE \bfseries Dr.\ rer.\ nat.\ Joachim~Schlosser}}
+% \smallskip}
+%}
+\setkomafont{backaddress}{\sffamily}
+\setkomafont{fromaddress}{\sffamily}
+%\setkomavar{fromlogo}{\parbox[b]{8cm}{\includegraphics[width=2cm]{logo.jpeg}}}
+\setkomavar{fromlogo}{\includegraphics[width=2cm]{logo.jpeg}}
+\setkomavar{nexthead}{\mbox{\textbf{Siedlervereinigung Berg am Laim}} \usekomavar{fromlogo}}
+\headheight=2cm
+\setkomafont{fromname}{\sffamily}
+\addtokomafont{fromaddress}{\scriptsize}
+\pagestyle{headings}
+%\CenterWallPaper{1}{MitgliederausweisSVBaLVorlage_leer_v2.pdf}
+\CenterWallPaper{1}{../Aktuell/BriefpapierSVBaLVorlage.pdf}
+
--- /dev/null
+brief_202507.tex
\ No newline at end of file
--- /dev/null
+'''
+Created on 02.08.2024
+
+@author: sparky2021
+'''
+from eh_app.models import ConfigData
+
+the_instance = None
+
+class Config:
+ '''
+ Singleton Klasse für Konfiguration
+ '''
+
+ def __init__(self, verein):
+ self.verein = verein
+
+ def getConfig(self, key, default=None):
+ data = ConfigData.objects.filter(verein=self.verein, key=key)
+ if data:
+ return data[0].value
+ return default
+
+ def requireConfig(self, key):
+ data = self.getConfig(key)
+ if not data:
+ raise RuntimeError(f"Kein Eintag für: {self.verein}/{key}")
+ return data
+
+ def setConfig(self, key, value=None):
+ # No value supplied: delete entry
+ # check, if entry already exists
+ data = ConfigData.objects.filter(verein=self.verein, key=key)
+ if data:
+ # check data set
+ if len(data) != 1:
+ raise RuntimeError("config entry not unique")
+ if value:
+ if data[0].value != value:
+ data[0].value = value
+ data[0].save()
+ else:
+ data[0].delete()
+ elif value:
+ data = ConfigData(verein=self.verein, key=key, value=value)
+ data.save()
+
+def getInstance(verein=None):
+ global the_instance
+ if not the_instance:
+ if not verein:
+ raise RuntimeError("Bei der ersten Instanzierung muss der Verein mitgegeben werden.")
+ the_instance = Config(verein)
+ return the_instance
--- /dev/null
+import os
+
+class PdfErsteller(object):
+ '''
+ Klasse zur Erstellung von PDFs
+ Diese Klasse verwaltet Resourcen. Mit "with" verwenden!
+ '''
+
+ def __init__(self, request, template, basisbtr: int, zusatzbtr: int, pfad, pdfersteller):
+ self.request = request
+ self.template = template
+ self.pfad = pfad
+ self.pdfersteller = pdfersteller
+ self.basisbtr = basisbtr
+ self.zusatzbtr = zusatzbtr
+ self.gesamtbetrag = 0
+ self.anzahl = 0
+ self.csvfile = open(os.path.join(pfad, "ergebnis", "rechnungen.csv"), "w")
+ print("Name", "Vorname", "Straße", "PLZ", "Ort", "Anz. Grundstück", "Betrag", sep=";", file=self.csvfile )
+
+ def __enter__(self):
+ return self
+
+ def __exit__(self, exc_type, exc_value, traceback):
+ print ("Gesamt", self.gesamtbetrag, sep=";", file=self.csvfile )
+ self.csvfile.close()
+
+ def erstellepdf(self, m):
+ gg = m.VersicherteGrundstucke()
+ g1 = gg[0]
+ gn = gg[1:]
+ beitrag = self.basisbtr + self.zusatzbtr*len(gn)
+ konto = None
+ if len(m.iban) > 0:
+ konto = m.iban[0:4]+" xxxx xxxx xxxx "+m.iban[-2:]
+
+ # Hinweise zur Templateerstellung:
+ # https://docs.djangoproject.com/en/2.2/ref/templates/builtins/#ref-templates-builtins-tags
+
+ tex_bearbeitet = self.template.render(
+ {"vorname" : m.vorname,
+ "nachname" : m.nachname,
+ "strasse" : m.strasse,
+ "plz" : m.plz,
+ "ort" : m.ort,
+ "anrede" : m.anrede,
+ "grundstuck1" : g1,
+ "basisbeitrag" : self.basisbtr,
+ "g_weitere" : gn,
+ "zusatzbeitrag": self.zusatzbtr,
+ "beitrag" : beitrag,
+ "konto" : konto,
+ "m_nr" : m.mitgliedsnr
+ }, self.request)
+
+ with open(f'{self.pfad}/{m.nachname}_{m.mitgliedsnr}_brief.tex', 'w') as f:
+ f.write(tex_bearbeitet) # schreibt in dieses neue Dokument
+
+ # AUfruf PDF latex tex -> pdf
+ import subprocess
+ rc = subprocess.call(["bash", self.pdfersteller, self.pfad, f'{m.nachname}_{m.mitgliedsnr}_brief.tex'])
+ if rc != 0:
+ raise RuntimeError(f"pdfersteller.sh failed: {rc}")
+
+ # schreibe Eintrag in Ergebnisdatei und erhöhe Gesamzbetrag
+ print(m.nachname, m.vorname, m.strasse, m.plz, m.ort, len(gg), beitrag, sep=";", file=self.csvfile )
+ self.gesamtbetrag += beitrag
+ self.anzahl += 1
--- /dev/null
+import os
+import time
+
+from eh_app.AWK import config
+
+'''
+def handle_uploaded_file(csv_file):
+ csv_file_name = str(csv_file)
+ data_path = config.getInstance().requireConfig("data_path")
+ path = os.path.join(data_path, csv_file_name)
+ with open(path, 'wb+') as destination:
+ for chunk in csv_file.chunks():
+ destination.write(chunk)
+'''
+from django.utils.datetime_safe import strftime
+def aktualisiere_config(config, vorlage, beitrag_data):
+ '''
+ if file:
+ uploaded_file = file.name
+ data_path = config.requireConfig("data_path")
+ # copy briefpapier into data_path
+ with open(os.path.join(data_path, uploaded_file), 'wb+') as destination:
+ for chunk in file.chunks():
+ destination.write(chunk)
+ config.setConfig("briefpapier", uploaded_file)
+ '''
+ if vorlage:
+ config.setConfig("vorlage", vorlage)
+ if beitrag_data["basisbeitrag"]:
+ config.setConfig("beitrag_basis", beitrag_data["basisbeitrag"])
+
+ if beitrag_data["zusatzbeitrag"]:
+ config.setConfig("beitrag_zusatz", beitrag_data["zusatzbeitrag"])
+
+def erstelle_ehmeldung(data):
+ from PyPDF2 import PdfFileWriter, PdfFileReader
+ from datetime import date
+ import io
+ from reportlab.pdfgen import canvas
+ from reportlab.lib.pagesizes import letter
+
+ packet = io.BytesIO()
+ can = canvas.Canvas(packet, pagesize=letter)
+
+ # Adressfeld
+ can.setFont("Helvetica", 14)
+ can.drawString(80, 770, "Siedlervereinigung Berg am Laim")
+ can.setFont("Helvetica", 12)
+ can.drawString(205, 618, data["VorZuname"])
+ can.drawString(205, 600, data["VorZunamePartner"])
+ can.drawString(205, 583, data["Wohnanschrift"])
+ can.drawString(205, 566, data["Telefon"])
+ can.drawString(365, 566, data["Email"])
+ can.drawString(205, 549, data["Geburtsdatum"])
+ versichertes_object = data["VersichertesObjekt"]
+ if versichertes_object == "":
+ versichertes_object = data["Wohnanschrift"]
+ can.drawString(205, 500, versichertes_object)
+ can.drawString(193, 466, str(data["AnzahlWohnungen"]))
+ if data["Selbstgenutzt"]:
+ can.drawString(360, 466, "X")
+ if data["Eigentumswohnung"]:
+ can.drawString(192, 449, "X")
+ if data["Gewerblich"]:
+ can.drawString(360, 449, "X")
+ can.drawString(140, 376, date.today().strftime('%d.%m.%Y'))
+ can.drawString(350, 376, "Maschinell erstellt.")
+
+ can.save()
+
+ #move to the beginning of the StringIO buffer
+ packet.seek(0)
+
+ # create a new PDF with Reportlab
+ new_pdf = PdfFileReader(packet)
+ # read your existing PDF
+ existing_pdf = PdfFileReader(open("/home/sparky2021/SVBaL/Aktuell/BeitrittserklarungSVBaL.pdf", "rb"))
+ output = PdfFileWriter()
+ # add the "watermark" (which is the new pdf) on the existing page
+ page = existing_pdf.pages[0]
+ page.mergePage(new_pdf.pages[0])
+ output.addPage(page)
+ # finally, write "output" to a real file
+ output_stream = open("meldung.pdf", "wb")
+ output.write(output_stream)
+ output_stream.close()
+
+def erstelle_ausweis(data):
+ from PyPDF2 import PdfFileWriter, PdfFileReader
+ from datetime import date
+ import io
+ from reportlab.pdfgen import canvas
+ from reportlab.lib.pagesizes import letter
+
+ packet = io.BytesIO()
+ can = canvas.Canvas(packet, pagesize=letter)
+
+ # Adressfeld
+ can.setFont("Helvetica", 12)
+ can.drawString(70, 640, "Herr/Frau")
+ can.drawString(70, 625, data["VorZuname"])
+ can.drawString(70, 610, data["Wohnanschrift"])
+ can.drawString(70, 590, "PLZ/Ort")
+
+ # Datum
+ can.setFont("Helvetica", 9)
+ can.drawString(350, 520, "München, "+date.today().strftime('%d.%m.%Y'))
+
+ # Anschreiben
+ can.drawString(70, 500, "Sehr geehrte/r Herr/Frau"+data["VorZuname"]+",")
+ text = can.beginText(70, 480)
+ text.textLines("Hier Ihr Ausweis")
+ can.drawText(text)
+
+
+ can.line(20, 180, 560, 180)
+
+ # Ausweis
+ can.setFont("Helvetica", 12)
+ can.drawString(460, 100, "#0817654")
+ can.drawString(330, 80, data["VorZuname"])
+ can.setFont("Helvetica", 9)
+ can.drawString(400, 56, data["Geburtsdatum"])
+ can.drawString(400, 42, date.today().strftime('%d.%m.%Y'))
+ versichertes_object = data["VersichertesObjekt"]
+ if versichertes_object == "":
+ versichertes_object = data["Wohnanschrift"]
+ can.drawString(400, 20, versichertes_object)
+
+ can.save()
+
+ #move to the beginning of the StringIO buffer
+ packet.seek(0)
+
+ # create a new PDF with Reportlab
+ new_pdf = PdfFileReader(packet)
+ # read your existing PDF
+ existing_pdf = PdfFileReader(open("MitgliederausweisSVBaLVorlage_leer.pdf", "rb"))
+ output = PdfFileWriter()
+ # add the "watermark" (which is the new pdf) on the existing page
+ page = existing_pdf.pages[0]
+ page.mergePage(new_pdf.pages[0])
+ output.addPage(page)
+ # finally, write "output" to a real file
+ output_stream = open("ausweis.pdf", "wb")
+ output.write(output_stream)
+ output_stream.close()
+
+def pdfs_erstellen(request, verein, mitglieder, templ_name, data_path, build_name):
+ from django.template import loader
+
+ # lese alle Miglieder
+ from eh_app.qmodels import Mitglied
+ if mitglieder == "alle":
+ mm = Mitglied.objects.all()
+ else:
+ mm = []
+ m_ids = mitglieder.split(",")
+ for m_id in m_ids:
+ o = Mitglied.objects
+ m = o.get(mitgliedsnr=m_id)
+ if not m:
+ raise RuntimeError(f"Mitglied mit id {m_id} konnte nicht geladen werden.")
+ mm.append(m)
+ template = loader.get_template(f"{verein}/{templ_name}")
+
+ cf = config.getInstance()
+ ehappdir = cf.getConfig("ehappdir", "/opt/eh_app")
+ pdfersteller = f"{ehappdir}/bin/pdfersteller.sh"
+ if not os.path.exists(pdfersteller):
+ raise RuntimeError("Install-Skript nicht gefunden: "+pdfersteller)
+
+ from eh_app.AWK.pdf_ersteller import PdfErsteller
+ build_base = os.path.join(data_path, "build")
+ build_path = os.path.join(build_base, build_name)
+ result_path = os.path.join(build_path, "ergebnis")
+ tpl_name_wo_ext = os.path.splitext(templ_name)[0]
+ template_path = os.path.join(data_path, f"{tpl_name_wo_ext}")
+
+ # alte builds löschen
+ rc = os.system(f'cd {build_base}; rm -r *')
+ if rc != 0:
+ from eh_app.AWK import util
+ util.schreibe_log(f"Löschen alter builds fehlgeschlagen: {rc}")
+
+ # lege Verzeichnis + Links auf Templatedateien an
+ os.makedirs(result_path)
+ rc = os.system(f'cd {build_path}; ln -s {template_path}/* .')
+ if rc != 0:
+ raise RuntimeError(f"Linkerstellung fehlgeschlagen: {rc}")
+
+ basisbtr = int(cf.requireConfig("beitrag_basis"))
+ zusatzbtr = int(cf.requireConfig("beitrag_zusatz"))
+
+ with PdfErsteller(request, template, basisbtr, zusatzbtr, build_path, pdfersteller) as pe:
+
+ # Erstelle PDFs
+ for m in mm:
+ pe.erstellepdf(m)
+
+ # Ergebnis packen
+ rc = os.system(f'cd {build_path}; tar czf ergebnis.tgz ergebnis')
+ if rc != 0:
+ raise RuntimeError(f"Packen (tar) fehlgeschlagen: {rc}")
+
+ return pe.anzahl, pe.gesamtbetrag
+
+def vertragsliste_erstellen(verein, data_path):
+ build_path = os.path.join(data_path, "build")
+ ergebnis_datei = "vertragsliste_"+time.strftime("%Y%m%d%H%M%S", time.localtime())+".csv"
+
+ # lese alle Miglieder
+ from eh_app.qmodels import Mitglied
+ mm = Mitglied.objects.all()
+
+ with open(os.path.join(build_path,ergebnis_datei), "w") as d:
+ print("Name", "Vorname", "Straße", "PLZ", "Ort", "Grundstück", "Eintrittsdatum", sep=";", file=d )
+ for m in mm:
+ gg = m.VersicherteGrundstucke()
+ for g in gg:
+ print(m.nachname,
+ m.vorname,
+ m.strasse,
+ m.plz,
+ m.ort,
+ g,
+ m.eintrittsdatum.strftime("%d.%m.%Y"),
+ sep=";", file=d )
+ return ergebnis_datei
+
+def vorlagen_verwalten(verein, zu_loschen, vorlage_neu):
+ import subprocess
+ cf = config.getInstance(verein)
+ ehappdir = cf.getConfig("ehappdir", "/opt/eh_app")
+ workdir = cf.getConfig("data_path", "/var/mysite/eh_app")
+ djangodir = cf.getConfig("djangodir", "/opt/mysite")
+ install_sh = f"{ehappdir}/bin/install_vorlage.sh"
+ delete_sh = f"{ehappdir}/bin/delete_vorlage.sh"
+ ehapp_check = f"{ehappdir}/bin/ehapp-verein-check.sh"
+
+ # prüfe Existenz der Skripte
+ if not os.path.exists(install_sh):
+ raise RuntimeError("Install-Skript nicht gefunden: "+install_sh)
+ if not os.path.exists(delete_sh):
+ raise RuntimeError("Delete-Skript nicht gefunden: "+delete_sh)
+ if not os.path.exists(ehapp_check):
+ raise RuntimeError("Check-Skript nicht gefunden: "+ehapp_check)
+
+ # prüfe Dateistruktur
+ rc = subprocess.call(["bash", ehapp_check, workdir, verein])
+ if rc != 0:
+ raise RuntimeError(f"install_sh failed: {rc}")
+
+
+ for vorlage in zu_loschen:
+ rc = os.system(f'{delete_sh} {verein} {vorlage} {ehappdir}')
+ if rc != 0:
+ raise RuntimeError(f"delete_sh fehlgeschlagen: {rc}")
+ if vorlage_neu:
+ vorlage_name = str(vorlage_neu)
+ path = os.path.join(workdir, "upload", vorlage_name)
+ with open(path, 'wb+') as destination:
+ for chunk in vorlage_neu.chunks():
+ destination.write(chunk)
+ #raise RuntimeError(f"xxxxxxxx: {install_sh} {verein} {vorlage_name} {workdir} {ehappdir}")
+ rc = subprocess.call(["bash", install_sh, verein, vorlage_name, workdir, ehappdir])
+ if rc != 0:
+ raise RuntimeError(f"install_sh failed: {rc}")
+
+def datenquelle_andern(verein, pfad, zu_loschen, zu_verwenden, zu_install):
+ cf = config.getInstance(verein)
+ akt_quelle = cf.getConfig("datenquelle", "")
+
+ # Dateien löschen
+ for file in zu_loschen:
+ dpath = os.path.join(pfad, file)
+ os.unlink(dpath)
+ if akt_quelle == file:
+ # Datenquelle zurücksetzen
+ cf.setConfig("datenquelle")
+
+ # Neue Datei verwenden
+ if zu_install:
+ datei_name = str(zu_install)
+ dpath = os.path.join(pfad, datei_name)
+ with open(dpath, 'wb+') as destination:
+ for chunk in zu_install.chunks():
+ destination.write(chunk)
+ cf.setConfig("datenquelle", datei_name)
+ elif zu_verwenden:
+ cf.setConfig("datenquelle", zu_verwenden)
--- /dev/null
+'''
+Utilities für EHUtil
+'''
+import syslog
+from http import cookies
+
+def schreibe_log(eintrag):
+ syslog.openlog("eh_app")
+ syslog.syslog(eintrag)
+
\ No newline at end of file
--- /dev/null
+from django.contrib import admin
+
+# Register your models here.
+
+from django.contrib import admin
+
+from .models import ConfigData
+
+admin.site.register(ConfigData)
--- /dev/null
+from django.apps import AppConfig
+
+
+class EhAppConfig(AppConfig):
+ name = 'eh_app'
--- /dev/null
+from django import forms
+'''
+class UploadFileForm(forms.Form):
+ file1 = forms.FileField(label='S-Verein-Export')
+
+class DocumentForm(forms.Form):
+ docfile = forms.FileField(
+ label='Select a file',
+ help_text='max. 42 megabytes'
+ )
+
+class TextInputForm(forms.Form):
+ text = forms.CharField(
+ label = "Text für das Anschreiben",
+ empty_value = "Bitte Text eingeben ...",
+ widget=forms.Textarea,
+ )
+'''
+from django.db.models.fields import BooleanField
+'''
+- Doku zu Forms:
+https://docs.djangoproject.com/en/2.2/topics/forms/
+- Doku zu Fields:
+https://docs.djangoproject.com/en/2.2/ref/forms/fields/
+'''
+class VorlagenForm(forms.Form):
+ vorlagen = forms.ChoiceField(choices=())
+ def __init__(self, *args, templates=[('AB', 'ab'),('BC','bc')], **kwargs):
+ super().__init__(*args, **kwargs)
+ self.fields['vorlagen'].choices = templates
+
+class VorlagenVerwaltungForm(forms.Form):
+ vorlagen_zu_loschen = forms.MultipleChoiceField(
+ widget=forms.CheckboxSelectMultiple,
+ choices=(),
+ label="Vorlagen zum Löschen vormerken:",
+ required=False
+ )
+ vorlage_neu = forms.FileField(label='Neue Vorlage installieren:', required=False)
+ def __init__(self, *args, vorlagen=[('AB', 'ab'),('BC','bc')], **kwargs):
+ self.vorlagen = vorlagen
+ super().__init__(*args, **kwargs)
+ self.fields['vorlagen_zu_loschen'].choices = vorlagen
+
+class DatenfileForm(forms.Form):
+ dateien = forms.ChoiceField(choices=())
+ def __init__(self, *args, dateien=[('should', 'not'),('be','here')], **kwargs):
+ super().__init__(*args, **kwargs)
+ self.fields['dateien'].choices = dateien
+
+class DatenfileVerwaltungForm(forms.Form):
+ dateien_zu_loschen = forms.MultipleChoiceField(
+ widget=forms.CheckboxSelectMultiple,
+ choices=(),
+ label="Dateien zum Löschen vormerken:",
+ required=False
+ )
+ datei_verwendung = forms.ChoiceField(
+ choices=(),
+ label="Datei zur Verwendung:",
+ required=False
+ )
+ datei_neu = forms.FileField(label='Neue Datei verwenden:', required=False)
+ def __init__(self, *args, datenquellen=[('should', 'not'),('be','here')], **kwargs):
+ self.dateien = datenquellen
+ super().__init__(*args, **kwargs)
+ self.fields['dateien_zu_loschen'].choices = datenquellen
+ self.fields['datei_verwendung'].choices = [(None, "Auswählen ...")]+datenquellen
+
+class BeitragForm(forms.Form):
+ basisbeitrag = forms.IntegerField()
+ zusatzbeitrag = forms.IntegerField(label="Beitrag für Zusatzgrundstück")
+
+class MitgliederForm(forms.Form):
+ mg_auswahl = forms.ChoiceField(
+ choices = (),
+ widget=forms.RadioSelect,
+ label = ""
+ )
+ def __init__(self, *args, zul="", **kwargs):
+ #self.templates = templates
+ super().__init__(*args, **kwargs)
+ self.zulstr = zul
+ self.fields['mg_auswahl'].choices = [("alle","Alle Mitglieder"), ("zul",f"Zuletzt ausgewählte Mitglieder: {zul}")]
+
+class MitgliederAuswahlForm(forms.Form):
+ mg_auswahl = forms.MultipleChoiceField(
+ widget=forms.CheckboxSelectMultiple,
+ choices=(),
+ label=""
+ )
+ def __init__(self, *args, mitglieder=(), **kwargs):
+ #self.templates = templates
+ super().__init__(*args, **kwargs)
+ self.fields['mg_auswahl'].choices = mitglieder
+
+class KassenbriefForm_alt(forms.Form):
+ #briefpapier = forms.FileField(label='Briefpapier ändern:', required=False)
+ template = forms.ChoiceField(choices=())
+ basisbeitrag = forms.IntegerField()
+ zusatzbeitrag = forms.IntegerField(label="Beitrag für Zusatzgrundstück")
+ def __init__(self, *args, templates=[('AB', 'ab'),('BC','bc')], **kwargs):
+ #self.templates = templates
+ super().__init__(*args, **kwargs)
+ self.fields['template'].choices = templates
+
+class EhmeldungForm(forms.Form):
+ VorZuname = forms.CharField(
+ label = "Vor- und Zuname",)
+ VorZunamePartner = forms.CharField(
+ label = "Vor- und Zuname Partner",
+ required=False)
+ Wohnanschrift = forms.CharField(label = "Wohnanschrift (Str, PLZ, Ort)")
+ Telefon = forms.CharField(
+ label = "Telefon",
+ required=False)
+ Email = forms.CharField(
+ label = "E-Mail",
+ required=False)
+ Geburtsdatum = forms.CharField(
+ label = "Geburtsdatum",
+ required=False)
+ VersichertesObjekt = forms.CharField(
+ label = "Versichertes Objekt",
+ required=False)
+ AnzahlWohnungen = forms.IntegerField(initial=1, label="Anzahl Wonungen")
+ Selbstgenutzt = forms.BooleanField(label="Selbstgenutzt", required=False)
+ Eigentumswohnung = forms.BooleanField(label="Eigentumswohnung", required=False)
+ Gewerblich = forms.BooleanField(label="(teilw.) gewerblich genutzt", required=False)
+ Eintrittsdatum = forms.CharField(
+ label = "Eintrittsdatum",
+ required=False)
+
+class LoginForm(forms.Form):
+ verein = forms.CharField(label = "Vereinskürzel")
+ name = forms.CharField(label = "Login-Name")
+ password = forms.CharField(widget=forms.PasswordInput, label = "Passwort")
+ next = forms.CharField(widget = forms.HiddenInput(), required = False)
--- /dev/null
+# Generated by Django 2.2.28 on 2024-11-08 19:25
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ initial = True
+
+ dependencies = [
+ ]
+
+ operations = [
+ migrations.CreateModel(
+ name='ConfigData',
+ fields=[
+ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('verein', models.CharField(max_length=100)),
+ ('key', models.CharField(max_length=50)),
+ ('value', models.CharField(max_length=200)),
+ ],
+ ),
+ ]
--- /dev/null
+from django.db import models
+
+"""
+Falls hier Änderungen gemacht werden:
+- ./manage.py makemigrations eh_app
+- ./manage.py migrate
+"""
+
+class ConfigData(models.Model):
+ verein = models.CharField(max_length=100)
+ key = models.CharField(max_length=50)
+ value = models.CharField(max_length=200)
+
+
\ No newline at end of file
--- /dev/null
+'''
+Created on 04.12.2024
+
+@author: sparky2021
+'''
+from q import QError
+from qif import QIF
+from .AWK import config
+import datetime
+from django.utils.decorators import classproperty
+import os
+
+def create_mitglied_from_dataset(data):
+ eintrittsdatum = datetime.datetime.strptime(data[8], '%d.%m.%Y')
+ if eintrittsdatum > datetime.datetime.today():
+ return None
+ if data[9] != "":
+ austrittsdatum = datetime.datetime.strptime(data[9], '%d.%m.%Y')
+ if austrittsdatum < datetime.datetime.today():
+ return None
+ m = Mitglied()
+ m.eintrittsdatum = eintrittsdatum
+ m.mitgliedsnr = data[0]
+ m.anrede = data[1]
+ m.vorname = data[2]
+ m.nachname = data[3]
+ m.strasse = data[4]
+ # "Zusatzadresse"
+ m.plz = data[5]
+ m.ort = data[6]
+
+ # "Land"
+ # "Titel"
+ # "Geschlecht"
+ # "Familienstand"
+ # m.geburtsdatum = data[7]
+ # "Austrittsgrund"
+ # m.zahlungsart = data[16]
+ m.iban = data[11]
+ # m.bic = data[18]
+ # "Kontonummer"
+ # "Bankleitzahl"
+ # "Kreditinstitut"
+ # m.kontoinhaber = data[22]
+ # m.mandatsreferenz = data[23]
+ # m.debitorenkontonr = data[24]
+ # m.status = data[25]
+ # "Branche"
+ # "Notfallnummer"
+ # "Notfallkontakt"
+ # m.email = data[29] # "KommE-Mail_P1"
+ # "KommFax_P1"
+ # "KommMobil_P1"
+ # "KommWeb_P1"
+ # "KommTelefon_P1"
+ # "KommSkype_P1"
+ # m.abteilung_1 = data[35]
+ # m.abteilungseintritt_1 = data[36]
+ # m.abteilungsaustritt_1 = data[37]
+ # if data[67] == '""':
+ # m.stammnummer = 0
+ # else:
+ # m.stammnummer = int(m.rd_opt_qval(data[67]))
+ # "Freifeldname_2"
+ # m.ver_grund = m.rd_opt_qval(data[69])
+ # if len(m.ver_grund) == 0:
+ # m.ver_grund = f"{m.strasse}, {m.plz} {m.ort}"
+ # "Freifeldname_3"
+ # m.zeitung = data[71]
+ return m
+
+class MitgliederQuery:
+ def __init__(self):
+ self.data_source = QIF({"d" : ";", "H" : 1})
+ '''
+ d (separator) : ;
+ H (header line): yes
+ '''
+ #cf = config.getInstance()
+ #self.file_name = os.path.join(cf.requireConfig("data_path"), "quellen", cf.requireConfig("datenquelle"))
+ self.file_name = "undefined. Set by .init(verein)"
+ self.att_list = "MitgliedschaftsNr, Mitgliedschaftsanrede, Vorname1, Nachname1, Strasse1, Plz1, Ort1, Geburtsdatum1, EintrittVerein, AustrittVerein, Zahlungsart, IBAN, BIC, Kontoinhaber, MandatsReferenz, Email"
+ #self.att_list = "Mitgliedschaftsanrede, Vorname1, Nachname1, Strasse1, Plz1, Ort1, Geburtsdatum1, EintrittVerein, AustrittVerein, Zahlungsart, IBAN, BIC, Kontoinhaber, MandatsReferenz, Email"
+ # 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
+ cf = config.getInstance()
+ self.file_name = os.path.join(cf.requireConfig("data_path"), "quellen", cf.requireConfig("datenquelle"))
+
+ def all(self):
+ data_set = self.data_source.request(f"SELECT {self.att_list} FROM {self.file_name} ORDER BY Nachname1, Vorname1")
+ if type(data_set) is QError:
+ raise RuntimeError(data_set)
+ mm = []
+ for data in data_set:
+ m = create_mitglied_from_dataset(data)
+ if m:
+ mm.append(m)
+ return mm
+
+ def get(self, mitgliedsnr):
+ data_set = self.data_source.request(f"SELECT {self.att_list} FROM {self.file_name} WHERE MitgliedschaftsNr = {mitgliedsnr}")
+ if type(data_set) is QError:
+ raise RuntimeError(data_set)
+ if data_set[0]:
+ return create_mitglied_from_dataset(data_set[0])
+ return None
+
+ def VersicherteGrundstucke(self, mitglied):
+ # Hole Basiseintrag
+
+ data_set = self.data_source.request(f"SELECT Objekt FROM {self.file_name} WHERE MitgliedschaftsNr = {mitglied.mitgliedsnr}")
+ if type(data_set) is QError:
+ raise RuntimeError(data_set)
+ if data_set[0][0]:
+ gr = data_set[0][0]
+ else:
+ gr = f"{mitglied.strasse}, {mitglied.plz} {mitglied.ort}"
+ gst = [gr]
+
+ # Suche nach weiteren Grunstücken
+ data_set = self.data_source.request(f"SELECT `Weiteres Grundstück 1` FROM {self.file_name} WHERE MitgliedschaftsNr = {mitglied.mitgliedsnr}")
+ if type(data_set) is QError:
+ raise RuntimeError(data_set)
+ if data_set[0][0] != "":
+ gst.append(data_set[0][0])
+
+ data_set = self.data_source.request(f"SELECT `Weiteres Grundstück 2` FROM {self.file_name} WHERE MitgliedschaftsNr = {mitglied.mitgliedsnr}")
+ if type(data_set) is QError:
+ raise RuntimeError(data_set)
+ if data_set[0][0] != "":
+ gst.append(data_set[0][0])
+
+ data_set = self.data_source.request(f"SELECT `Weiteres Grundstück 3` FROM {self.file_name} WHERE MitgliedschaftsNr = {mitglied.mitgliedsnr}")
+ if type(data_set) is QError:
+ raise RuntimeError(data_set)
+ if data_set[0][0] != "":
+ gst.append(data_set[0][0])
+
+ return gst
+class classproperty(object):
+ def __init__(self, f):
+ self.f = f
+ def __get__(self, obj, owner):
+ return self.f(owner)
+
+class Mitglied:
+ #def objects = MitgliederQuery()
+ _objects = None
+ @classproperty
+ def objects(cls):
+ if not cls._objects:
+ cls._objects = MitgliederQuery()
+ ############################ Hack #########################
+ #cls._objects.init("svbal")
+ return cls._objects
+
+
+ #@property : nette Idee, funktioniert aber nicht auf Klassenebene
+ '''
+ def objects():
+ if not _objects:
+ _objects = MitgliederQuery()
+ print ("xxxxxxxxxxxxxxxxxxxxxxtype _objects",type(_objects))
+ return _objects
+ '''
+ def __init__(self):
+ pass
+
+ def VersicherteGrundstucke(self):
+ return self.objects.VersicherteGrundstucke(self)
--- /dev/null
+{% load static %}
+<html>
+<head>
+ <link rel="stylesheet" type="text/css" href="{% static 'admin/css/base.css' %}">
+ <title>Siedlerverein-Verwaltung by WagnerTech UG</title>
+</head>
+<body>
+<h1>Datenquelle ändern</h1>
+<form action="/eh-app/{{verein}}/datenquelle-andern/" method="post" enctype="multipart/form-data">
+{% csrf_token %}
+<table>
+{{datenquelle_form}}
+</table>
+<input type="hidden" name="letzte_seite" value="{{letzte_seite}}"/>
+<p><input type="submit" value="Ändern"/>
+</form>
+</body>
+</html>
--- /dev/null
+{% load static %}
+<html>
+<head>
+ <link rel="stylesheet" type="text/css" href="{% static 'admin/css/base.css' %}">
+</head>
+<body>
+<h1>Anwendung Eigenheimerverband</h1>
+<h2>Funktionen für Verein {{verein_name}}</h2>
+<p><a href="/eh-app/{{verein}}/kassenbrief">Kassenbrief erstellen</a></p>
+<p><a href="/eh-app/{{verein}}/ehmeldung">Meldung Eigenheimerverband</a></p>
+<p><a href="/eh-app/{{verein}}/vertragsliste">Liste der Mitgliedschaften</a></p>
+<h2>Verwendete Datenquelle:</h2>
+<p style="color:red">{{fehler_quelle}}</p>
+<p>Datenquelle: {{datenquelle}}</datenquelle>
+<p><a href = "/eh-app/{{verein}}/datenquelle-andern/">Datenquelle ändern</a></p>
+
+</body>
+</html>
--- /dev/null
+<!DOCTYPE html>
+{% load static %}
+<html>
+<head>
+ <link rel="stylesheet" type="text/css" href="{% static 'admin/css/base.css' %}">
+ <meta charset="utf-8">
+ <title>WagnerTech - Eigenheimer - Meldung</title>
+</head>
+
+<body>
+
+ <!-- Upload form. Note enctype attribute! -->
+ <form action="/eh-app/{{verein}}/ehmeldung/" method="post" enctype="multipart/form-data">
+ {% csrf_token %}
+ <p>{{ form.VorZuname.label_tag }} {{ form.VorZuname }}</p>
+ <p>{{ form.VorZunamePartner.label_tag }} {{ form.VorZunamePartner }}</p>
+ <p>{{ form.Wohnanschrift.label_tag }} {{ form.Wohnanschrift }}</p>
+ <p>{{ form.Telefon.label_tag }} {{ form.Telefon }}</p>
+ <p>{{ form.Email.label_tag }} {{ form.Email }}</p>
+ <p>{{ form.Geburtsdatum.label_tag }} {{ form.Geburtsdatum }}</p>
+ <p>{{ form.VersichertesObjekt.label_tag }} {{ form.VersichertesObjekt }}</p>
+ <p>{{ form.AnzahlWohnungen.label_tag }} {{ form.AnzahlWohnungen }}</p>
+ <p>{{ form.Selbstgenutzt.label_tag }} {{ form.Selbstgenutzt }}</p>
+ <p>{{ form.Eigentumswohnung.label_tag }} {{ form.Eigentumswohnung }}</p>
+ <p>{{ form.Gewerblich.label_tag }} {{ form.Gewerblich }}</p>
+ <p>{{ form.Eintrittsdatum.label_tag }} {{ form.Eintrittsdatum }}</p>
+
+ <p><input type="submit" value="Meldung erstellen"/></p>
+ </form>
+</body>
+
+</html>
--- /dev/null
+{% load static %}
+<html>
+<head>
+ <title>Siedlerverein-Verwaltung by WagnerTech UG</title>
+ <link rel="stylesheet" type="text/css" href="{% static 'admin/css/base.css' %}">
+</head>
+<body>
+<h1>Erstellung Kassenbrief</h1>
+<p>Überprüfen Sie folgende Eingabedaten:</p>
+<hr>
+
+<form action="/eh-app/{{verein}}/kassenbrief/" method="post" enctype="multipart/form-data">
+{% csrf_token %}
+
+<h2>Datenquelle</h2>
+<p style="color:red">{{fehler_quelle}}</p>
+<p>Datenquelle: {{datenquelle}}</datenquelle>
+<p><a href = "/eh-app/{{verein}}/datenquelle-andern/?letzte_seite=kassenbrief">Datenquelle ändern</a></p>
+<hr>
+
+<h2>Mitgliederauswahl</h2>
+<table>
+{{mausw_form}}
+</table>
+<a href = "/eh-app/{{verein}}/mitglieder_auswahlen/">Mitglieder auswählen</a>
+<hr>
+
+<h2>Kassenbriefvorlagen</h2>
+<table>
+{{vorlagen_form}}
+</table>
+<br>
+<a href = "/eh-app/{{verein}}/vorlagen_verwalten/">Kassenbriefvorlagen verwalten</a>
+<hr>
+
+<h2>Beiträge</h2>
+<table>
+{{beitrag_form}}
+</table>
+<hr>
+
+<p><input type="submit" value="Weiter ..."/>
+</form>
+</body>
+</html>
--- /dev/null
+{% load static %}
+<html>
+<head>
+ <link rel="stylesheet" type="text/css" href="{% static 'admin/css/base.css' %}">
+</head>
+<body>
+<h1>Erstellung Kassenbrief</h1>
+<p>Die Kassenbriefe wurden erfolgreich erstellt und können jetzt heruntergeladen werden.</p>
+<p>Anzahl: {{anzahl}}</p>
+<p>Gesamtbetrag: {{gesamtbetrag}}.-</p>
+<form action="/eh-app/{{verein}}/kassenbrief/download" method="get">
+{% csrf_token %}
+<input type="submit" name="download" value="Herunterladen"/>
+</form>
+</body>
+</html>
--- /dev/null
+{% load static %}
+<html>
+<head>
+ <title>Siedlerverein-Verwaltung by WagnerTech UG</title>
+ <link rel="stylesheet" type="text/css" href="{% static 'admin/css/base.css' %}">
+</head>
+<body>
+<h1>Erstellung Kassenbrief</h1>
+<p>Überprüfen Sie folgende Eingabedaten:</p>
+<table>
+<tr><td>Datenquelle</td><td>{{datenquelle}}</td></tr>
+<tr><td>Vorlage</td><td>{{vorlage}}</td></tr>
+<tr><td>Basisbeitrag</td><td>{{basisbeitrag}}</td></tr>
+<tr><td>Zusatzbeitrag</td><td>{{zusatzbeitrag}}</td></tr>
+<tr><td>Mitglieder</td><td>{{miglieder}}</td></tr>
+</table>
+<form action="/eh-app/{{verein}}/kassenbrief/zusammenfassung" method="post">
+{% csrf_token %}
+<input type="submit" name="zuruck" value="Zurück"/> 
+<input type="submit" name="erstellen" value="Erstellen"/>
+</form>
+</body>
+</html>
--- /dev/null
+{% load static %}
+<html>
+<head>
+ <title>Siedlerverein-Verwaltung by WagnerTech UG</title>
+ <link rel="stylesheet" type="text/css" href="{% static 'admin/css/base.css' %}">
+</head>
+<body>
+<h1>Siedlerverein-Verwaltung by WagnerTech UG</h1>
+<h2>Login</h2>
+<form action="/eh-app/login" method="post" enctype="multipart/form-data">
+{% csrf_token %}
+{{fehlertext}}
+<table>
+{{form}}
+</table>
+<p><input type="submit" value="Anmelden"/>
+</form>
+</body>
+</html>
--- /dev/null
+{% load static %}
+<html>
+<head>
+ <title>Siedlerverein-Verwaltung by WagnerTech UG</title>
+ <link rel="stylesheet" type="text/css" href="{% static 'admin/css/base.css' %}">
+</head>
+<body>
+<h1>Mitglieder auswählen</h1>
+<form action="." method="post" enctype="multipart/form-data">
+{% csrf_token %}
+<table>
+{{mausw_form}}
+</table>
+<p><input type="submit" value="Auswählen"/>
+</form>
+</body>
+</html>
--- /dev/null
+{% load static %}
+<html>
+<head>
+ <link rel="stylesheet" type="text/css" href="{% static 'admin/css/base.css' %}">
+ <title>Siedlerverein-Verwaltung by WagnerTech UG</title>
+</head>
+<body>
+<h1>Vorlagen verwalten</h1>
+<form action="/eh-app/{{verein}}/vorlagen_verwalten/" method="post" enctype="multipart/form-data">
+{% csrf_token %}
+<table>
+{{vorlagen_form}}
+</table>
+<p><input type="submit" value="Ändern"/>
+</form>
+</body>
+</html>
--- /dev/null
+from django.test import TestCase
+
+# Create your tests here.
+from .AWK import config
+
+class TestConfig(TestCase):
+ def test_setter(self):
+ cf = config.getInstance("svbal")
+ cf.setConfig("bla", "blub")
+
+ val = cf.getConfig("bla")
+ assert (val == "blub")
+
+ # change setting
+ cf.setConfig("bla", "bar")
+ val = cf.getConfig("bla")
+ assert (val == "bar")
+
+
+class TestQModel(TestCase):
+ def setUp(self):
+ cf = config.getInstance("svbal")
+ cf.setConfig("DataFile", "../../Test/etc/TestExport.csv")
+
+ def test_allinstances(self):
+ config.getInstance("svbal")
+ from eh_app.qmodels import Mitglied
+ mm = Mitglied.objects.all()
+ assert (len(mm) == 4)
+ gst = mm[0].VersicherteGrundstucke()
+ assert (len(gst) == 1)
+ for m in mm:
+ if m.nachname == "Wagner":
+ gst = m.VersicherteGrundstucke()
+ assert (len(gst) == 3)
+
\ No newline at end of file
--- /dev/null
+from django.urls import path
+
+from . import views
+
+urlpatterns = [
+ path('<slug:verein>/datenquelle-andern/', views.datenquelle_andern),
+ path('<slug:verein>/kassenbrief/', views.kassenbrief),
+ path('<slug:verein>/vorlagen_verwalten/', views.vorlagen_verwalten),
+ path('<slug:verein>/mitglieder_auswahlen/', views.mitglieder_auswahlen),
+ path('<slug:verein>/kassenbrief/zusammenfassung', views.kassenbrief_zusammenfassung),
+ path('<slug:verein>/kassenbrief/erfolg', views.kassenbrief_erfolg),
+ path('<slug:verein>/kassenbrief/download', views.kassenbrief_download),
+ path('<slug:verein>/ehmeldung/', views.ehmeldung),
+ path('<slug:verein>/vertragsliste/', views.vertragsliste),
+ path('login/', views.login),
+ path('login', views.login),
+ path('<slug:verein>/', views.index),
+ path('<slug:verein>', views.index),
+ path('', views.login),
+]
--- /dev/null
+import os,sys
+
+from django.contrib.auth.decorators import login_required
+from django.http import HttpResponse, HttpResponseRedirect, FileResponse
+from django.shortcuts import render
+from django.template import loader
+
+from .AWK import config, routines, util
+#import .forms
+from .forms import (
+ EhmeldungForm,
+ VorlagenForm,
+ BeitragForm,
+ VorlagenVerwaltungForm,
+ MitgliederForm,
+ MitgliederAuswahlForm,
+ DatenfileVerwaltungForm )
+from eh_app.AWK.pdf_ersteller import PdfErsteller
+
+from mysite import settings
+import time
+
+# Create your views here.
+
+# change working dir due to relative paths in scripts
+os.chdir(settings.BASE_DIR)
+
+try:
+ home = os.environ["HOME"]
+ if os.path.exists(f"{home}/.eclipse/org.eclipse.platform_4.18.0_1473617060_linux_gtk_x86_64/plugins/org.python.pydev.core_8.3.0.202104101217/pysrc/"):
+ # its a eclipse development environment
+ sys.path.append(f"{home}/.eclipse/org.eclipse.platform_4.18.0_1473617060_linux_gtk_x86_64/plugins/org.python.pydev.core_8.3.0.202104101217/pysrc/")
+ import pydevd
+ pydevd.settrace()
+
+except:
+ pass
+
+LOGIN_URL = "/eh-app/login"
+
+def erstelle_datenquelle_liste(data_path):
+ dirlist = None
+ vorlagen_liste = []
+ if os.path.isdir(data_path):
+ dirlist = os.listdir(data_path) # returns list
+ if dirlist:
+ for t in dirlist:
+ vorlagen_liste.append((t,t))
+ return vorlagen_liste
+
+def erstelle_vorlagen_liste(verein):
+ # Erstelle Vorlagenliste
+ os.chdir(settings.BASE_DIR)
+ dirlist = os.listdir()
+ util.schreibe_log(str(dirlist))
+ dirlist = None
+ vorlagen_liste = []
+ if os.path.isdir("eh_app/templates/"+verein):
+ dirlist = os.listdir("eh_app/templates/"+verein) # returns list
+ if dirlist:
+ for t in dirlist:
+ tpl_name_wo_ext = os.path.splitext(t)[0]
+ vorlagen_liste.append((t,tpl_name_wo_ext))
+ return vorlagen_liste
+
+@login_required(login_url=LOGIN_URL)
+def vorlagen_verwalten(request, verein):
+ vorlagen_liste = erstelle_vorlagen_liste(verein)
+
+ if request.method == 'POST':
+ # Form auswerten
+ form = VorlagenVerwaltungForm(request.POST, request.FILES, vorlagen=vorlagen_liste)
+ if form.is_valid():
+ zu_loschen = form.cleaned_data['vorlagen_zu_loschen']
+ zu_install = request.FILES.get('vorlage_neu', None)
+ routines.vorlagen_verwalten(verein, zu_loschen, zu_install)
+ else:
+ raise RuntimeError(f"Form not valid: {form.errors}")
+ # Verarbeitung in routines.py aufrufen
+
+ # Wenn alles gut gegangen, zurück zum Kassenbrief
+ return HttpResponseRedirect(f'/eh-app/{verein}/kassenbrief')
+ else:
+ vorlagen_form = VorlagenVerwaltungForm(vorlagen=vorlagen_liste)
+
+ template = loader.get_template("vorlagen_verwalten.html")
+ return HttpResponse(template.render(
+ {
+ "verein" : verein,
+ "vorlagen_form" : vorlagen_form },
+ request))
+
+@login_required(login_url=LOGIN_URL)
+def datenquelle_andern(request, verein):
+ cf = config.getInstance(verein)
+ data_path = cf.requireConfig("data_path")
+ ehappdir = cf.getConfig("ehappdir", "/opt/eh_app")
+ vereinchecker = f"{ehappdir}/bin/ehapp-verein-check.sh"
+ if not os.path.exists(vereinchecker):
+ raise RuntimeError("ehapp-verein-check.sh nicht gefunden: "+vereinchecker)
+
+ rc = os.system(f'{vereinchecker} {data_path}')
+ if rc != 0:
+ raise RuntimeError(f"ehapp-verein-check.sh fehlgeschlagen: {rc}")
+ quellen_path = os.path.join(data_path, "quellen")
+ datenquellen_liste = erstelle_datenquelle_liste(quellen_path)
+
+ if request.method == 'POST':
+ # Form auswerten
+ form = DatenfileVerwaltungForm(
+ request.POST,
+ request.FILES,
+ datenquellen=datenquellen_liste)
+ if form.is_valid():
+ zu_loschen = form.cleaned_data['dateien_zu_loschen']
+ zu_verwenden = form.cleaned_data['datei_verwendung']
+ zu_install = request.FILES.get('datei_neu', None)
+ routines.datenquelle_andern(verein, quellen_path, zu_loschen, zu_verwenden, zu_install)
+ else:
+ raise RuntimeError(f"Form not valid: {form.errors}")
+ # Verarbeitung in routines.py aufrufen
+
+ # Wenn alles gut gegangen, zurück zum Kassenbrief
+ letzte_seite = request.POST.get("letzte_seite")
+ return HttpResponseRedirect(f'/eh-app/{verein}/{letzte_seite}')
+ else:
+ form = DatenfileVerwaltungForm(datenquellen=datenquellen_liste)
+
+ letzte_seite = request.GET.get("letzte_seite") or ""
+ template = loader.get_template("datenquelle_andern.html")
+ return HttpResponse(template.render(
+ {
+ "verein" : verein,
+ "datenquelle_form" : form,
+ "letzte_seite" : letzte_seite },
+ request))
+
+@login_required(login_url=LOGIN_URL)
+def mitglieder_auswahlen(request, verein):
+ mitglieder = (request.COOKIES.get('mausw2') or "").split(",")
+ config.getInstance(verein) # wird in qmodel gebraucht
+ from eh_app.qmodels import Mitglied
+ mm = Mitglied.objects.all()
+ mitglieder_liste = []
+ for m in mm:
+ mitglieder_liste.append((m.mitgliedsnr, m.nachname+" "+m.vorname))
+
+ if request.method == 'POST':
+ # Form auswerten
+ form = MitgliederAuswahlForm(
+ request.POST,
+ request.FILES,
+ mitglieder=mitglieder_liste)
+ if form.is_valid():
+ mg_ausw = form.cleaned_data['mg_auswahl']
+ else:
+ raise RuntimeError(f"Form not valid: {form.errors}")
+
+ # Wenn alles gut gegangen, zurück zum Kassenbrief
+ response = HttpResponseRedirect(f'/eh-app/{verein}/kassenbrief')
+ mg_ausw_str = ",".join(mg_ausw)
+ response.set_cookie("mausw2", mg_ausw_str)
+ return response
+ else:
+ mausw_form = MitgliederAuswahlForm(mitglieder=mitglieder_liste, initial={"mg_auswahl":mitglieder})
+
+ template = loader.get_template("mitglieder_auswahlen.html")
+ return HttpResponse(template.render(
+ {
+ "verein" : verein,
+ "mausw_form" : mausw_form },
+ request))
+
+@login_required(login_url=LOGIN_URL)
+def kassenbrief(request, verein):
+ '''
+ GET:
+ Diese Methode liest aus der Config die Einstellungen und zeigt sie an.
+
+ POST:
+ Diese Methode lädt die Zusammenfassung
+
+ ---------------------------------------------------------------
+ Templateauswahl
+
+ Ausgewähltes Template: <Wert aus Config>
+ Link -> Neue Templates installieren
+ ---------------------------------------------------------------
+ '''
+
+ mg_ausw = request.COOKIES.get('mausw1') or "leer"
+ mg_zul = request.COOKIES.get('mausw2') or "leer"
+ alles_ok = True
+ fehlertext_quelle = ""
+ fehlertext_vorlage = ""
+ fehlertext_beitrag = ""
+ vconf = config.getInstance(verein)
+ datenquelle = vconf.getConfig("datenquelle")
+ beitrag_basis = vconf.getConfig("beitrag_basis", 0)
+ beitrag_zusatz = vconf.getConfig("beitrag_zusatz", 0)
+ vorlagen_liste = erstelle_vorlagen_liste(verein)
+ vorlage = vconf.getConfig("vorlage", "")
+ mausw_form = MitgliederForm(
+ zul=mg_zul,
+ initial={"mg_auswahl" : mg_ausw,}
+ )
+ if request.method == 'POST':
+ # Prüfe Datenquelle
+ if not datenquelle:
+ fehlertext_quelle = "Datenquelle auswählen"
+ alles_ok = False
+
+ # Prüfe Vorlage
+ vorlagen_form = VorlagenForm(request.POST, request.FILES, templates=vorlagen_liste)
+ if not vorlagen_form.is_valid():
+ raise RuntimeError("VorlagenForm invalid: "+str(vorlagen_form.errors))
+ vorlage = vorlagen_form.cleaned_data["vorlagen"]
+ if not vorlage:
+ fehlertext_vorlage = "Bitte Kassenbriefvorlage auswählen"
+ alles_ok = False
+
+ # Prüfe Beiträge
+ beitrag_form = BeitragForm(request.POST, request.FILES)
+ if not beitrag_form.is_valid():
+ raise RuntimeError("BeitragForm invalid: Formular nochmal schicken")
+ beitrag_basis = beitrag_form.cleaned_data["basisbeitrag"]
+ beitrag_zusatz = beitrag_form.cleaned_data["zusatzbeitrag"]
+ if beitrag_basis == 0 or beitrag_zusatz == 0:
+ fehlertext_beitrag = "Beiträge ausfüllen"
+ alles_ok = False
+
+ routines.aktualisiere_config(vconf, vorlage, beitrag_form.cleaned_data)
+
+ # Speichere Migliederauswahl in Cookie
+ mausw_form = MitgliederForm(request.POST, request.FILES)
+ if not mausw_form.is_valid():
+ raise RuntimeError("MitgliederForm invalid: "+str(mausw_form.errors))
+ mausw = mausw_form.cleaned_data["mg_auswahl"]
+
+
+ if alles_ok:
+ response = HttpResponseRedirect('zusammenfassung')
+ response.set_cookie("mausw1", mausw)
+ return response
+
+ # GET request / POST mit Fehlern
+ vorlagen_form = VorlagenForm(
+ templates=vorlagen_liste,
+ initial={'vorlagen' : vorlage } )
+ beitrag_form = BeitragForm(
+ initial={
+ "basisbeitrag" : beitrag_basis,
+ "zusatzbeitrag" : beitrag_zusatz,
+ })
+ return render(request, 'kassenbrief.html', {
+ "datenquelle" : datenquelle or "Keine Datenquelle ausgewählt",
+ 'vorlagen_form': vorlagen_form,
+ 'beitrag_form' : beitrag_form,
+ 'mausw_form' : mausw_form,
+ 'verein' : verein,
+ 'fehler_quelle': fehlertext_quelle
+ })
+
+@login_required(login_url=LOGIN_URL)
+def kassenbrief_zusammenfassung(request, verein):
+ vconf = config.getInstance(verein)
+ datenquelle = vconf.getConfig("datenquelle")
+ beitrag_basis = vconf.getConfig("beitrag_basis", 0)
+ beitrag_zusatz = vconf.getConfig("beitrag_zusatz", 0)
+ vorlage = vconf.getConfig("vorlage")
+ mitglieder = request.COOKIES.get('mausw1')
+ if mitglieder == "zul":
+ mitglieder = request.COOKIES.get('mausw2')
+ if request.method == 'POST':
+ post = request.POST
+ if "erstellen" in post:
+ data_path = vconf.getConfig("data_path", "/var/ehapp")
+ build_name = time.strftime("%Y%m%d%H%M%S", time.localtime())
+
+ anzahl, gesamtbetrag = routines.pdfs_erstellen(request, verein, mitglieder, vorlage, data_path, build_name)
+ response = HttpResponseRedirect(f'/eh-app/{verein}/kassenbrief/erfolg')
+ response.set_cookie("build_name", build_name)
+ response.set_cookie("anzahl", anzahl)
+ response.set_cookie("gesamtbetrag", gesamtbetrag)
+ return response
+ else:
+ return HttpResponseRedirect(f'/eh-app/{verein}/kassenbrief')
+
+ else:
+ tpl_name_wo_ext = os.path.splitext(vorlage)[0]
+ return render(request, 'kassenbrief_zusammenfassung.html', {
+ 'verein' : verein,
+ 'datenquelle' : datenquelle,
+ 'vorlage' : tpl_name_wo_ext,
+ 'basisbeitrag' : beitrag_basis,
+ 'zusatzbeitrag' : beitrag_zusatz,
+ 'miglieder' : mitglieder })
+
+@login_required(login_url=LOGIN_URL)
+def kassenbrief_erfolg(request, verein):
+ return render(request, 'kassenbrief_erfolg.html', {
+ 'verein' : verein,
+ 'anzahl' : request.COOKIES.get('anzahl'),
+ 'gesamtbetrag' : request.COOKIES.get('gesamtbetrag'),
+ })
+
+@login_required(login_url=LOGIN_URL)
+def kassenbrief_download(request, verein):
+ vconf = config.getInstance(verein)
+ data_path = vconf.getConfig("data_path", "/var/ehapp")
+ build_name = request.COOKIES.get('build_name')
+
+ ergebnis_datei = os.path.join(data_path, "build", build_name, "ergebnis.tgz")
+
+ response = FileResponse(open(ergebnis_datei, 'rb'), as_attachment=True, filename=f"{build_name}.tgz")
+ return response
+
+@login_required(login_url=LOGIN_URL)
+def ehmeldung(request, verein):
+ # if this is a POST request we need to process the form data
+ if request.method == 'POST':
+ # create a form instance and populate it with data from the request:
+ form = EhmeldungForm(request.POST, request.FILES)
+ # check whether it's valid:
+ if form.is_valid():
+ # bei Änderungen Konfiguration aktualisieren
+ routines.erstelle_ehmeldung(form.cleaned_data)
+ routines.erstelle_ausweis(form.cleaned_data)
+ # redirect to a new URL:
+ return HttpResponseRedirect('/thanks/')
+
+ # if a GET (or any other method) we'll create a blank form
+ else:
+ form = EhmeldungForm()
+
+ return render(request, 'ehmeldung.html', {'form': form, 'verein': verein})
+
+@login_required(login_url=LOGIN_URL)
+def vertragsliste(request, verein):
+ vconf = config.getInstance(verein)
+ data_path = vconf.getConfig("data_path", "/var/ehapp")
+ ergebnis_datei = routines.vertragsliste_erstellen(verein, data_path)
+ response = FileResponse(open(os.path.join(data_path, "build",ergebnis_datei), 'rb'), as_attachment=True, filename=ergebnis_datei)
+ return response
+
+def index(request, verein):
+ if request.user.is_authenticated:
+ print("index login ok")
+ else:
+ print("index not logged in")
+
+ datenquelle = config.getInstance(verein).getConfig("datenquelle")
+
+ template = loader.get_template('eh_app.html')
+ response = HttpResponse(template.render(
+ {"verein" : verein,
+ "verein_name" : verein,
+ "datenquelle" : datenquelle,
+ }, request))
+ return response
+
+def login(request):
+ from django.contrib import auth
+ from .forms import LoginForm
+
+ fehlertext = ""
+ # if this is a POST request we need to process the form data
+ if request.method == 'POST':
+ # create a form instance and populate it with data from the request:
+ form = LoginForm(request.POST, request.FILES)
+ # check whether it's valid:
+ if form.is_valid():
+ user = auth.authenticate(
+ username = request.POST["name"],
+ password = request.POST["password"],
+ )
+ verein = request.POST["verein"]
+ if user is not None:
+
+ # check group
+ for group in user.groups.all():
+ if group.name == verein:
+ auth.login(request, user)
+ if request.user.is_authenticated:
+ print("auth login ok")
+ else:
+ print("auth not logged in")
+ next = request.POST.get("next", None)
+ if next:
+ return HttpResponseRedirect(next)
+ else:
+ return HttpResponseRedirect(f'/eh-app/{verein}')
+ # login fehlgeschlagen
+ fehlertext = "Login fehlgeschlagen"
+
+ # if a GET (or any other method) we'll create a blank form
+ else:
+ next = None
+ verein = ""
+ next = request.GET.get("next", None)
+ if next:
+ path_elems = next.split("/")
+ verein = path_elems[2]
+ form = LoginForm(initial={'next': next, 'verein': verein})
+
+ return render(request, 'login.html', {'form': form, 'fehlertext': fehlertext})
+
\ No newline at end of file
--- /dev/null
+'''
+Created on 02.08.2024
+
+@author: sparky2021
+'''
+from ausweis.models import ConfigData
+
+the_instance = None
+
+class Config:
+ '''
+ Singleton Klasse für Konfiguration
+ '''
+
+ def __init__(self, verein):
+ self.verein = verein
+
+ def getConfig(self, key):
+ data = ConfigData.objects.filter(verein=self.verein, key=key)
+ if data:
+ return data[0].value
+ return None
+
+ def requireConfig(self, key):
+ data = self.getConfig(key)
+ if not data:
+ raise RuntimeError(f"Kein Eintag für: {self.verein}/{key}")
+ return data
+
+
+def getInstance(verein=None):
+ global the_instance
+ if not the_instance:
+ if not verein:
+ raise RuntimeError("Bei der ersten Instanzierung muss der Verein mitgegeben werden.")
+ the_instance = Config(verein)
+ return the_instance
--- /dev/null
+from ausweis.AWK import config
+
+import os
+
+def handle_uploaded_file(csv_file):
+ csv_file_name = str(csv_file)
+ data_path = config.getInstance().requireConfig("data_path")
+ path = os.path.join(data_path, csv_file_name)
+ with open(path, 'wb+') as destination:
+ for chunk in csv_file.chunks():
+ destination.write(chunk)
+
\ No newline at end of file
--- /dev/null
+from django.contrib import admin
+
+# Register your models here.
+
+#from django.contrib import admin
+
+#from .models import ConfigData
+
+#admin.site.register(ConfigData)
--- /dev/null
+from django.apps import AppConfig
+
+
+class AusweisConfig(AppConfig):
+ name = 'ausweis'
--- /dev/null
+from django import forms
+
+class UploadFileForm(forms.Form):
+ file1 = forms.FileField(label='S-Verein-Export')
+
+class DocumentForm(forms.Form):
+ docfile = forms.FileField(
+ label='Select a file',
+ help_text='max. 42 megabytes'
+ )
+
+class TextInputForm(forms.Form):
+ text = forms.CharField(
+ label = "Text für das Anschreiben",
+ empty_value = "Bitte Text eingeben ...",
+ widget=forms.Textarea,
+ )
\ No newline at end of file
--- /dev/null
+from django.db import models
+
+"""
+Falls hier Änderungen gemacht werden:
+- ./manage.py makemigrations ausweis
+- ./manage.py migrate
+"""
+
--- /dev/null
+<!DOCTYPE html>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>WagnerTech - Siedlerverein</title>
+</head>
+
+<body>
+<h1>Anschreiben für den Ausweis</h1>
+<form action="anschreiben" method="post" enctype="multipart/form-data">
+{% csrf_token %}
+<p>{{ form.text.label_tag }} {{ form.text }}</p>
+
+ <p><input type="submit" value="Anschreiben erstellen"/></p>
+</form>
+</body>
+</html>
--- /dev/null
+<html>
+<head>
+ <title>Siedlerverein-Verwaltung by WagnerTech UG</title>
+</head>
+<body>
+<h1>Erstellung Mitgliederausweise</h1>
+{% if csv_datei_name %}
+ <p>S-Verein-Export: {{csv_datei_name}}</p>
+ <p><a href="upload">Datei ändern</a></p>
+{% else %}
+ <p><a href="upload">Datei hochladen</a></p>
+{% endif %}
+<p><a href="anschreiben">Anschreiben erstellen</a></p>
+<p><a href="alle_ausweise">Alle Ausweise erstellen</a></p>
+<p><a href="einzelausweis">Einzelnen Ausweis erstellen</a></p>
+</body>
+</html>
--- /dev/null
+<!DOCTYPE html>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>WagnerTech - Siedlerverein</title>
+</head>
+
+<body>
+<h1>Upload der S-Verein-Exportdatei</h1>
+ <!-- Upload form. Note enctype attribute! -->
+ <form action="upload" method="post" enctype="multipart/form-data">
+ {% csrf_token %}
+ <p>{{ form.file1.label_tag }} {{ form.file1 }}</p>
+
+ <p><input type="submit" value="Datei hochladen"/></p>
+ </form>
+</body>
+
+</html>
--- /dev/null
+from django.test import TestCase
+
+# Create your tests here.
--- /dev/null
+from django.urls import path
+
+from . import views
+
+urlpatterns = [
+ path('', views.index, name='index'),
+ path('upload', views.upload),
+ path('anschreiben', views.anschreiben),
+ path('alle_ausweise', views.alle_ausweise),
+ path('einzelausweis', views.einzelausweis),
+]
\ No newline at end of file
--- /dev/null
+from .AWK import routines, config
+from .forms import UploadFileForm, DocumentForm, TextInputForm
+
+from django.http import HttpResponse, HttpResponseRedirect
+from django.shortcuts import render
+from django.template import loader
+
+
+def index(request, verein):
+
+ # check existence in DB
+ vconf = config.getInstance(verein)
+ csv_datei_name = vconf.getConfig("csv_datei_name")
+ if not csv_datei_name:
+ template = loader.get_template('aus_index.html')
+ context = {
+ 'csv_datei_name': csv_datei_name,
+ }
+ return HttpResponse(template.render(context, request))
+ return render(request, 'index.html', {'csv_datei_name': csv_datei_name})
+
+def upload(request, verein):
+ if request.method == 'POST':
+ # initialize configuration
+ config.getInstance(verein)
+ form = UploadFileForm(request.POST, request.FILES)
+ if form.is_valid():
+ routines.handle_uploaded_file(request.FILES['file1'])
+ return HttpResponseRedirect(f'/{verein}/ausweis')
+ return HttpResponse("Dateiverarbeitung fehlerhaft")
+ else:
+ form = UploadFileForm()
+ return render(request, 'upload.html', {'form': form})
+
+def anschreiben(request, verein):
+ if request.method == 'POST':
+ form = TextInputForm(request.POST)
+ if form.is_valid():
+ return HttpResponse("Dateiverarbeitung ok")
+ return HttpResponse("Dateiverarbeitung fehlerhaft")
+ else:
+ form = TextInputForm()
+ return render(request, 'anschreiben.html', {'form': form})
+
+def alle_ausweise(request, verein):
+ return HttpResponse("NIY")
+
+def einzelausweis(request, verein):
+ return HttpResponse("NIY")
--- /dev/null
+from AWK.mitglied import Mitglied
+class SVereinDatei(object):
+ '''
+ classdocs
+ '''
+
+ def __init__(self, datei_name):
+ '''
+ Constructor
+ '''
+ self.datei_name = datei_name
+ self.mitglieder = {}
+ self.get_merker = 0
+
+ dh = open(datei_name)
+ line = dh.readline().rstrip()
+ export_header = line.split(";")
+
+ sv_pn_spalte = -1
+
+ i = 0
+ for kopf in export_header:
+ if kopf[0] == '"':
+ kopf = kopf[1:-1]
+ if kopf == 'Mitglieds-Nr':
+ sv_pn_spalte = i
+ i += 1
+
+ if sv_pn_spalte == -1:
+ raise RuntimeError("S-Verein-Export enthält keine Partnernummer")
+
+ for line in dh:
+ data = line.rstrip().split(";")
+ pn = data[sv_pn_spalte]
+ if len(pn) == 0:
+ print("Diese Zeile (export) hat keine Migliedsnummer: ", line)
+ else:
+ if pn[0] == '"':
+ pn = pn[1:-1]
+ pn = int(pn)
+ self.mitglieder[pn] = Mitglied(data)
+ # setze zusätzliche Mitgliedschaften im Stamm
+ for mnr in self.mitglieder:
+ if self.mitglieder[mnr].stammnummer > 0:
+ self.mitglieder[self.mitglieder[mnr].stammnummer].add_weitere_mitgliedschaft(mnr)
+
+ def get(self, mnr = None):
+ if mnr:
+ return self.mitglieder[mnr]
+ if self.get_merker == 0:
+ for m in self.mitglieder:
+ self.get_merker = m
+ return self.mitglieder[m]
+ return_next = False
+ for m in self.mitglieder:
+ if return_next:
+ self.get_merker = m
+ return self.mitglieder[m]
+ if m == self.get_merker:
+ return_next = True
+ return None
--- /dev/null
+#!/usr/bin/python3
+
+import sys
+from mitglied import Mitglied
+
+"""
+Testaufruf:
+./ausweis.py Michael Wagner "25.5.1965" MitgliederausweisSVBaLVorlage_leer.pdf ./
+"""
+
+def erzeuge_ausweis(mitglied: Mitglied, ausgabetext, hintergrund_pdf, ausgabe_pfad):
+ from PyPDF2 import PdfFileWriter, PdfFileReader
+ from datetime import date
+ import io
+ from reportlab.pdfgen import canvas
+ from reportlab.lib.pagesizes import letter
+
+ packet = io.BytesIO()
+ can = canvas.Canvas(packet, pagesize=letter)
+
+ # Adressfeld
+ can.setFont("Helvetica", 12)
+ can.drawString(70, 640, mitglied.anrede)
+ can.drawString(70, 625, mitglied.vorname+" "+mitglied.nachname)
+ can.drawString(70, 610, mitglied.strasse)
+ can.drawString(70, 590, mitglied.plz+" "+mitglied.ort)
+
+ # Datum
+ can.setFont("Helvetica", 9)
+ can.drawString(350, 520, "München, "+date.today().strftime('%d.%m.%Y'))
+
+ # Anschreiben
+ can.drawString(70, 500, "Sehr geehrte/r "+mitglied.anrede+" "+mitglied.nachname+",")
+ text = can.beginText(70, 480)
+ text.textLines(ausgabetext)
+ can.drawText(text)
+
+
+ can.line(20, 180, 560, 180)
+
+ # Ausweis
+ can.setFont("Helvetica", 12)
+ can.drawString(460, 100, mitglied.mitgliedsnr)
+ can.drawString(330, 80, mitglied.vorname+" "+mitglied.nachname)
+ can.setFont("Helvetica", 9)
+ can.drawString(400, 56, mitglied.geburtsdatum)
+ can.drawString(400, 42, mitglied.eintrittsdatum)
+ can.drawString(400, 20, mitglied.ver_grund)
+
+
+ can.save()
+
+ #move to the beginning of the StringIO buffer
+ packet.seek(0)
+
+ # create a new PDF with Reportlab
+ new_pdf = PdfFileReader(packet)
+ # read your existing PDF
+ existing_pdf = PdfFileReader(open(hintergrund_pdf, "rb"))
+ output = PdfFileWriter()
+ # add the "watermark" (which is the new pdf) on the existing page
+ page = existing_pdf.pages[0]
+ page.mergePage(new_pdf.pages[0])
+ output.addPage(page)
+ # finally, write "output" to a real file
+ output_stream = open(ausgabe_pfad, "wb")
+ output.write(output_stream)
+ output_stream.close()
+
+if __name__ == "__main__":
+ if len(sys.argv) == 6:
+ nachname = sys.argv[1]
+ vorname = sys.argv[2]
+ geburtsdatum = sys.argv[3]
+ infile = sys.argv[4]
+ outpath = sys.argv[5]
+ else:
+ print ("Nachname: ")
+ nachname = input()
+ print ("Vorname:")
+ vorname = input()
+ print ("Geburtsdatum:")
+ geburtsdatum = input()
+ print ("Input-Datei: ")
+ infile = input()
+ print ("Ausgabepfad:")
+ outpath = input()
+
+ mitglied = Mitglied(nachname, vorname, geburtsdatum)
+ erzeuge_ausweis(mitglied,infile, outpath)
+
--- /dev/null
+'''
+Created on 29.02.2024
+
+@author: sparky2021
+'''
+class Mitglied(object):
+ '''
+ classdocs
+ '''
+
+ def rd_opt_qval(self, s):
+ if s[0] == '"':
+ s = s[1:-1]
+ return s
+
+ def __init__(self, data):
+ '''
+ Constructor
+ '''
+ self.weitere_mitgliedschaften = []
+ self.anrede = data[0]
+ self.vorname = data[1]
+ self.nachname = data[2]
+ self.strasse = self.rd_opt_qval(data[3])
+ # "Zusatzadresse"
+ self.plz = data[5]
+ self.ort = data[6]
+ # "Land"
+ # "Titel"
+ # "Geschlecht"
+ # "Familienstand"
+ self.mitgliedsnr = self.rd_opt_qval(data[11])
+ self.geburtsdatum = data[12]
+ self.eintrittsdatum = data[13]
+ self.austrittsdatum = data[14]
+ # "Austrittsgrund"
+ self.zahlungsart = data[16]
+ self.iban = data[17]
+ self.bic = data[18]
+ # "Kontonummer"
+ # "Bankleitzahl"
+ # "Kreditinstitut"
+ self.kontoinhaber = data[22]
+ self.mandatsreferenz = data[23]
+ self.debitorenkontonr = data[24]
+ self.status = data[25]
+ # "Branche"
+ # "Notfallnummer"
+ # "Notfallkontakt"
+ self.email = data[29] # "KommE-Mail_P1"
+ # "KommFax_P1"
+ # "KommMobil_P1"
+ # "KommWeb_P1"
+ # "KommTelefon_P1"
+ # "KommSkype_P1"
+ self.abteilung_1 = data[35]
+ self.abteilungseintritt_1 = data[36]
+ self.abteilungsaustritt_1 = data[37]
+ # "Abteilungsstatus_1"
+ # "Abteilungsstatus DFB_1"
+ # "Abteilungsaustrittsgrund_1"
+ # "Abteilung_2"
+ # "Abteilungseintritt_2"
+ # "Abteilungsaustritt_2"
+ # "Abteilungsstatus_2"
+ # "Abteilungsstatus DFB_2"
+ # "Abteilungsaustrittsgrund_2"
+ # "Beitragsbezeichnung_1_1"
+ # "Beitragsstart_1_1"
+ # "Beitragsende_1_1"
+ # "BeitragBerechnetBis_1_1"
+ # "BeitragZahlweise_1_1"
+ # "BeitragFälligkeitsdatum_1_1"
+ # "BeitragVariabel_1_1"
+ # "BeitragFormel_1_1"
+ # "BeitragGrundbetrag1_1_1"
+ # "BeitragGB1Gesperrt_1_1"
+ # "BeitragGrundbetrag2_1_1"
+ # "BeitragGB2Gesperrt_1_1"
+ # "BeitragGrundbetrag3_1_1"
+ # "BeitragGB3Gesperrt_1_1"
+ # "BeitragGrundbetrag4_1_1"
+ # "BeitragGB4Gesperrt_1_1"
+ # "BeitragGrundbetrag5_1_1"
+ # "BeitragGB5Gesperrt_1_1"
+ # "BeitragZahlweiseGesperrt_1_1"
+ # "Freifeldname_1"
+ if data[67] == '""':
+ self.stammnummer = 0
+ else:
+ self.stammnummer = int(self.rd_opt_qval(data[67]))
+ # "Freifeldname_2"
+ self.ver_grund = self.rd_opt_qval(data[69])
+ if len(self.ver_grund) == 0:
+ self.ver_grund = f"{self.strasse}, {self.plz} {self.ort}"
+ # "Freifeldname_3"
+ self.zeitung = data[71]
+
+ def add_weitere_mitgliedschaft(self, pn):
+ self.weitere_mitgliedschaften.append(pn)
+
+
\ No newline at end of file
--- /dev/null
+#!/usr/bin/python3
+from AWK.SVereinControl import SVereinDatei
+from AWK import ausweis
+import sys
+
+def mytest(datei_name):
+ daten = SVereinDatei(datei_name)
+ print ("Daten geladen")
+ m = daten.get()
+ while m:
+ if m.abteilung_1 == "Standard" and len(m.austrittsdatum) == 0:
+ austxt = "als Mitglied unser Siedlervereinigung Berg am Laim wollen wir Sie\nüber Ihren Mitgliedsbeitrag für 2024 informieren.\n\n"
+ austxt += "Ihr Beitrag für 2024 setzt sich wie folgt zusammen:\n"
+ austxt += f"Standardmitgliedschaft ({m.ver_grund}): 39.-"
+ betrag = 39
+ weitere = m.weitere_mitgliedschaften
+ for weitere_mnr in weitere:
+ wm = daten.get(weitere_mnr)
+ austxt += f"\nZusatzgrundstück ({wm.ver_grund}): 32.-"
+ betrag += 32
+ if len(m.iban) > 0:
+ iban = m.iban[0:3]+"XXXXXXXXXXXXX"+m.iban[-4:]
+ austxt += f"\n\nDer Betrag von {betrag}.- wird von Ihrem Konto {iban} mit Gläubiger ID DE08 ZZZ0 0000 9547 90\nund Mandatsreferenz {m.mandatsreferenz} eingezogen."
+ else:
+ austxt += f"\n\nBitte überweisen Sie den offnen Betrag von {betrag}.- auf unser Konto DE69 7019 0000 0003 2143 62\nbei der Münchner Bank."
+ austxt += "\n\nUnd nun endlich ist es so weit, dass wir Ihnen hiermit auch Ihren Mitgliedsausweis\n"
+ austxt += "zukommen lassen können. Bitte schneiden Sie den unteren Teil ab und unterschreiben Sie diesen.\n"
+ austxt += "Weitere Infos zum Einkaufen und die Einladung für die Hauptversammlung finden Sie in der Anlage.\n"
+ austxt += "Wir freuen uns auf Ihr Kommen. "
+ austxt += "\n\nMit freundlichen Grüßen,\nMichael Wagner\n(Vorstand)"
+ ausweis.erzeuge_ausweis(m, austxt, "MitgliederausweisSVBaLVorlage_leer.pdf", f"Ausweis_{m.nachname}_{m.mitgliedsnr}.pdf")
+ #return
+ m = daten.get()
+ print ("Ausweise erstellt.")
+
+def test_q():
+ import qif
+ qif = qif.QIF({"d" : ";", "H" : 1})
+ data = qif.request("select Vorname,Nachname from /home/sparky2021/SVBaL/tmp/export.csv")
+
+ print(data)
+
+
+if __name__ == '__main__':
+ numArgs = len(sys.argv)
+ if (numArgs != 2):
+ raise RuntimeError("usage: MyTest DATEI")
+
+ #mytest(sys.argv[1])
+
+ test_q()
+
--- /dev/null
+from django.contrib import admin
+
+# Register your models here.
--- /dev/null
+from django.apps import AppConfig
+
+
+class EhAbgleichConfig(AppConfig):
+ name = 'eh_abgleich'
--- /dev/null
+def vergleiche_sverein_eheimer(f_sverein, f_eheimer):
+ return f"Es werden die Dateien {f_sverein} und {f_eheimer} vergleichen."
\ No newline at end of file
--- /dev/null
+from django import forms
+
+class UploadFileForm(forms.Form):
+ file1 = forms.FileField(label='S-Verein-Export')
+ file2 = forms.FileField(label='Eigemheimer-Datei')
+
+class DocumentForm(forms.Form):
+ docfile = forms.FileField(
+ label='Select a file',
+ help_text='max. 42 megabytes'
+ )
\ No newline at end of file
--- /dev/null
+from django.db import models
+
+# Create your models here.
--- /dev/null
+<html>
+<body>
+<h1>Eigenheimer - Werkzeuge</h1>
+<p>Hier befinden sich Werkzeuge, um den Datenbestand eines
+ Mitgliedsvereins des Eigenheimerverbands Bayern zu bearbeiten</p>
+
+<h2>Datenabgleich S-Verein - Verband</h2>
+<p>Dieses Werkzeug vergleicht die Export-Datei von S-Verein mit
+ der Mitgliedermeldung des Verbands. Als primäres Vergleichsmerkmal
+ wird dabei die Partnernummer verwendet.</p>
+<p><a href="eh_abgleich">Zum Abgleich</a></p>
+</body>
+</html>
+
--- /dev/null
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8">
+ <title>Minimal Django File Upload Example</title>
+ </head>
+
+ <body>
+ <!-- List of uploaded documents -->
+ {% if documents %}
+ <ul>
+ {% for document in documents %}
+ <li><a href="{{ document.docfile.url }}">{{ document.docfile.name }}</a></li>
+ {% endfor %}
+ </ul>
+ {% else %}
+ <p>No documents.</p>
+ {% endif %}
+
+ <!-- Upload form. Note enctype attribute! -->
+ <form action="{% url 'list' %}" method="post" enctype="multipart/form-data">
+ {% csrf_token %}
+ <p>{{ form.non_field_errors }}</p>
+
+ <p>{{ form.docfile.label_tag }} {{ form.docfile.help_text }}</p>
+
+ <p>
+ {{ form.docfile.errors }}
+ {{ form.docfile }}
+ </p>
+
+
+
+ <p><input type="submit" value="Upload"/></p>
+ </form>
+ </body>
+
+</html>
--- /dev/null
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8">
+ <title>WagnerTech - Eigenheimer - Abgleich</title>
+ </head>
+
+ <body>
+
+ <!-- Upload form. Note enctype attribute! -->
+ <form action="{% url 'eh_abgleich' %}" method="post" enctype="multipart/form-data">
+ {% csrf_token %}
+ <p>{{ form.file1.label_tag }} {{ form.file1 }}</p>
+ <p>{{ form.file2.label_tag }} {{ form.file2 }}</p>
+
+ <p><input type="submit" value="Vergleich starten"/></p>
+ </form>
+ </body>
+
+</html>
--- /dev/null
+from django.test import TestCase
+
+# Create your tests here.
--- /dev/null
+from django.urls import path
+
+from . import views
+
+urlpatterns = [
+ path('', views.index, name='index'),
+ path('ss', views.upload_file, name='upload_file1'),
+ path('aa', views.list, name='list')
+]
--- /dev/null
+from django.shortcuts import render
+from django.http import HttpResponse, HttpResponseRedirect
+from eh_abgleich.forms import UploadFileForm, DocumentForm
+
+# Create your views here.
+
+
+def index(request):
+ return HttpResponse("Hello, world. You're at the polls index.")
+
+
+# Imaginary function to handle an uploaded file.
+#from somewhere import handle_uploaded_file
+
+def upload_file(request):
+ if request.method == 'POST':
+ form = UploadFileForm(request.POST, request.FILES)
+ if form.is_valid():
+ #handle_uploaded_file(request.FILES['file'])
+ return HttpResponseRedirect('/success/url/')
+ else:
+ form = UploadFileForm()
+ return render(request, 'upload.html', {'form': form})
+
+def list(request):
+ # Handle file upload
+ if request.method == 'POST':
+ form = DocumentForm(request.POST, request.FILES)
+ if form.is_valid():
+ #newdoc = Document(docfile = request.FILES['docfile'])
+ #newdoc.save()
+
+ # Redirect to the document list after POST
+ return HttpResponseRedirect(reverse('list'))
+ else:
+ form = DocumentForm() # A empty, unbound form
+
+ # Load documents for the list page
+ #documents = Document.objects.all()
+ documents = {}
+
+
+ # Render list page with the documents and the form
+ return render(request, 'list.html', {'documents': documents, 'form': form})
--- /dev/null
+from django import forms
+
+class LoginForm(forms.Form):
+ verein = forms.CharField(label = "Vereinskürzel")
+ name = forms.CharField(label = "Login-Name")
+ password = forms.CharField(widget=forms.PasswordInput, label = "Passwort")
+ next = forms.CharField(widget = forms.HiddenInput(), required = False)
--- /dev/null
+"""
+Django settings for eh_util project.
+
+Generated by 'django-admin startproject' using Django 2.2.28.
+
+For more information on this file, see
+https://docs.djangoproject.com/en/2.2/topics/settings/
+
+For the full list of settings and their values, see
+https://docs.djangoproject.com/en/2.2/ref/settings/
+"""
+
+import os
+
+# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
+BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
+MEDIA_ROOT = BASE_DIR
+
+# Quick-start development settings - unsuitable for production
+# See https://docs.djangoproject.com/en/2.2/howto/deployment/checklist/
+
+# SECURITY WARNING: keep the secret key used in production secret!
+SECRET_KEY = 'x8xmlmq_%a3^rp7@1x0n%ugebrp!4@hc*5@=g%&6fo@5m3g!kw'
+
+# SECURITY WARNING: don't run with debug turned on in production!
+DEBUG = True
+
+ALLOWED_HOSTS = []
+
+LOGIN_URL = "/eh-util/login"
+
+# Application definition
+
+INSTALLED_APPS = [
+ 'eh_app.apps.EhAppConfig',
+# 'ausweis.apps.AusweisConfig',
+# 'kassenbrief.apps.KassenbriefConfig',
+ 'django.contrib.admin',
+ 'django.contrib.auth',
+ 'django.contrib.contenttypes',
+ 'django.contrib.sessions',
+ 'django.contrib.messages',
+ 'django.contrib.staticfiles',
+]
+
+MIDDLEWARE = [
+ 'django.middleware.security.SecurityMiddleware',
+ 'django.contrib.sessions.middleware.SessionMiddleware',
+ 'django.middleware.common.CommonMiddleware',
+ 'django.middleware.csrf.CsrfViewMiddleware',
+ 'django.contrib.auth.middleware.AuthenticationMiddleware',
+ 'django.contrib.messages.middleware.MessageMiddleware',
+ 'django.middleware.clickjacking.XFrameOptionsMiddleware',
+]
+
+ROOT_URLCONF = 'eh_util.urls'
+
+TEMPLATES = [
+ {
+ 'BACKEND': 'django.template.backends.django.DjangoTemplates',
+ 'DIRS': [os.path.join(BASE_DIR, "eh_util/templates"), os.path.join(BASE_DIR, "eh_utils/eh_app/templates/svbal")],
+ 'APP_DIRS': True,
+ 'OPTIONS': {
+ 'context_processors': [
+ 'django.template.context_processors.debug',
+ 'django.template.context_processors.request',
+ 'django.contrib.auth.context_processors.auth',
+ 'django.contrib.messages.context_processors.messages',
+ ],
+ },
+ },
+]
+
+WSGI_APPLICATION = 'eh_util.wsgi.application'
+
+
+# Database
+# https://docs.djangoproject.com/en/2.2/ref/settings/#databases
+
+DATABASES = {
+ 'default': {
+ 'ENGINE': 'django.db.backends.sqlite3',
+ 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
+ }
+}
+
+
+# Password validation
+# https://docs.djangoproject.com/en/2.2/ref/settings/#auth-password-validators
+
+AUTH_PASSWORD_VALIDATORS = [
+ #{
+ # 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
+ #},
+ #{
+ # 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
+ #},
+ #{
+ # 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
+ #},
+ #{
+ # 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
+ #},
+]
+
+
+# Internationalization
+# https://docs.djangoproject.com/en/2.2/topics/i18n/
+
+LANGUAGE_CODE = 'en-us'
+
+TIME_ZONE = 'UTC'
+
+USE_I18N = True
+
+USE_L10N = True
+
+USE_TZ = True
+
+
+# Static files (CSS, JavaScript, Images)
+# https://docs.djangoproject.com/en/2.2/howto/static-files/
+
+STATIC_URL = '/static/'
--- /dev/null
+<html>
+<head>
+ <title>Siedlerverein-Verwaltung by WagnerTech UG</title>
+</head>
+<body>
+<h1>Siedlerverein-Verwaltung by WagnerTech UG</h1>
+<p>Wählen Sie Ihren Verein:</p>
+<p><a href="svbal/">Siedlervereinigung Berg am Laim</a></p>
+</body>
+</html>
--- /dev/null
+<html>
+<head>
+ <title>Siedlerverein-Verwaltung by WagnerTech UG</title>
+</head>
+<body>
+<h1>Siedlerverein-Verwaltung by WagnerTech UG</h1>
+<p>Verfügbare Funktionen für {{verein}}:</p>
+<p><a href="ausweis">Ausweiserstellung</a></p>
+<p><a href="kassenbrief">Erstellung der Kassenbriefe</a></p>
+</body>
+</html>
--- /dev/null
+"""eh_util URL Configuration
+
+The `urlpatterns` list routes URLs to views. For more information please see:
+ https://docs.djangoproject.com/en/2.2/topics/http/urls/
+Examples:
+Function views
+ 1. Add an import: from my_app import views
+ 2. Add a URL to urlpatterns: path('', views.home, name='home')
+Class-based views
+ 1. Add an import: from other_app.views import Home
+ 2. Add a URL to urlpatterns: path('', Home.as_view(), name='home')
+Including another URLconf
+ 1. Import the include() function: from django.urls import include, path
+ 2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
+"""
+from django.contrib import admin
+from django.urls import include, path
+import eh_util
+from . import views
+
+urlpatterns = [
+ path('', views.index),
+ path('login/', views.login),
+ path('admin/', admin.site.urls),
+ path('eh-abgleich/', include('eh_abgleich.urls')),
+# path('<slug:verein>/', views.vbasis),
+# path('<slug:verein>/ausweis/', include('ausweis.urls')),
+# path('<slug:verein>/kassenbrief/', include('kassenbrief.urls')),
+ path('<slug:verein>/', include('eh_app.urls')),
+]
--- /dev/null
+from django.http import HttpResponse, HttpResponseRedirect
+from django.shortcuts import render
+from django.template import loader
+
+
+def index(request):
+ template = loader.get_template('index.html')
+ return HttpResponse(template.render({}, request))
+
+def login(request):
+ from django.contrib import auth
+ from .forms import LoginForm
+
+ fehlertext = ""
+ # if this is a POST request we need to process the form data
+ if request.method == 'POST':
+ # create a form instance and populate it with data from the request:
+ form = LoginForm(request.POST, request.FILES)
+ # check whether it's valid:
+ if form.is_valid():
+ user = auth.authenticate(
+ username = request.POST["name"],
+ password = request.POST["password"],
+ )
+ if user is None:
+ # login fehlgeschlagen
+ fehlertext = "Login fehlgeschlagen"
+
+ else:
+ auth.login(request, user)
+ next = request.POST.get("next", None)
+ if next:
+ return HttpResponseRedirect(next)
+ else:
+ return HttpResponseRedirect('/')
+
+ # if a GET (or any other method) we'll create a blank form
+ else:
+ next = None
+ verein = ""
+ next = request.GET.get("next", None)
+ if next:
+ path_elems = next.split("/")
+ verein = path_elems[1]
+ form = LoginForm(initial={'next': next, 'verein': verein})
+
+ return render(request, 'login.html', {'form': form, 'fehlertext': fehlertext})
+
+def vbasis(request, verein):
+ template = loader.get_template("vbasis.html")
+ raise RuntimeError("blub")
+ return HttpResponse(template.render({"verein" : verein}, request))
+
--- /dev/null
+"""
+WSGI config for eh_util project.
+
+It exposes the WSGI callable as a module-level variable named ``application``.
+
+For more information on this file, see
+https://docs.djangoproject.com/en/2.2/howto/deployment/wsgi/
+"""
+
+import os
+
+from django.core.wsgi import get_wsgi_application
+
+os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'eh_util.settings')
+
+application = get_wsgi_application()
--- /dev/null
+from django.contrib import admin
+
+# Register your models here.
--- /dev/null
+from django.apps import AppConfig
+
+
+class KassenbriefConfig(AppConfig):
+ name = 'kassenbrief'
--- /dev/null
+from django.db import models
+
+# Create your models here.
--- /dev/null
+from django.test import TestCase
+
+# Create your tests here.
--- /dev/null
+from django.urls import path
+
+from . import views
+
+urlpatterns = [
+ path('', views.index),
+]
\ No newline at end of file
--- /dev/null
+from django.http import HttpResponse
+from django.shortcuts import render
+
+# Create your views here.
+
+def index(request):
+
+ return HttpResponse("NYI")
+++ /dev/null
-#!/usr/bin/python3
-'''
-Created on 10.01.2024
-
-@author: sparky2021
-'''
-
-import sys
-
-if __name__ == '__main__':
- pass
-
-numArgs = len(sys.argv)
-if (numArgs != 4):
- raise RuntimeError("usage: sv-merger EXPORT DELTA FIELD")
-
-
-dh_export = open(sys.argv[1])
-dh_delta = open(sys.argv[2])
-dh_import = open("import.csv", "w")
-
-# Lese die Kopfzeile aus EXPORT
-line = dh_export.readline().rstrip()
-print(line, file=dh_import)
-export_header = line.split(";")
-
-sv_pn_spalte = -1
-sv_such_spalte = -1
-
-i = 0
-for kopf in export_header:
- kopf = kopf[1:-1]
- if kopf == 'Freifeldwert_1':
- sv_pn_spalte = i
- if kopf == sys.argv[3]:
- sv_such_spalte = i
- i += 1
-
-if sv_pn_spalte == -1:
- raise RuntimeError("S-Verein-Export enthält keine Partnernummer")
-if sv_such_spalte == -1:
- raise RuntimeError("S-Verein-Export enthält nicht das gewünschte Datenfeld "+sys.argv[3])
-
-line = dh_delta.readline().rstrip()
-delta_header = line.split(";")
-
-delta_pn_sp = -1
-delta_such_sp = -1
-
-i = 0
-for kopf in delta_header:
- if kopf == "Partnernummer":
- delta_pn_sp = i
- if kopf == sys.argv[3]:
- delta_such_sp = i
- i += 1
-
-if delta_pn_sp == -1:
- raise RuntimeError("Delta-Datei enthält keine Partnernummer")
-if delta_such_sp == -1:
- raise RuntimeError("Delta-Datei enthält nicht das gewünschte Datenfeld")
-
-delta = {}
-for line in dh_delta:
- if len(line.rstrip()):
- # not a empty line
- data = line.split(";")
- delta[int(data[delta_pn_sp])] = data[delta_such_sp]
-
-for line in dh_export:
- data = line.rstrip().split(";")
- pn = data[sv_pn_spalte][1:-1]
- if len(pn):
- pn = int(pn)
- if pn in delta:
- if len(delta[pn]):
- if data[sv_such_spalte] != delta[pn]:
- data[sv_such_spalte] = delta[pn]
- print(";".join(data), file=dh_import)
-
-dh_export.close()
-dh_delta.close()
-dh_import.close()
-
-'''
-Argumente:
-
-EXPORT: Export-Datei aus S-Verein
-
-DELTA: csv-Daten, die eingearbeitet werden sollen
-
-FIELD: Feld, das eingearbeitet werden soll, wenn
- - Das Quellfeld nicht leer ist
- - Sich der Wert von der EXPORT-Datei unterscheidet
-
-Die Synchronisation der Daten erfolgt anhand der Partnernummer.
-
-Das Ergebnis wird stets in die Datei import.csv geschrieben.
-'''