package com.dvelop.hooks;


import com.amazonaws.util.IOUtils
import com.dvelop.d3.server.Document
import com.dvelop.d3.server.DocumentType
import com.dvelop.d3.server.User
import com.dvelop.d3.server.core.D3Interface
import com.dvelop.d3.server.exceptions.D3Exception
import com.google.gson.JsonArray
import com.google.gson.JsonElement
import com.google.gson.JsonObject
import com.google.gson.JsonParser
import groovy.json.StringEscapeUtils
import org.apache.http.HttpEntity
import org.apache.http.client.methods.CloseableHttpResponse
import org.apache.http.client.methods.HttpGet
import org.apache.http.client.methods.HttpPost
import org.apache.http.entity.StringEntity
import org.apache.http.impl.client.CloseableHttpClient
import org.apache.http.impl.client.HttpClientBuilder
import org.apache.http.util.EntityUtils
import groovy.json.JsonSlurper
import java.nio.charset.StandardCharsets;

import wslite.*
import wslite.soap.*

// Global d.3 libraries
import com.dvelop.d3.server.core.D3Interface;
import com.dvelop.d3.server.Document;
import com.dvelop.d3.server.User;
import com.dvelop.d3.server.DocumentType;
 
// Libraries to handle the diferent hook types
import com.dvelop.d3.server.Entrypoint;




public class D3Hooks
{
	
	
	@Entrypoint( entrypoint = "hook_insert_entry_10" )
	public int insertEntry_10( D3Interface d3, User user, DocumentType docTypeShort, Document doc )
	{
		//Alle Dokumente und Akten sollen im Status Freigabe importiert werden:
		doc.setStatus( "Freigabe" );
		
		
		//def e = getUserIdpId( d3, "dvelop", "b3be8a21-9cc1-5079-8dac-1c719ac7f80f", "https://d3one-test.kleeberg.kleeberg.de/", "lEtMJfO/jQqDvrfHTtdD5GZ0Ro8S5/UVO1NQkxGwrFCTznNl78gKtcUXXBn1mdVZh75+Nym9PjcZTZyIGrT16Nt9Lbqjpz0A3B/qCF9kDZI=&_z_A0V5ayCRn_Bn5wFTNnf3FUYT7AzFYDFJtTKz2vib1R4XhvF5pT8ZXjCzqiNkbw6I2Nrk4uR-QafuJy0XujnfyNQFfItf3" );
		def sqlQuery		= "";
		def where			= "";
		def resultRows		= "";
		def oreg, reg, ureg, ureg2, ureg3, such_doku_art;
		def where_allg	= " dok_dat_feld_1 = '"+ doc.field[ 1 ] + "' ";
		

		
		//////////////////////////////////////
		// Prüfen, ob in einem der Benutzerfelder eine E-Mail-Adresse angegeben wurde. Ist das der Fall, so wird der entsprechende Benutzer in der Benutzer-Tabelle gesucht und mit seinem Kürzel eingetragen. START
		//////////////////////////////////////
		
		if ( docTypeShort.id == "AMAND" )
		{
			
			// Hier wird für die Eigenschaft Geschäftsführer aus der Tribus-Schnittstelle das DDF45 gefüllt. Benutzt wird in der Akte das Feld 25. Gemacht wird diese Brücke, damit sich Änderungen 
			// an der Akte im DATEV nicht direkt in Aktenaktualisierungsjobs im d.3 manifestieren. Das gleiche Verfahren wird für den Mandatsverantwortlichen verwendet.
			
			
			
			///////////////////////////////////////////
			// DDF 25 / Geschäftsführer
			///////////////////////////////////////////
			def benutzername = "nicht ermittelbar";
			if ( doc.field[ 45 ] )
			{
				if ( doc.field[ 45 ].indexOf( "@" ) > 0 )
				{
					def sql_STATEMENT = "select realname + ' (' + benutzername + ')' as realbenutzername from benutzer where email = '" + doc.field[ 45 ] + "'";
					
					def sql_resultRows = d3.sql.executeAndGet( (String) sql_STATEMENT );
					
					if ( sql_resultRows.size() > 0 )
					{
						benutzername = sql_resultRows[ 0 ].realbenutzername;
					}
				}
			}
			
			xlog( d3, 4, "Mandatenakte " + doc.id + " / " + doc.field[ 1 ] + " : GF " + benutzername );
				
			doc.field[ 25 ] = benutzername;
			
			
			///////////////////////////////////////////
			// DDF 37 / Mandatsverantwortlicher
			///////////////////////////////////////////
			benutzername = "nicht ermittelbar";
			if ( doc.field[ 44 ] )
			{
				if ( doc.field[ 44 ].indexOf( "@" ) > 0 )
				{ 
					def sql_STATEMENT = "select realname + ' (' + benutzername + ')' as realbenutzername from benutzer where email = '" + doc.field[ 44 ] + "'";
					
					def sql_resultRows = d3.sql.executeAndGet( (String) sql_STATEMENT );
					
					if ( sql_resultRows.size() > 0 )
					{
						benutzername = sql_resultRows[ 0 ].realbenutzername;
					}
				}
			}
			
			xlog( d3, 4, "Mandatenakte " + doc.id + " / " + doc.field[ 1 ] + " : GF " + benutzername );
			
			doc.field[ 37 ] = benutzername;
			
			
			
			
		}
		
		//////////////////////////////////////
		// Prüfen, ob in einem der Benutzerfelder eine E-Mail-Adresse angegeben wurde. Ist das der Fall, so wird der entsprechende Benutzer in der Benutzer-Tabelle gesucht und mit seinem Kürzel eingetragen. ENDE
		//////////////////////////////////////
		
		
		/////////////////////////////////////////
		// Allgemeines START
		/////////////////////////////////////////
		
		
		switch ( docTypeShort.id )
		{
			// Das folgende betrifft alle Mandantenakte-Dokument- und Aktenarten:
			case "DBETR":
			case "DDAUE":
			case "DABSC":
			case "DBERA":
			case "DSTEU":
			case "DFIBU":
			case "DLOHN":
			case "DDEBD":
			case "DLSTD":
			case "DKRED":
			
			case "AMAND":
			
			case "ABPSA":
			case "ABESA":
			case "AFBSA":
			case "AJASA":
			case "ALOSA":
			case "ASTSA":
			
			case "AJAOB":
			case "ALBRE":
			case "AJAAB":
			case "ABERO":
			case "ABERA":
			case "ASTOR":
			case "ASTRA":
			case "ABEPA":
			case "ABEOR":
			case "AFIOR":
			case "AFIRA":
			case "ALBOR":
			case "ALBSO":
			case "AAURR":
			case "AKROR":
			case "DUMMY":
			case "AOREG":
			case "AREGS":
			case "AUREG":
			case "AURG2":
			case "AURG3":
			case "AAURU":
			case "AAUR2":
			case "ABEUR":
			case "ABEU2":
			case "ABPUR":
			case "ABPU2":
			case "AFIUR":
			case "AFIU2":
			case "AJAUR":
			case "AJAU2":
			case "ALJUR":
			case "ALOUR":
			case "ALJR2":
			case "ALBU2":
			case "ASTU2":
			case "ASTUR":
			case "ADAUR":
			case "ABERB":
			case "ABETR":
			case "AFIBA":
			case "AJAAA":
			case "AKRED":
			case "ALOJA":
			case "ALBSA":
			case "ASTEU":
			
				
			
			
			
			
			//////////////////////////////////////
			// Falls "gesperrt" nicht gesetzt ist, setze das Feld auf "Nein" START
            //////////////////////////////////////
			
			if ( ! doc.field[ 43 ] )
			{
				doc.field[ 43 ] = "Nein";
			}
			
			//////////////////////////////////////
			// Falls "gesperrt" nicht gesetzt ist, setze das Feld auf "Nein" ENDE
            //////////////////////////////////////
			
			
			
			
			//////////////////////////////////////
			// Falls "Benachrichtigung Postempfänger" nicht gesetzt ist, setze das Feld auf "Nein" START
            //////////////////////////////////////
			
			if ( ! doc.field[ 38 ] )
			{
				doc.field[ 38 ] = "Nein";
			}
			
			//////////////////////////////////////
			// Falls "Benachrichtigung Postempfänger" nicht gesetzt ist, setze das Feld auf "Nein" ENDE
            //////////////////////////////////////
			
			
            //////////////////////////////////////
			// Falls Aktennummer gesetzt, fülle die Mandantinformationen: START
            //////////////////////////////////////
				
            if ( doc.field[ 10 ] )
            {
				doc.field[ 1 ] = doc.field[ 10 ].substring( 0, 5 );
				
				sqlQuery = "select dok_dat_feld_1, dok_dat_feld_2, dok_dat_feld_13 from firmen_spezifisch where kue_dokuart = 'AMAND' and dok_dat_feld_1 = '" + doc.field[ 1 ] + "'";
				
				resultRows = d3.sql.executeAndGet( (String) sqlQuery );
				
				
				if ( resultRows.size() > 0 )
				{
					doc.field[  2 ] = resultRows[ 0 ].dok_dat_feld_2;
					doc.field[ 13 ] = resultRows[ 0 ].dok_dat_feld_13;
				}
            }
            
            
            
            
            //////////////////////////////////////
			// Falls Aktennummer gesetzt, fülle die Mandantinformationen: ENDE
            //////////////////////////////////////
            
		
		
			// Prüfe, ob Aktennummer angegeben wurde und gleichzeitig die Mandantennummer weggelassen wurde. Dann kann die Mandantennummer aus der Aktennummer extrahiert werden.
			if ( ( ! doc.field[ 1 ] ) && ( doc.field[ 10 ] ) )
			{
				doc.field[ 1 ] = doc.field[ 10 ].substring( 0, 5 );
			}
			
			
			
			
			// Falls Unterregister leer: leere auch Unterregister 2
			if ( ! doc.field[ 23 ] )
			{
				doc.field[ 17 ] = "";
			}
			
			// Falls Unterregister 2 leer: leere auch Unterregister 3
			if ( ! doc.field[ 17 ] )
			{
				doc.field[ 32 ] = "";
			}
			
			
			/////////////////////////////////////////
			// Setzen der Register START
			/////////////////////////////////////////
			
			
			def wm_typ = "";
			def do_it = 0;      // Steuerung des Füllens des Registers auf Basis des Dokumenttyps
			def gj_do_it = 0;   // Steuerung des Füllens des Feldes Geschäftsjahr
			
			
			switch ( docTypeShort.id )
			{
				case "DDAUE":
					wm_typ = "Dauerakte";
					
					// Sonderfall Unterregister: Unterregister gefüllt? Falls ja: Oberregister + Register können direkt gefüllt werden.
					// 
					if ( doc.field[ 23 ] != null )
					{
						sqlQuery = "select dok_dat_feld_2, dok_dat_feld_3 from firmen_spezifisch where kue_dokuart = 'AVMNT' and dok_dat_feld_1 = '" + wm_typ + "' and dok_dat_feld_4 = '" + doc.field[ 23 ] + "'";
						
						resultRows = d3.sql.executeAndGet( (String) sqlQuery );
						
						if ( resultRows.size() > 0 )
						{
							doc.field[ 3 ] = resultRows[ 0 ].dok_dat_feld_2;
							doc.field[ 4 ] = resultRows[ 0 ].dok_dat_feld_3;
						}
						else
						{
							do_it = 1;
						}
					}
					else
					{
						do_it = 1;
					}
					break;
				case "DABSC":
					do_it = 1;
					wm_typ = "Jahresabschlussakte";
					gj_do_it = 1;
					break;
				case "DBERA":
				case "ABERA":
					do_it = 1;
					wm_typ = "Beratungsakte";
					gj_do_it = 1;
					break;
				case "DSTEU":
					do_it = 1;
					wm_typ = "Steuerakte";
					gj_do_it = 2;
					break;
				case "DBETR":
					do_it = 1;
					wm_typ = "Betriebspruefungsakte";
					gj_do_it = 2;
					break;
				case "DLOHN":
					do_it = 1;
					wm_typ = "Lohnbuchhaltungjahresakte";
					gj_do_it = 2;
					break;
				case "DLSTD":
					do_it = 1;
					wm_typ = "Lohnbuchhaltungsstammdatenakte";
					// In den Lohnbuchhaltungsstammdaten gibt es kein Geschäftsjahr, daher bleibt gj_do_it unverändert
					break;
				case "DDEBD":
					do_it = 1;
					wm_typ = "Ausgangsrechnungsregister";
					gj_do_it = 1;
					break;
				case "DKRED":
					do_it = 1;
					wm_typ = "Kreditorenaktenregister";
					gj_do_it = 1;
					break;
				
				default:
					break;
			}
			
			
			
			// Register gefüllt?
			if ( ( doc.field[ 4 ] != null ) && ( do_it == 1 ) )
			{
				// Füllen des Registers auf Basis des Dokumenttyps
				sqlQuery = "select dok_dat_feld_2 from firmen_spezifisch where kue_dokuart = 'AVMNT' and dok_dat_feld_1 = '" + wm_typ + "' and dok_dat_feld_3 = '" + doc.field[ 4 ] + "'";
				
				resultRows = d3.sql.executeAndGet( sqlQuery );
				
				if ( resultRows.size() > 0 )
				{
					doc.field[ 3 ] = resultRows[ 0 ].dok_dat_feld_2;
				}
				
			}
			
			
			
			switch ( gj_do_it )
			{
				case 1:
					// Wird verwendet für Dokumentarten in der Mandantenakte, die sowohl das Geschäftsjahr als auch das Belegdatum enthalten.
					// Falls ein Belegdatum angegeben wurde, aber kein Geschäftsjahr, setze Geschäftsjahr auf das Jahr des Belegdatums
					if ( ( doc.field[ 50 ] ) && ( ! doc.field[ 5 ] ) )
					{
						def jahr = doc.field[ 50 ].getYear().toInteger() + 1900;
						doc.field[ 5 ] = jahr.toString();
					}
					break;
				case 2:
					// Wird verwendet für Dokumentarten in der Mandantenakte, die das Geschäftsjahr, nicht aber das Belegdatum enthalten.
					// Falls Geschäftsjahr leer ist: setze aktuelles Jahr
					if ( ! doc.field[ 5 ] )
					{
						def jahr = new Date().getYear().toInteger() + 1900;
						doc.field[ 5 ] = jahr.toString();
					}
					break;
			}
			
			
			/////////////////////////////////////////
			// Setzen der Register ENDE
			/////////////////////////////////////////
				
		}
		
		
		
		/////////////////////////////////////////
		// Allgemeines ENDE
		/////////////////////////////////////////
		
		
		
		
		
		
		/////////////////////////////////////////
		// Kreditor Stammdatenergänzung START
		/////////////////////////////////////////
		
		
		if ( docTypeShort.id == "DKRED" )
		{
			if ( doc.field[ 10 ] )
			{
				doc.field[ 19 ] = doc.field[ 10 ].substring( 0, 5 );
			}
			
			if ( ( doc.field[ 19 ] ) && ( ! doc.field[ 20 ] ) )
			{
				sqlQuery = "select dok_dat_feld_20 from firmen_spezifisch where kue_dokuart = 'AKRED' and dok_dat_feld_19 = '" + doc.field[ 19 ] + "' ";
					
				resultRows = d3.sql.executeAndGet( (String) sqlQuery );
				
				if ( resultRows.size() > 0 )
				{
					doc.field[ 20 ] = resultRows[ 0 ].dok_dat_feld_20;
				}
			}
			
			if ( ( doc.field[ 20 ] ) && ( ! doc.field[ 19 ] ) )
			{
				sqlQuery = "select dok_dat_feld_19 from firmen_spezifisch where kue_dokuart = 'AKRED' and dok_dat_feld_20 = '" + doc.field[ 20 ] + "' ";
					
				resultRows = d3.sql.executeAndGet( (String) sqlQuery );
				
				if ( resultRows.size() > 0 )
				{
					doc.field[ 19 ] = resultRows[ 0 ].dok_dat_feld_19;
				}
			}

		}
		
		
		/////////////////////////////////////////
		// Kreditor Stammdatenergänzung ENDE
		/////////////////////////////////////////
		
		
		/////////////////////////////////////////
		// Eigenverwaltungsakte Stammdatenergänzung START
		/////////////////////////////////////////
		
		switch ( docTypeShort.id )
		{
			case "DEVDO":
			case "AEVAK":
			case "AEVOR":
			case "AEVRE":
				
				if ( ( doc.field[ 10 ] ) && ( ! doc.field[ 21 ] ) )
				{
					sqlQuery = "select dok_dat_feld_21 from firmen_spezifisch where kue_dokuart = 'AEVAK' and dok_dat_feld_10 = '" + doc.field[ 10 ] + "' ";
					
					resultRows = d3.sql.executeAndGet( (String) sqlQuery );
					
					if ( resultRows.size() > 0 )
					{
						doc.field[ 21 ] = resultRows[ 0 ].dok_dat_feld_21;
					}
				}
				
				if ( ( doc.field[ 21 ] ) && ( ! doc.field[ 10 ] ) )
				{
					sqlQuery = "select dok_dat_feld_10 from firmen_spezifisch where kue_dokuart = 'AEVAK' and dok_dat_feld_21 = '" + doc.field[ 21 ] + "' ";
					
					resultRows = d3.sql.executeAndGet( (String) sqlQuery );
					
					if ( resultRows.size() > 0 )
					{
						doc.field[ 10 ] = resultRows[ 0 ].dok_dat_feld_10;
					}
				}
		}
		
		/////////////////////////////////////////
		// Eigenverwaltungsakte Stammdatenergänzung ENDE
		/////////////////////////////////////////
		
		
		//////////////////////////////////////////////////////
		// Verarbeitung Mandantenakte START
		//////////////////////////////////////////////////////
		
		
		switch ( docTypeShort.id )
		{
			case "AMAND":
				
				
				break;
			case "DBETR":
				
				//////////////////////////////////////
				// Bei Betriebsprüfungsdokumenten müssen die Prüfungsart und der Prüfungszeitraum von der Akte geholt und an das Dokument ergänzt werden START
				//////////////////////////////////////
				
				if ( doc.field[ 10 ] )
				{
					sqlQuery = "select dok_dat_feld_12, dok_dat_feld_14 from firmen_spezifisch where kue_dokuart = 'ABETR' and dok_dat_feld_10 = '" + doc.field[ 10 ] + "' ";
					
					resultRows = d3.sql.executeAndGet( (String) sqlQuery );
					
					if ( resultRows.size() > 0 )
					{
						if ( resultRows[ 0 ].dok_dat_feld_12 )
						{
							doc.field[ 12 ] = resultRows[ 0 ].dok_dat_feld_12;
						}
						
						if ( resultRows[ 0 ].dok_dat_feld_14 )
						{
							doc.field[ 14 ] = resultRows[ 0 ].dok_dat_feld_14;
						}
					}
				}
				
				
				
				
				
				
				//////////////////////////////////////
				// Bei Betriebsprüfungsdokumenten müssen die Prüfungsart und der Prüfungszeitraum von der Akte geholt und an das Dokument ergänzt werden ENDE
				//////////////////////////////////////
				
			case "DDAUE":
			case "DEVDO":
			case "DABSC":
			case "DBERA":
			case "DSTEU":
			case "DFIBU":
			case "DLOHN":
			case "DDEBD":
			case "DLSTD":
			case "DKRED":
				
				
				
            
            
            
				
				// Falls Betreff leer: setze Betreff auf den Dateinamen
				if ( ! doc.field[ 6 ] )
				{
					doc.field[ 6 ] =  doc.getFilename();
					d3.log.info( "setze Betreff auf " +  doc.getFilename() );
				}
				
				// Falls Dokumentdatum leer: Setze Dokumentdatum auf Tagesdatum
				if ( ! doc.field[ 50 ] )
				{
					doc.field[ 50 ] = new Date();
				}
				
				
				// Für Eigenverwaltungsdokumente ist hier Schluss.
				if ( docTypeShort.id == "DEVDO" )
				{
					break;
				}
				
				//////////////////////////////////////
				// Im Zuge der Archivierung muss geprüft werden, ob es unterhalb der angegebenen Register noch weitere Unterregister gibt. Ist das der Fall, müssen diese vom Anwender ausgewählt werden;
				// d.h. eine Archivierung wird dann abgelehnt.  START
				//////////////////////////////////////
				
				// Diese Logik ist aufgrund einer E-Mail von Hrn. Meyer vom 11. Februar 2022 13:58 Uhr an JFEL, ISTRE und CBUE deaktiviert.
				
				
				if ( false ) // Logik ist deaktiviert
				{
					// Festlegen, in welcher Aktenart gesucht werden soll:
					
					switch( docTypeShort.id )
					{
						case "DDAUE":				// Dauerakte
							oreg	= "AOREG";
							reg		= "AREGS";
							ureg	= "AUREG";
							ureg2	= "AURG2";
							ureg3	= "AURG3";
							break;
						case "DABSC":				// Jahresabschlussakte
							oreg	= "AJAOB";
							reg		= "AJAAB";
							ureg	= "AJAUR";
							ureg2	= "AJAU2";
							break;
						case "DBERA":				// Beratungsakte
							oreg	= "ABERO";
							reg		= "ABERA";
							ureg	= "ABEUR";
							ureg2	= "ABEU2";
							break;
						case "DSTEU":				// Steuerakte
							oreg	= "ASTOR";
							reg		= "ASTRA";
							ureg	= "ASTUR";
							ureg2	= "ASTU2";
							break;
						case "DBETR":				// Betriebspruefungsakte
							oreg	= "ABEOR";
							reg		= "ABEPA";
							ureg	= "ABPUR";
							ureg2	= "ABPU2";
							break;
						case "DFIBU":				// Finanzbuchhaltungsakte
							oreg	= "AFIOR";
							reg		= "AFIRA";
							ureg	= "AFIUR";
							ureg2	= "AFIU2";
							break;
						case "DLOHN":				// Lohnbuchhaltungjahresakte
							oreg	= "ALBOR";
							reg		= "ALBRE";
							ureg	= "ALJUR";
							ureg2	= "ALJR2";
							break;
						case "DDEBD":				// Ausgangsrechnungsakte
							oreg	= "AAURR";
							reg		= "AAURA";
							ureg	= "AAURU";
							ureg2	= "AAUR2";
							break;
						case "DLSTD":				// Lohnbuchhaltungsstammdatenakte
							oreg	= "ALBSO";
							reg		= "ALORE";
							ureg	= "ALOUR";
							ureg2	= "ALBU2";
							break;
						case "DKRED":				// Kreditorenakte
							oreg	= "AKROR";
							reg		= "AKRER";
							ureg	= "AKREU";
							ureg2	= "AKRU2";
							break;
					}
					
					
					
					
					def such_feld;
					def such_ok = false;
					def add_i_t;
					
					where = "";
					
					if ( doc.field[ 3 ] )  // Oberregister
					{
						where				= " and dok_dat_feld_3 = '" + doc.field[ 3 ] + "' ";
						such_doku_art	= reg;
						such_feld		= 4;
						add_i_t			= "Es gibt Register unterhalb von '" + doc.field[ 3 ] + "'. Bitte verwenden Sie diese.";
						such_ok			= true;
						
						if ( doc.field[ 4 ] )  // Register
						{
							where				= where + " and dok_dat_feld_4 = '" + doc.field[ 4 ] + "' ";
							such_doku_art	= ureg;
							such_feld		= 23;
							add_i_t			= "Es gibt Register unterhalb von '" + doc.field[ 4 ] + "'. Bitte verwenden Sie diese.";
							such_ok			= true;
							
							if ( doc.field[ 23 ] )  // Unterregister
							{
								where				= where + " and dok_dat_feld_23 = '" + doc.field[ 23 ] + "'  ";
								such_doku_art	= ureg2;
								such_feld		= 17;
								add_i_t			= "Es gibt Register unterhalb von '" + doc.field[ 23 ] + "'. Bitte verwenden Sie diese.";
								such_ok			= true;
								
								if ( doc.field[ 17 ] )  // 2. Unterregister
								{
									where				= where + " and dok_dat_feld_17 = '" + doc.field[ 17 ] + "'  ";
									such_doku_art	= ureg3;
									such_feld		= 32;
									add_i_t			= "Es gibt Register unterhalb von '" + doc.field[ 17 ] + "'. Bitte verwenden Sie diese.";
									such_ok			= true;
									
									if (  doc.field[ 32 ] )  // 3. Unterregister
									{
										// Wenn das 3. Unterregister gefüllt ist, braucht die Prüfung nicht stattzufinden, weil der Anwender eh keine weiteren Register angeben kann.
										// Da ist dann nur noch die Prüfung fällig, ob das Register auch existiert, die findet aber an anderer Stelle statt.
										
										such_ok = false;
									}
								}
							}
						}
					}
					
					
					
					
					if ( such_ok )
					{
						
						where = where_allg + where + " and dok_dat_feld_" + such_feld + " is not null ";
						
						sqlQuery = "select count(*) anzahl from firmen_spezifisch where kue_dokuart = '" + such_doku_art + "' and " + where;
						
						resultRows = d3.sql.executeAndGet( (String) sqlQuery );
						
						if ( resultRows.size() > 0 )
						{
							if ( resultRows[ 0 ].anzahl > 0 )
							{
								// Es wurde eine Kombination gefunden => es gibt vorhandene, aber nicht vom Anwender ausgewählte Unterregister.
								d3.hook.setProperty( "additional_info_text", add_i_t );
								return -502;
							}
						}
					}
				
				
				}
				
				//////////////////////////////////////
				// Im Zuge der Archivierung muss geprüft werden, ob es unterhalb der angegebenen Register noch weitere Unterregister gibt. Ist das der Fall, müssen diese vom Anwender ausgewählt werden;
				// d.h. eine Archivierung wird dann abgelehnt.  ENDE
				//////////////////////////////////////
				
				
				
				
				
				
				
			case "AJAOB":
			case "ALBRE":
			case "AJAAB":
			case "ABERO":
			case "ABERA":
			case "ASTOR":
			case "ASTRA":
			case "ABEPA":
			case "ABEOR":
			case "AFIOR":
			case "AFIRA":
			case "ALBOR":
			case "ALBSO":
			case "AAURR":
			case "AKROR":
			case "DUMMY":
			case "AOREG":
			case "AREGS":
				
				//////////////////////////////////////////////////////
				// Grundstücksangabe muss ein Pflichtfeld sein, wenn eine 04.01 Grundstück-Akte ausgewählt wurde START
				//////////////////////////////////////////////////////
				
				
				// Diese Logik ist aufgrund einer E-Mail von Hrn. Meyer vom 11. Februar 2022 13:58 Uhr an JFEL, ISTRE und CBUE deaktiviert.
				
				if ( false ) // Logik ist deaktiviert
				{
					// Gilt für Daueraktendokumente, Daueraktenunterregister und 2. Daueraktenunterregister
					// Bedingungen:
					// o DDF 4 (Register) wurde angegeben
					// o DDF 30 ist leer => ein Grundstück wurde nicht angegeben
					// o DDF 23 ist gefüllt => es wurde ein Unterregister angegeben
					// o Dokumentart ist DDAUE oder AUREG oder AURG2
					if ( ( doc.field[ 4 ] ) && ( ! doc.field[ 30 ] ) && ( doc.field[ 23 ] ) && ( ( docTypeShort.id == "DDAUE" ) || ( docTypeShort.id == "AUREG" ) || ( docTypeShort.id == "AURG2" ) ) )
					{
						def grundstueck_korrekter_ordner = false;
						def grundstueck_ordner = doc.field[ 23 ].substring( 0, 8 );
						
						switch ( grundstueck_ordner )
						{
							case "04.01.01":
							case "04.01.02":
							case "04.01.03":
							case "04.01.04":
								grundstueck_korrekter_ordner = true;
						}
						
						
						if ( ( grundstueck_korrekter_ordner ) && ( doc.field[ 4 ].substring( 0, 13 ) == "04.01 Grundst" ) )
						{
							return -505;
						}
					}
				}
				
				//////////////////////////////////////////////////////
				// Grundstücksangabe muss ein Pflichtfeld sein, wenn eine 04.01 Grundstück-Akte ausgewählt wurde ENDE
				//////////////////////////////////////////////////////
				
				
				
				
				
				
				
			case "AUREG":
			case "AURG2":
			case "AURG3":
			
			case "AAURU":
			case "AAUR2":
			
			case "ABEUR":
			case "ABEU2":
			
			case "ABPUR":
			case "ABPU2":
			
			case "AFIUR":
			case "AFIU2":
			
			case "AJAUR":
			case "AJAU2":
			
			case "ALJUR":
			case "ALOUR":
			case "ALJR2":
			case "ALBU2":
			
			case "ASTU2":
			case "ASTUR":
			
				
				
				////////////////////////////////////////////////////////
				// Es muss geprüft werden, ob eine gewählte Registerkombination valide ist, d.h. für einen Mandanten so existiert. Dabei muss unterschieden werden, ob die Akte gerade angelegt werden soll oder ein
				// Dokument innerhalb der Akte abgelegt werden soll. START
				////////////////////////////////////////////////////////
				
				def doktyp_art		= docTypeShort.id.substring( 0, 1 );
				
				
				
				
				
				
				if ( doktyp_art == "D" )
				{
					// Es soll ein Dokument abgelegt werden
					// Hier müssen alle angegebenen Register existieren
					
					
					// Festlegen, in welcher Aktenart gesucht werden soll:
					//def oreg, reg, ureg, ureg2, ureg3;
					
					where_allg	= " dok_dat_feld_10 = '" + doc.field[ 10 ] + "' ";
					
					switch( docTypeShort.id )
					{
						case "DDAUE":
							oreg	= "AOREG";
							reg		= "AREGS";
							ureg	= "AUREG";
							ureg2	= "AURG2";
							ureg3	= "AURG3";
							break;
						case "DABSC":
							oreg	= "AJAOB";
							reg		= "AJAAB";
							ureg	= "AJAUR";
							ureg2	= "AJAU2";
							break;
						case "DBERA":
							oreg	= "ABERO";
							reg		= "ABERA";
							ureg	= "ABEUR";
							ureg2	= "ABEU2";
							break;
						case "DSTEU":
							oreg	= "ASTOR";
							reg		= "ASTRA";
							ureg	= "ASTUR";
							ureg2	= "ASTU2";
							break;
						case "DBETR":
							oreg	= "ABEOR";
							reg		= "ABEPA";
							ureg	= "ABPUR";
							ureg2	= "ABPU2";
							break;
						case "DFIBU":
							oreg	= "AFIOR";
							reg		= "AFIRA";
							ureg	= "AFIUR";
							ureg2	= "AFIU2";
							break;
						case "DLOHN":
							oreg	= "ALBOR";
							reg		= "ALBRE";
							ureg	= "ALJUR";
							ureg2	= "ALJR2";
							break;
						case "DDEBD":
							oreg	= "AAURR";
							reg		= "AAURA";
							ureg	= "AAURU";
							ureg2	= "AAUR2";
							break;
						case "DLSTD":
							oreg	= "ALBSO";
							reg		= "ALORE";
							ureg	= "ALOUR";
							ureg2	= "ALBU2";
							break;
						case "DKRED":
							oreg	= "AKROR";
							reg		= "AKRER";
							ureg	= "AKREU";
							ureg2	= "AKRU2";
							where_allg = " dok_dat_feld_19 = '"+ doc.field[ 19 ] + "' ";
							break;
					}
					
					
					
					where = "";
					
					if ( doc.field[ 3 ] )  // Oberregister
					{
						where			= " and " + where_allg + " and dok_dat_feld_3 = '" + doc.field[ 3 ] + "' ";
						such_doku_art	= oreg;
						
						if ( doc.field[ 4 ] )  // Register
						{
							where			= where + " and dok_dat_feld_4 = '" + doc.field[ 4 ] + "' ";
							such_doku_art	= reg;
							
							if ( doc.field[ 23 ] )  // Unterregister
							{
								where			= where + "  and dok_dat_feld_23 = '" + doc.field[ 23 ] + "'  ";
								such_doku_art	= ureg;
								
								if ( doc.field[ 17 ] )  // 2. Unterregister
								{
									where			= where + " and dok_dat_feld_17 = '" + doc.field[ 17 ] + "'  ";
									such_doku_art	= ureg2;
									
									if ( doc.field[ 32 ] )  // 3. Unterregister
									{
										where			= where + " and dok_dat_feld_32 = '" + doc.field[ 32 ] + "' ";
										such_doku_art	= ureg3;
									}
								}
							}
						}
					}
					
					
				
					sqlQuery = "select count(*) anzahl from firmen_spezifisch where kue_dokuart = '" + such_doku_art + "' " + where;
					
					//d3.log.error( sqlQuery );
					
					resultRows = d3.sql.executeAndGet( (String) sqlQuery );
					
					if ( resultRows.size() > 0 )
					{
						if ( resultRows[ 0 ].anzahl == 0 )
						{
							d3.log.error( "Es konnte keine passende Registerkombination gefunden werden. Der Import wird abgelehnt." )
							
							return -501;
						}
					}
					
					
				}
				else
				{
					
					
					
					// Es soll eine Akte angelegt werden
					// Hier müssen alle bis auf das unterste Register existieren
					
					// Welche Register müssen vorhanden sein? (_mds => müssen da sein).
					// Oberregister werden nicht geprüft, weil sie immer da sein müssen.
					
					def reg_mds, ureg_mds, ureg2_mds;
					
					def pruefe_register = true;
					
					switch ( docTypeShort.id )
					{
						case "AOREG":	// Mandantenakte + Ebene Oberregister: müssen nicht geprüft werden
						case "AJAOB":
						case "ABERO":
						case "ASTOR":
						case "ABEOR":
						case "AFIOR":
						case "ALBOR":
						case "AAURR":
						case "ALBSO":
						case "AKROR":
						case "AMAND":
							pruefe_register = false;
							break;
						case "AURG3":	// Ebene Unterregister 3 (nur Dauerakte)
							reg_mds			= true;
							ureg_mds		= true;
							ureg2_mds		= true;
							such_doku_art	= "AURG2";
							break;
						case "AURG2":	// Ebene Unterregister 2
							reg_mds			= true;
							ureg_mds	   	= true;
							ureg2_mds		= false;
							such_doku_art	= "AUREG";
							break;
						case "AJAU2":
							reg_mds			= true;
							ureg_mds		   = true;
							ureg2_mds		= false;
							such_doku_art	= "AJAUR";
							break;
						case "ABEU2":
							reg_mds			= true;
							ureg_mds	   	= true;
							ureg2_mds		= false;
							such_doku_art	= "ABEUR";
							break;
						case "ASTU2":
							reg_mds			= true;
							ureg_mds		   = true;
							ureg2_mds		= false;
							such_doku_art	= "ASTUR";
							break;
						case "ABPU2":
							reg_mds			= true;
							ureg_mds	   	= true;
							ureg2_mds		= false;
							such_doku_art	= "ABPUR";
							break;
						case "AFIU2":
							reg_mds			= true;
							ureg_mds	   	= true;
							ureg2_mds		= false;
							such_doku_art	= "AFIUR";
							break;
						case "ALJR2":
							reg_mds			= true;
							ureg_mds		   = true;
							ureg2_mds  		= false;
							such_doku_art	= "ALJUR";
							break;
						case "AAUR2":
							reg_mds			= true;
							ureg_mds	   	= true;
							ureg2_mds		= false;
							such_doku_art	= "AAURU";
							break;
						case "ALBU2":
							reg_mds			= true;
							ureg_mds	   	= true;
							ureg2_mds		= false;
							such_doku_art	= "ALOUR";
							break;
						case "AKRU2":
							reg_mds			= true;
							ureg_mds	   	= true;
							ureg2_mds		= false;
							such_doku_art	= "AKREU";
							break;
						case "AUREG":	// Ebene Unterregister
							reg_mds			= true;
							ureg_mds	   	= false;
							ureg2_mds		= false;
							such_doku_art	= "AREGS";
							break;
						case "AJAUR":
							reg_mds			= true;
							ureg_mds	   	= false;
							ureg2_mds		= false;
							such_doku_art	= "AJAAB";
							break;
						case "ABEUR":
							reg_mds			= true;
							ureg_mds	   	= false;
							ureg2_mds		= false;
							such_doku_art	= "ABERA";
							break;
						case "ASTUR":
							reg_mds			= true;
							ureg_mds	   	= false;
							ureg2_mds		= false;
							such_doku_art	= "ASTRA";
							break;
						case "ABPUR":
							reg_mds			= true;
							ureg_mds	   	= false;
							ureg2_mds		= false;
							such_doku_art	= "ABEPA";
							break;
						case "AFIUR":
							reg_mds			= true;
							ureg_mds	   	= false;
							ureg2_mds		= false;
							such_doku_art	= "AFIRA";
							break;
						case "ALJUR":
							reg_mds			= true;
							ureg_mds	   	= false;
							ureg2_mds		= false;
							such_doku_art	= "ALBRE";
							break;
						case "AAURU":
							reg_mds			= true;
							ureg_mds	   	= false;
							ureg2_mds		= false;
							such_doku_art	= "AAURA";
							break;
						case "ALOUR":
							reg_mds			= true;
							ureg_mds	   	= false;
							ureg2_mds		= false;
							such_doku_art	= "ALORE";
							break;
						case "AKREU":
							reg_mds			= true;
							ureg_mds	   	= false;
							ureg2_mds		= false;
							such_doku_art	= "AKRER";
							break;
						case "AREGS":	// Ebene Register
							reg_mds			= false;
							ureg_mds	   	= false;
							ureg2_mds		= false;
							such_doku_art	= "AOREG";
							break;
						case "AJAAB":
							reg_mds			= false;
							ureg_mds		   = false;
							ureg2_mds		= false;
							such_doku_art	= "AJAOB";
							break;
						case "ABERA":
							reg_mds			= false;
							ureg_mds	   	= false;
							ureg2_mds		= false;
							such_doku_art	= "ABERO";
							break;
						case "ASTRA":
							reg_mds			= false;
							ureg_mds	   	= false;
							ureg2_mds		= false;
							such_doku_art	= "ASTOR";
							break;
						case "ABEPA":
							reg_mds			= false;
							ureg_mds	   	= false;
							ureg2_mds		= false;
							such_doku_art	= "ABEOR";
							break;
						case "AFIRA":
							reg_mds			= false;
							ureg_mds	   	= false;
							ureg2_mds		= false;
							such_doku_art	= "AFIOR";
							break;
						case "ALBRE":
							reg_mds			= false;
							ureg_mds	   	= false;
							ureg2_mds		= false;
							such_doku_art	= "ALBOR";
							break;
						case "AAURA":
							reg_mds			= false;
							ureg_mds	   	= false;
							ureg2_mds		= false;
							such_doku_art	= "AAURR";
							break;
						case "ALORE":
							reg_mds			= false;
							ureg_mds	   	= false;
							ureg2_mds		= false;
							such_doku_art	= "ALBSO";
							break;
						case "AKRER":
							reg_mds			= false;
							ureg_mds	   	= false;
							ureg2_mds		= false;
							such_doku_art	= "AKROR";
							break;
						
					}
					
					
					
					
					
					where = where_allg + " and dok_dat_feld_3 = '" + doc.field[ 3 ] + "' ";
					
					if ( reg_mds )
					{
						where = where + " and dok_dat_feld_4 = '" + doc.field[ 4 ] + "' ";
					}
					
					if ( ureg_mds )
					{
						where = where + " and dok_dat_feld_23 = '" + doc.field[ 23 ] + "' ";
					}
					
					if ( ureg2_mds )
					{
						where = where + " and dok_dat_feld_17 = '" + doc.field[ 17 ] + "' ";
					}

					if ( pruefe_register )
					{
						
						sqlQuery = "select count(*) anzahl from firmen_spezifisch where kue_dokuart = '" + such_doku_art + "' and " + where;
						
						//d3.log.error( "sqlQuery: 1 " + sqlQuery );
						
						
						resultRows = d3.sql.executeAndGet( (String) sqlQuery );
						
						if ( resultRows.size() > 0 )
						{
							if ( resultRows[ 0 ].anzahl == 0 )
							{
								d3.log.error( "Es konnte keine passende Registerkombination gefunden werden. Der Import wird abgelehnt." )
								
								return -501;
							}
						}
					}
				}
				
				
				////////////////////////////////////////////////////////
				// Es muss geprüft werden, ob eine gewählte Registerkombination valide ist, d.h. für einen Mandanten so existiert. Dabei muss unterschieden werden, ob die Akte gerade angelegt werden soll oder ein
				// Dokument innerhalb der Akte abgelegt werden soll. ENDE
				////////////////////////////////////////////////////////
				
				
				
				
				
				
			case "ADAUR":
			case "ABERB":
			case "ABETR":
			case "AFIBA":
			case "AJAAA":
			case "AKRED":
			case "ALOJA":
			case "ALBSA":
			case "ASTEU":
				
				// Prüfe, ob Aktennummer und Mandant zusammenpassen, ggf. Meldung
				if ( ( doc.field[ 1 ] ) && ( doc.field[ 10 ] ) )
				{
					// Aktennummer und Mandantnummer sind beide gefüllt
					
					if ( doc.field[ 1 ] != doc.field[ 10 ].substring( 0, 5 ) )
					{
						// Aktennummer passt nicht zur Mandantennummer
						d3.log.error( "Die angegebene Aktennummer passt nicht zur angegeben Mandantennummer. Der Import wird abgelehnt." )
						return -503;
					}
					
				}
				
				
				
				
				
				
				
				///////////////////////
				// Aktenkürzel-Buchstabenanteil groß schreiben:
				if ( doc.field[ 10 ] )
				{
					doc.field[ 10 ] = doc.field[ 10 ].toUpperCase();
				}
				
				
				///////////////////////
				// Prüfe, ob Aktennummer zu ausgewählter Dokumentart passt START
				///////////////////////
				
				if ( doc.field[ 10 ] )
				{
					def aktenkuerzel = "";
					def lzahlen = "0123456789";
					
					for ( int m = 0; m <= doc.field[ 10 ].length() -1 ; m++ )
					{
						if ( lzahlen.indexOf( doc.field[ 10 ].substring( m, m + 1 ) ) == -1 )
						{
							aktenkuerzel = aktenkuerzel + doc.field[ 10 ].substring( m, m + 1 );
						}
					}
					
					d3.log.info( "Dokument-/Aktenart " + docTypeShort.id + " / gefundenes Aktenkuerzel " + aktenkuerzel );
					
					// RC -507: Es wurde versucht, ein Dokument mit einer Aktennummer in eine für diese Aktennummer nicht passende Dokumentart zu importieren.
					
					
				
				
					
					switch( docTypeShort.id )
					{
						case "DDAUE":				// Dauerakte
						case "AOREG":
						case "AREGS":
						case "AUREG":
						case "AURG2":
						case "AURG3":
							if ( aktenkuerzel != "DA" )
							{
								return -507;
							}
							break;
						case "DABSC":				// Jahresabschlussakte
						case "AJAOB":
						case "AJAAB":
						case "AJAUR":
						case "AJAU2":
							if ( aktenkuerzel != "JA" )
							{
								return -507;
							}
							break;
						case "DBERA":				// Beratungsakte
						case "ABERO":
						case "ABERA":
						case "ABEUR":
						case "ABEU2":
							if ( aktenkuerzel != "BE" )
							{
								return -507;
							}
							break;
						case "DSTEU":				// Steuerakte
						case "ASTOR":
						case "ASTRA":
						case "ASTUR":
						case "ASTU2":
							if ( aktenkuerzel != "ST" )
							{
								return -507;
							}
							break;
						case "DBETR":				// Betriebspruefungsakte
						case "ABEOR":
						case "ABEPA":
						case "ABPUR":
						case "ABPU2":
							if ( aktenkuerzel != "BP" )
							{
								return -507;
							}
							break;
						case "DFIBU":				// Finanzbuchhaltungsakte
						case "AFIOR":
						case "AFIRA":
						case "AFIUR":
						case "AFIU2":
							if ( aktenkuerzel != "FI" )
							{
								return -507;
							}
							break;
						case "DLOHN":				// Lohnbuchhaltungjahresakte
						case "ALBOR":
						case "ALBRE":
						case "ALJUR":
						case "ALJR2":
							if ( aktenkuerzel != "LO" )
							{
								return -507;
							}
							break;
						case "DDEBD":				// Ausgangsrechnungsakte
						case "AAURR":
						case "AAURA":
						case "AAURU":
						case "AAUR2":
							if ( aktenkuerzel != "RE" )
							{
								return -507;
							}
							break;
						case "DLSTD":				// Lohnbuchhaltungsstammdatenakte
						case "ALBSO":
						case "ALORE":
						case "ALOUR":
						case "ALBU2":
							if ( aktenkuerzel != "LS" )
							{
								return -507;
							}
							break;
						case "DKRED":				// Kreditorenakte
						case "AKROR":
						case "AKRER":
						case "AKREU":
						case "AKRU2":
							if ( aktenkuerzel != "KA" )
							{
								return -507;
							}
							break;
					}
					
					
				}
				
				///////////////////////
				// Prüfe, ob Aktennummer zu ausgewählter Dokumentart passt ENDE
				///////////////////////
				
				
				
				
				
				///////////////////////
				// Mandantinformationen ergänzen START
				///////////////////////
				
				if ( doc.field[ 1 ] )
				{
					def sql = groovy.sql.Sql.newInstance( "jdbc:sqlserver://kp-sql01\\D3;databaseName=D3P_Datev", 'd3_master', 'Xbn8"Ep4', 'com.microsoft.sqlserver.jdbc.SQLServerDriver' );
					
					def row = sql.firstRow( "select clientname, number from DatevClients where number = '" + doc.field[ 1 ] + "'" );
					
					if ( row )
					{
						doc.field[  1 ] = (String) row.number;
						doc.field[  2 ] = row.clientname;
						//doc.field[ 13 ] = (String) row.number;
					}
					
					sql.close();
				}
				
				
				///////////////////////
				// Mandantinformationen ergänzen ENDE
				///////////////////////
				
				
				
				
				
				///////////////////////
				// Setzen des Feldes Briefkopf, falls noch nicht gefüllt START
				///////////////////////
				
				if ( ! doc.field[ 42 ] )
				{
					doc.field[ 42 ] = "Kleeberg";
				}
				
				///////////////////////
				// Setzen des Feldes Briefkopf, falls noch nicht gefüllt ENDE
				///////////////////////
				
				
				
				
				
				
				
				//////////////////////////////////////////////////////
				// automatisches Vergeben einer Aktennummer, ggf. Füllen des Aktennamens START
				//////////////////////////////////////////////////////
				
				
				
				
				
				
				def akten_kuerzel;
				def akten_name;
				def akten_verfahren;
				
				switch ( docTypeShort.id )
				{
					case "ADAUR": // Dauerakte
					case "DDAUE": // Daueraktendokumente
					case "AOREG": // Oberregister
					case "AREGS": // Register
					case "AUREG": // Unterregister
					case "AURG2": // 2. Unterregister
						akten_kuerzel	= "DA";
						akten_name		= "Dauerakte";
						akten_verfahren	= 1;
						break;
						
					case "AAURE": // Ausgangsrechnungsakte
					case "DDEBD": // Debitorendokumente
					case "AAURR": // Ausgangsrechnungsregister
						akten_kuerzel	= "RE";
						akten_name		= "Ausgangsrechnungsakte";
						akten_verfahren	= 1;
						break;
					case "ABERA":
					case "DBERA":
					case "ABERO":
					case "ABERB":
						akten_kuerzel	= "BE";
						akten_name		= "Beratungsakte";
						akten_verfahren	= 1;
						break;
					case "DSTEU":
					case "ASTEU":
					case "ASTRA":
					case "ASTOR":
						akten_kuerzel	= "ST";
						akten_name		= "Steuerakte";
						akten_verfahren	= 2;
						break;
					case "DBETR":
					case "ABETR":
					case "ABEPA":
					case "ABEOR":
						akten_kuerzel	= "BP";
						akten_name		= "Betriebspruefungsakte";
						akten_verfahren	= 1;
						break;
					case "DFIBU":
					case "AFIBA":
					case "AFIOR":
					case "AFIRA":
						akten_kuerzel	= "FI";
						akten_name		= "Finanzbuchhaltungsakte";
						akten_verfahren	= 1;
						break;
					case "DLOHN":
					case "ALOJA":
					case "ALBOR":
					case "ALBRE":
						akten_kuerzel	= "LO";
						akten_name		= "Lohnbuchhaltungs-Jahresakte";
						akten_verfahren	= 2;
						break;
					case "DLSTD":
					case "ALBSO":
					case "ALBSA":
						akten_kuerzel	= "ST";
						akten_name		= "Steuerakte";
						akten_verfahren	= 1;
						break;
					case "DKRED":
					case "AKRED":
					case "ALBSA":
						akten_kuerzel	= "KR";
						akten_name		= "Kreditorakte";
						akten_verfahren	= 1;
						break;
				}

				if ( doc.field[ 10 ] )
				{
					// Aktennummer ist gefüllt
					if ( ! doc.field[ 21 ] )
					{
						// Es wurde kein Aktenname angegeben
						sqlQuery = "select dok_dat_feld_21 from firmen_spezifisch where dok_dat_feld_10 = '" + doc.field[10] + "' and kue_dokuart in ( 'ADAUR', 'ABERB', 'ABETR', 'AFIBA', 'AJAAA', 'AKRED', 'ALOJA', 'ALBSA', 'ASTEU' )";
						
						resultRows = d3.sql.executeAndGet( (String) sqlQuery );
						
						if ( resultRows.size() > 0 )
						{
							doc.field[ 21 ] = resultRows[ 0 ].dok_dat_feld_21;
						}
						else
						{
							doc.field[ 21 ] = akten_name;
						}
					}
				}
				else
				{
					
					// Aktennummer ist leer
					if ( akten_verfahren == 1 )
					{
						// Aktennummer: <Mandant-Nr 5St.><Aktenkürzel 2St.><Aktensuffixnummer 4St.><Unteraktennummer 2St.>
						
						// Mit diesem Verfahren wird bei leerer Aktennummer nach Akten dieses Typs gesucht. Die höchste gefundene Aktensuffixnummer wird dann um 1 inkrementiert und als
						// Grundlage für die neue Aktennummer verwendet.
						
						if ( docTypeShort.id.substring( 0,1 ) == "A" )
						{
							// Bei Aktenanlage wird die Aktennummer generiert, falls nicht angegeben.
							
							sqlQuery = "select distinct dok_dat_feld_10 from firmen_spezifisch where kue_dokuart in ( \
							'ADAUR', 'AAURE', 'ABERB', 'ABETR', 'AFIBA', 'AJAAA', 'AKRED', 'ALOJA', 'ALBSA', 'ASTEU', 'DBERA', 'DDAUE', 'DBETR', 'DDEBD', 'DFIBU', 'DABSC', 'DKRED', 'DLOHN', 'DLSTD', 'DSTEU' \
							) and dok_dat_feld_10 like '" + doc.field[ 1 ] + akten_kuerzel + "%' order by dok_dat_feld_10 desc"
							
							resultRows = d3.sql.executeAndGet( sqlQuery );
							
							if ( resultRows.size() > 0 )
							{
								//12345DA000100
								def akten_suffix = resultRows[ 0 ].dok_dat_feld_10;
								
							
								// Transformieren des DB-Treffers in die Ziel-Aktennummer
								akten_suffix	= akten_suffix.substring( 7, 11 );	// Ausschneiden der Aktensuffixnummer
								int akt_suff	= akten_suffix as Integer;			// Typkonvertierung nach Integer
								akt_suff		= akt_suff + 1;						// +1 weil neue Akte/Dokument
								akten_suffix	= akt_suff.toString();				// Typkonvertierung zurück nach String
								akten_suffix	= akten_suffix.padLeft( 4, "0" );	// Hinzufügen von Nullen bis zu einer Gesamtlänge von 4 Stellen
								
				
								// Setzen der neuen Aktennummer + des Aktennamens
								doc.field[ 10 ] = doc.field[ 1 ] + akten_kuerzel + akten_suffix + "00";
								doc.field[ 21 ] = akten_name;
								
				
								
								
							}
							else
							{
								// Es wurde keine passende Akte/Dokument gefunden:
								doc.field[ 10 ] = doc.field[ 1 ] + akten_kuerzel + "0000" + "00";
								doc.field[ 21 ] = akten_name;
							}
						}
						else
						{
							// Bei Dokumentarten wird eine Aktennummer gesucht und bei Erfolg als erste vorgeschlagen
							sqlQuery = "select distinct dok_dat_feld_10, dok_dat_feld_21 from firmen_spezifisch where kue_dokuart in ( \
							'ADAUR', 'AAURE', 'ABERB', 'ABETR', 'AFIBA', 'AJAAA', 'AKRED', 'ALOJA', 'ALBSA', 'ASTEU', 'DBERA', 'DDAUE', 'DBETR', 'DDEBD', 'DFIBU', 'DABSC', 'DKRED', 'DLOHN', 'DLSTD', 'DSTEU' \
							) and dok_dat_feld_10 like '" + doc.field[ 1 ] + akten_kuerzel + "%' order by dok_dat_feld_10 desc"
							
							resultRows = d3.sql.executeAndGet( sqlQuery );
							
							if ( resultRows.size() > 0 )
							{
								doc.field[ 10 ] = resultRows[ 0 ].dok_dat_feld_10;
								doc.field[ 21 ] = resultRows[ 0 ].dok_dat_feld_21;
							}
							else
							{
								// Der Benutzer muss zuerst die entsprechende Akte erstellen (siehe msglib.usr)
								return -506;
							}
						}
					}
					else
					{
						// Aktuell haben die Unterstrukturen der Kreditorakte keine Aktennummer, daher werden diese hier nochmal explizit ausgenommen
						if ( "AKROR".equals( docTypeShort.id ) || "AKRER".equals( docTypeShort.id ) || "AKREU".equals( docTypeShort.id ) )
						{
							d3.log.info( "keine Aktennummer bei Kreditorstrukturakten vorhanden" );
						}
						else
						{
							// Jahresakten haben ein etwas anderes Schema
							def jahr = new Date().getYear().toInteger() + 1900;
							def akten_suffix = jahr.toString();
							// Setzen der neuen Aktennummer + des Aktennamens
							doc.field[ 10 ] = doc.field[ 1 ] + akten_kuerzel + akten_suffix + "00";
							doc.field[ 21 ] = akten_name;
							
						}
					}
				}
				
				
				
				//////////////////////////////////////////////////////
				// automatisches Vergeben einer Aktennummer, ggf. Füllen des Aktennamens ENDE
				//////////////////////////////////////////////////////
		}

		
		
				
				
		
		//////////////////////////////////////////////////////
		// Verarbeitung Mandantenakte ENDE
		//////////////////////////////////////////////////////
		
		
		
		
		
		
		
		
		return 0;
    }
   
   
	@Entrypoint( entrypoint = "hook_insert_exit_20" )
	public int insertExit_20( D3Interface d3, Document doc, String fileDestination, int importOk, User user, DocumentType docTypeShort )
	{
		
		//////////////////////////////////////////////////////
		// Erstellen des Aktenbaums bei Anlage einer Mandantenakte START
		//////////////////////////////////////////////////////
		
		
		
		if ( docTypeShort.id == "AMAND" )
		{
			
			//xlog( d3, 4, "1 *********************************************************" );
			//xlog( d3, 4, "insertExit_20: " + docTypeShort.id + " / " + doc.id + " START " );
			//xlog( d3, 4, "Mandatenakte " + doc.id + " / " + doc.field[ 1 ] + " / " + doc.field[ 2 ] );
			//xlog( d3, 4, "1 *********************************************************" );
			
			//////////////////////////////////////////
			// erste Ebene unterhalb der neuen Mandantenakte anlegen
			// (Dauerakte, Ausgangsrechnungsakte sowie alle Sammelakten)
			def akten_ebene_1 = [ "ADAUR", "ALOSA", "ASTSA", "AJASA", "AFBSA", "ABPSA", "ABESA", "AAURE" ];
			
			
			// Daueraktennummer, -name
			def daueraktennr   = doc.field[ 1 ] + "DA000000";
			def daueraktenname = "Dauerakte";
			
			def ausgangsrechaktennr   = doc.field[ 1 ] + "RE000100";
			def ausgangsrechaktenname = "Ausgangsrechnungsakte";
			
			def splitted_str_array_69 = [];
			
			
			akten_ebene_1.each
			{
				
				
				
				
				xlog( d3, 4, "-----------------------" );
				xlog( d3, 4, "Mandatenakte " + doc.id + " / " + doc.field[ 1 ] + " : erstelle Akte vom Typ " + it );
				//d3.log.info( " erstelle Akte vom Typ " + it );
				def zieltabelle;
				def resultRows;
				def akte_aus_migration = false;
				def check_db = false;
				
				
				Document newDoc = d3.archive.newDocument();
				
				newDoc.type = it;
				
				newDoc.status = Document.DocStatus.DOC_STAT_PROCESSING;
				newDoc.editor = "dvelop";
				
				// Mandantnummer, -name, -gruppennummer, physischer Aufbewahrungsort, Geschäftsführer
				newDoc.field[  1 ] = doc.field[  1 ];
				newDoc.field[  2 ] = doc.field[  2 ];
				newDoc.field[ 13 ] = doc.field[ 13 ];
				newDoc.field[ 22 ] = "Digital";
				newDoc.field[ 25 ] = doc.field[ 25 ];	// Geschäftsführer
				newDoc.field[ 37 ] = doc.field[ 37 ];	// Mandatsverantwortlicher
				newDoc.field[ 42 ] = "Kleeberg";
				
				switch ( it )
				{
					case "ADAUR":
						zieltabelle = "mig_dauerakte";
						
						xlog( d3, 4, "Mandatenakte " + doc.id + " / " + doc.field[ 1 ] + " : erstelle Dauerakte mit GF " + doc.field[ 25 ] );
						xlog( d3, 4, "Mandatenakte " + doc.id + " / " + doc.field[ 1 ] + " : erstelle Dauerakte mit MV " + doc.field[ 37 ] );
						
						newDoc.field[ 10 ] = daueraktennr;
						newDoc.field[ 21 ] = daueraktenname;
						newDoc.field[ 60 ][ 1 ] = doc.field[ 25 ];
						if ( doc.field[ 25 ] != doc.field[ 37 ] )
						{
							newDoc.field[ 60 ][ 2 ] = doc.field[ 37 ];
						}
						
						check_db = true;
						
						break;
						
					case "AAURE":
						zieltabelle = "mig_ausgangsrechnungsakte";
						
						xlog( d3, 4, "Mandatenakte " + doc.id + " / " + doc.field[ 1 ] + " : erstelle AR-Akte mit GF " + doc.field[ 25 ] );
						xlog( d3, 4, "Mandatenakte " + doc.id + " / " + doc.field[ 1 ] + " : erstelle AR-Akte mit MV " + doc.field[ 37 ] );
						
						newDoc.field[ 10 ] = ausgangsrechaktennr;
						newDoc.field[ 21 ] = ausgangsrechaktenname;
						newDoc.field[ 60 ][ 1 ] = doc.field[ 25 ];
						if ( doc.field[ 25 ] != doc.field[ 37 ] )
						{
							newDoc.field[ 60 ][ 2 ] = doc.field[ 37 ];
						}
						
						check_db = true;
						
						break;
						
					default:
						check_db = false;
						break;
				}
				
				
				
				if ( check_db )
				{
					def sqlQuery = "select id,ddf1,ddf48,ddf10,ddf21,ddf22,ddf25,ddf37,ddf42,ddf60,ddf69 from " + zieltabelle + " where ddf1 = '" + doc.field[ 1 ] + "' and fehler is null and doku_id is null";
					
					resultRows = d3.sql.executeAndGet( (String) sqlQuery );
					
					if ( resultRows.size() > 0 )
					{
						akte_aus_migration = true;
					
						xlog( d3, 4, "Mandatenakte " + doc.id + ": Datensatz fuer Dauerakte gefunden." );
						// Falls ein Wert in der Tabelle gefunden wurde, überschreibt der in der Tabelle gefundene Wert den "geerbten" von der Mandantenakte:
						// Daueraktennummer:
						if ( resultRows[ 0 ].ddf10 )
						{
							//xlog( d3, 4, "Mandatenakte " + doc.id + ": Setze DDF10: " + resultRows[ 0 ].ddf10 );
							newDoc.field[ 10 ] = resultRows[ 0 ].ddf10;
						}
						
						// Daueraktenname:
						if ( resultRows[ 0 ].ddf21 )
						{
							//xlog( d3, 4, "Mandatenakte " + doc.id + ": Setze DDF21: " + resultRows[ 0 ].ddf21 );
							newDoc.field[ 21 ] = resultRows[ 0 ].ddf21;
						}
						
						// Physischer Aufbewahrungsort:
						if ( resultRows[ 0 ].ddf22 )
						{
							//xlog( d3, 4, "Mandatenakte " + doc.id + ": Setze DDF22: " + resultRows[ 0 ].ddf22 );
							newDoc.field[ 22 ] = resultRows[ 0 ].ddf22;
						}
						
						// Geschäftsführer:
						if ( resultRows[ 0 ].ddf25 )
						{
							//xlog( d3, 4, "Mandatenakte " + doc.id + ": Setze DDF25: " + resultRows[ 0 ].ddf25 );
							newDoc.field[ 25 ] = resultRows[ 0 ].ddf25;
							newDoc.field[ 60 ][ 1 ] = doc.field[ 25 ];
						}
						
						// Mandatsverantwortlicher:
						if ( resultRows[ 0 ].ddf37 )
						{
							//xlog( d3, 4, "Mandatenakte " + doc.id + ": Setze DDF37: " + resultRows[ 0 ].ddf37 );
							newDoc.field[ 37 ] = resultRows[ 0 ].ddf37;
							newDoc.field[ 60 ][ 2 ] = doc.field[ 37 ];
						}
						
						// Briefkopf:
						if ( resultRows[ 0 ].ddf42 )
						{
							//xlog( d3, 4, "Mandatenakte " + doc.id + ": Setze DDF42: " + resultRows[ 0 ].ddf42 );
							newDoc.field[ 42 ] = resultRows[ 0 ].ddf42;
						}
						
						// Unique-ID:
						if ( resultRows[ 0 ].ddf48 )
						{
							//xlog( d3, 4, "Mandatenakte " + doc.id + ": Setze DDF48: " + resultRows[ 0 ].ddf48 );
							newDoc.field[ 48 ] = resultRows[ 0 ].ddf48;
						}
						
						// Postempfänger:
						if ( resultRows[ 0 ].ddf60 )
						{
							newDoc.field[ 60 ][ 1 ] = "";
							newDoc.field[ 60 ][ 2 ] = "";
							
							def splitted_str_array = resultRows[ 0 ].ddf60.split( ';' );
							for ( int i = 0; i < splitted_str_array.size(); i++ )
							{
								//xlog( d3, 4, "Mandatenakte " + doc.id + ": Setze DDF60 / " + i + ": " + splitted_str_array[ i ] );
								newDoc.field[ 60 ][ i + 1 ] = splitted_str_array[ i ];
							}
						}
						
						// Berechtigter:
						if ( resultRows[ 0 ].ddf69 )
						{
							splitted_str_array_69 = resultRows[ 0 ].ddf69.split( ';' );
							for ( int i = 0; i < splitted_str_array_69.length; i++ )
							{
								//xlog( d3, 4, "Mandatenakte " + doc.id + ": Setze DDF69 / " + i + ": " + splitted_str_array_69[ i ] );
								newDoc.field[ 69 ][ i + 1 ] = splitted_str_array_69[ i ];
							}
						}
					}
					else
					{
						xlog( d3, 3, "Mandatenakte " + doc.id + ": Es wurde kein DB-Treffer gefunden (Tabelle " + zieltabelle + ", Aktenart " + it + ")." );
					}
				}
				
				
				// Prüfen, ob die zu erstellende Akte existiert:
				
				def sqlQuery_pruef = "select doku_id from firmen_spezifisch where kue_dokuart = '" + newDoc.type + "' and dok_dat_feld_10 = '" + newDoc.field[ 10 ] + "'";
				
				def resultRows2 = d3.sql.executeAndGet( (String) sqlQuery_pruef );
					
				if ( resultRows2.size() == 0 )
				{
				
					try
					{
						newDoc = d3.archive.importDocument( newDoc );
					}
					catch ( D3Exception e )
					{
						xlog( d3, 2, "Dokument konnte nicht erzeugt werden: " + e.message );
						
						if ( akte_aus_migration )
						{
							def meldung_db;
							if ( e.message.length() > 250 )
							{
								meldung_db =  e.message.substring( 0, 249 );
							}
							else
							{
								meldung_db =  e.message;
							}
							def sqlQuery = "update " + zieltabelle + " set fehler = '" + meldung_db + "' where id = " + resultRows[ 0 ].id;
							d3.sql.execute( sqlQuery );
						}
						return -175;
					}
					
					if ( akte_aus_migration )
					{
						//xlog( d3, 2, "Angekommen?" );
						
						xlog( d3, 4, "Mandatenakte " + doc.id + ": Setze Doku-ID " + newDoc.id + " fuer Element-ID " + resultRows[ 0 ].id + " in der Tabelle " + zieltabelle + "." );
						def sqlQuery = "update " + zieltabelle + " set doku_id = '" + newDoc.id + "' where id = " + resultRows[ 0 ].id;
						d3.sql.execute( sqlQuery );
					}
					
					xlog( d3, 4, "Mandatenakte " + doc.id + ": erzeugte Doku-Id: " + newDoc.id + " / " + newDoc.type );
					
				}
				else
				{
					xlog( d3, 3, "Mandatenakte " + doc.id + ": Akte vom Typ " + newDoc.type + " existiert bereits: " + resultRows[ 0 ].doku_id );
				}
				
			}
			
			
			//////////////////////////////////////////
			// Ebene unterhalb der Dauerakte / Ausgangsrechnungsakte anlegen
			// Dokumentart: Daueraktenoberregister / Ausgangsrechnungsberregister, darin alle in den Stammdaten angelegten Oberregister
			
			def sqlQuery = "select distinct dok_dat_feld_2, dok_dat_feld_24 from firmen_spezifisch where kue_dokuart = 'AVMNT' and ( dok_dat_feld_1 = 'Dauerakte' or dok_dat_feld_1 = 'Ausgangsrechnungsakte' )";
			
			def resultRows = d3.sql.executeAndGet( (String) sqlQuery );
			
			if ( resultRows.size() > 0 )
			{
				resultRows.each
				{
					d3.log.info( " erstelle Oberregister-Akte: " + it.dok_dat_feld_24 + " / " + it.dok_dat_feld_2 );
					
					Document newDoc = d3.archive.newDocument();
					
					if ( it.dok_dat_feld_24 == "RE" )
					{
						newDoc.type = "AAURR";
						newDoc.field[ 10 ] = ausgangsrechaktennr;      // Daueraktennummer
						newDoc.field[ 21 ] = ausgangsrechaktenname;    // Daueraktenname
					}
					else
					{
						newDoc.type = "AOREG";
						newDoc.field[ 10 ] = daueraktennr;      // Daueraktennummer
						newDoc.field[ 21 ] = daueraktenname;    // Daueraktenname
					}
					
					newDoc.status = Document.DocStatus.DOC_STAT_PROCESSING;
					newDoc.editor = "dvelop";
					
					newDoc.field[  1 ] = doc.field[  1 ];   // Mandantnummer
					newDoc.field[  2 ] = doc.field[  2 ];   // Mandantname
					newDoc.field[ 13 ] = doc.field[ 13 ];   // Mandantgruppennummer
					newDoc.field[  3 ] = it.dok_dat_feld_2; // Oberregister
					newDoc.field[ 25 ] = doc.field[ 25 ];	// Geschäftsführer
					newDoc.field[ 37 ] = doc.field[ 37 ];	// Mandatsverantwortlicher
					
					if ( splitted_str_array_69.size() > 0 )
					{
						for ( int i = 0; i < splitted_str_array_69.size(); i++ )
						{
							//xlog( d3, 4, "Mandatenakte " + doc.id + " / OR " + newDoc.field[  3 ] + ":Setze DDF69 / " + i + ": " + splitted_str_array_69[ i ] );
							newDoc.field[ 69 ][ i + 1 ] = splitted_str_array_69[ i ];
						}
					}
					
					//def ergebnis = d3.archive.importDocument( newDoc );
					// Prüfen, ob die zu erstellende Akte existiert:
					
					def sqlQuery_pruef = "select doku_id from firmen_spezifisch where kue_dokuart = '" + newDoc.type + "' and dok_dat_feld_10 = '" + newDoc.field[ 10 ] + "' and dok_dat_feld_3 = '" + newDoc.field[  3 ] + "'";
					
					resultRows = d3.sql.executeAndGet( (String) sqlQuery_pruef );
						
					if ( resultRows.size() == 0 )
					{
					
						try
						{
							newDoc = d3.archive.importDocument( newDoc );
						}
						catch ( D3Exception e )
						{
							xlog( d3, 2, "Dokument konnte nicht erzeugt werden: " + e.message );
							
							return -175;
						}
						
						xlog( d3, 4, "Mandatenakte " + doc.id + ": Akte vom Typ " + newDoc.type + " / Register [" + newDoc.field[  3 ] + "]: erzeugte Doku-Id: " + newDoc.id );
						
					}
					else
					{
						xlog( d3, 3, "Mandatenakte " + doc.id + ": Akte vom Typ " + newDoc.type + " / Oberregister [" + newDoc.field[  3 ] + "] existiert bereits: " + resultRows[ 0 ].doku_id );
					}
				}
			}
			
			
			
			//////////////////////////////////////////
			// 2. Ebene unterhalb der Dauerakte anlegen
			// Dokumentart: Daueraktenregister, darin alle in den Stammdaten angelegten Register
			
			sqlQuery = "select distinct dok_dat_feld_2, dok_dat_feld_3 from firmen_spezifisch where kue_dokuart = 'AVMNT' and dok_dat_feld_1 = 'Dauerakte' and dok_dat_feld_3 != ''";
			
			resultRows = d3.sql.executeAndGet( (String) sqlQuery );
			
			if ( resultRows.size() > 0 )
			{
				resultRows.each
				{
					d3.log.info( " erstelle Daueraktenregister-Akte: " + it.dok_dat_feld_2 + " / " + it.dok_dat_feld_3 );
					
					Document newDoc = d3.archive.newDocument();
					
					newDoc.type = "AREGS";
					
					newDoc.status = Document.DocStatus.DOC_STAT_PROCESSING;
					newDoc.editor = "dvelop";
					
					newDoc.field[  1 ] = doc.field[  1 ];   // Mandantnummer
					newDoc.field[  2 ] = doc.field[  2 ];   // Mandantname
					newDoc.field[ 13 ] = doc.field[ 13 ];   // Mandantgruppennummer
					newDoc.field[ 10 ] = daueraktennr;      // Daueraktennummer
					newDoc.field[ 21 ] = daueraktenname;    // Daueraktenname
					newDoc.field[  3 ] = it.dok_dat_feld_2; // Oberregister
					newDoc.field[  4 ] = it.dok_dat_feld_3; // Register
					newDoc.field[ 25 ] = doc.field[ 25 ];	// Geschäftsführer
					newDoc.field[ 37 ] = doc.field[ 37 ];	// Mandatsverantwortlicher
					
					if ( splitted_str_array_69.size() > 0 )
					{
						for ( int i = 0; i < splitted_str_array_69.size(); i++ )
						{
							//xlog( d3, 4, "Mandatenakte " + doc.id + " / OR " + newDoc.field[ 4 ] + ":Setze DDF69 / " + i + ": " + splitted_str_array_69[ i ] );
							newDoc.field[ 69 ][ i + 1 ] = splitted_str_array_69[ i ];
						}
					}
					
					//def ergebnis = d3.archive.importDocument( newDoc );
					// Prüfen, ob die zu erstellende Akte existiert:
					
					def sqlQuery_pruef = "select doku_id from firmen_spezifisch where kue_dokuart = '" + newDoc.type + "' and dok_dat_feld_10 = '" + newDoc.field[ 10 ] + "' and dok_dat_feld_3 = '" + newDoc.field[  3 ] + "' and dok_dat_feld_4 = '" + newDoc.field[ 4 ] + "'";
					
					resultRows = d3.sql.executeAndGet( (String) sqlQuery_pruef );
						
					if ( resultRows.size() == 0 )
					{
					
						try
						{
							newDoc = d3.archive.importDocument( newDoc );
						}
						catch ( D3Exception e )
						{
							xlog( d3, 2, "Dokument konnte nicht erzeugt werden: " + e.message );
							
							return -175;
						}
						
						xlog( d3, 4, "Mandatenakte " + doc.id + ": Akte vom Typ " + newDoc.type + " / Register [" + newDoc.field[  3 ] + "][" + newDoc.field[ 4 ] + "]: erzeugte Doku-Id: " + newDoc.id );
						
					}
					else
					{
						xlog( d3, 3, "Mandatenakte " + doc.id + ": Akte vom Typ " + newDoc.type + " / Register [" + newDoc.field[  3 ] + "][" + newDoc.field[ 4 ] + "] existiert bereits: " + resultRows[ 0 ].doku_id );
					}
					
				}
			}
			
			
			//////////////////////////////////////////
			// 3. Ebene unterhalb der Dauerakte anlegen
			// Dokumentart: Daueraktenunterregister, darin alle in den Stammdaten angelegten Unterregister
			
			sqlQuery = "select distinct dok_dat_feld_2, dok_dat_feld_3, dok_dat_feld_4 from firmen_spezifisch where kue_dokuart = 'AVMNT' and dok_dat_feld_1 = 'Dauerakte' and dok_dat_feld_3 != '' and dok_dat_feld_4 != ''";
			
			resultRows = d3.sql.executeAndGet( (String) sqlQuery );
			
			if ( resultRows.size() > 0 )
			{
				resultRows.each
				{
					d3.log.info( " erstelle Daueraktenregister-Akte: " + it.dok_dat_feld_2 + " / " + it.dok_dat_feld_2 + " / " + it.dok_dat_feld_4 );
					
					Document newDoc = d3.archive.newDocument();
					
					newDoc.type = "AUREG";
					
					newDoc.status = Document.DocStatus.DOC_STAT_PROCESSING;
					newDoc.editor = "dvelop";
					
					newDoc.field[  1 ] = doc.field[  1 ];   // Mandantnummer
					newDoc.field[  2 ] = doc.field[  2 ];   // Mandantname
					newDoc.field[ 13 ] = doc.field[ 13 ];   // Mandantgruppennummer
					newDoc.field[ 10 ] = daueraktennr;      // Daueraktennummer
					newDoc.field[ 21 ] = daueraktenname;    // Daueraktenname
					newDoc.field[  3 ] = it.dok_dat_feld_2; // Oberregister
					newDoc.field[  4 ] = it.dok_dat_feld_3; // Register
					newDoc.field[ 23 ] = it.dok_dat_feld_4; // Unterregister
					newDoc.field[ 25 ] = doc.field[ 25 ];	// Geschäftsführer
					newDoc.field[ 37 ] = doc.field[ 37 ];	// Mandatsverantwortlicher
					
					if ( splitted_str_array_69.size() > 0 )
					{
						for ( int i = 0; i < splitted_str_array_69.size(); i++ )
						{
							//xlog( d3, 4, "Mandatenakte " + doc.id + " / UR " + newDoc.field[ 23 ] + ":Setze DDF69 / " + i + ": " + splitted_str_array_69[ i ] );
							newDoc.field[ 69 ][ i + 1 ] = splitted_str_array_69[ i ];
						}
					}
					
					def ergebnis = d3.archive.importDocument( newDoc );
					
				}
			}
			
			
			
		}
		
		
		
		//////////////////////////////////////////////////////
		// Erstellen des Aktenbaums bei Anlage einer Mandantenakte ENDE
		//////////////////////////////////////////////////////
		
		
		
		//////////////////////////////////////
		// Wenn ein Dokument in der Mandantenakte abgelegt wird (d.h. in die bekannten Dokumentarten importiert wird), sollen die "Postempfänger", d.h. die Personen, die im entsprechenden Eigenschaftsfeld der zugehörigen
		// Akte (Dauerakte, Beratungsakte, ...) hinterlegt sind, eine Benachrichtigung in ihren Postkorb (Kachel "Aufgaben") bekommen. START
		//////////////////////////////////////
		
		
		if ( true )
		{
		switch ( docTypeShort.id )
		{
			case "DDAUE":
			case "DABSC":
			case "DBERA":
			case "DSTEU":
			case "DBETR":
			case "DFIBU":
			case "DLOHN":
			case "DDEBD":
			case "DLSTD":
			case "DKRED": 
					
					// Die Benachrichtigung soll nur erfolgen, wenn im Feld "Benachrichtigung Postempfänger" (DDF 38) der Wert "Ja" steht:
					if ( doc.field[ 38 ] == "Ja" )
					{
						// Welche Akte gehört zum aktuellen Dokument?
						// Die Akte wird herausgefunden, indem mit der Aktennummer gesucht wird
						
						def sqlQuery = "select doku_id from firmen_spezifisch where dok_dat_feld_10 = '" + doc.field[ 10 ] + "' and kue_dokuart in ( 'ADAUR', 'AAURE', 'ABERB', 'ABETR', 'AFIBA', 'AJAAA', 'ALOJA', 'ALBSA', 'ASTEU' )";
						
						def resultRows = d3.sql.executeAndGet( (String) sqlQuery );
						
						d3.log.info( "instert_exit_20: Ermittlung doku_id für Aktennummer: "+ doc.field[ 10 ]); //JFEL: 09.12.22 Erweiterung Loging aufgrund von nicht erstellten Tasks 
						
						if ( resultRows.size() > 0 )
						{
							def doku_id = resultRows[0][ "doku_id" ];
							
							//d3.log.error( "gefundene Akten-ID " + doku_id );
							
							def akte = d3.archive.getDocument( doku_id );
							
							def username;
							
							ArrayList<String> empfaenger = new ArrayList<>();
							empfaenger = [];
							
							def server_kuerzel = d3.config.value( "d3fc_server_id" );
							def repo_id, baseUri, authUsr;
							
							
							switch ( server_kuerzel )
							{
								case "T":
									repo_id = "b3be8a21-9cc1-5079-8dac-1c719ac7f80f";
									baseUri = "https://d3one-test.kleeberg.kleeberg.de/";
									authUsr = "t4HPtO8zLfxYVu0LylFG9dVvxc6b5sBV+P1YMt6GtKx7IxoKPQO0UWsh8ch6+MPGiCfUIn4MVwhvj6SSAiKDe83vl0MbtbG4xB/Igl6ilLg=&_z_A0V5ayCQyduqJQXU6c1T8QPL7tAJUPapw4J4uxsq_6e6a8timZXZmTwaqCcqcIoecor7zzqzpY0tCUhlW1L9b3Hsxgtdw";
									break;
								case "P":
									repo_id = "7b813cf7-9909-54ba-a333-f62d302fdfdc";
									baseUri = "https://d3one.kleeberg.kleeberg.de/";
									authUsr = "XEnvA6iv1JlaMuWBut1oiG1sGb88zZVtlgclIzrfPnD9haZ6s+NzZEMIUPc5W4tMQarJ0N4BI1WLlCWeHvrfp8JXbflWNZMDq12iXux2lxM=&_z_A0V5ayCQKwVv9K-Z0eIw5kCzeLaJAoOxpj1fw6px159gyZQadH2d8uhawpnegUH6CDD0pisvF_lyf3Ks9qINLrPd_K263";
									break;
							}
							
							//JFEL 06.05.2022: Anpassung zum Test der Performance
							for ( int i = 1 ; i <= Integer.valueOf( d3.config.value( "CUR_60ER_FIELD_NR" ) ); i++ )
							//for ( int i = 1 ; i < 10; i++ )
							{
								// Iterieren über die gefundenen Benutzer:
								
								if ( akte.field[ 60 ][ i ] )
								{
									
									username = getUserIdpId( d3, akte.field[ 60 ][ i ].substring( akte.field[ 60 ][ i ].indexOf ( "(" ) + 1, akte.field[ 60 ][ i ].indexOf( ")" ) ), repo_id, baseUri, authUsr );
									
									empfaenger.push( username );
									
									//d3.log.error( "insert_exit_20: Task für Username "+ username); //JFEL: 09.12.22 Erweiterung Loging aufgrund von nicht erstellten Tasks 
									
									def e = createTask( d3, user, docTypeShort, doc, "ND " + doc.field[ 10 ] + " / " + doc.field[ 6 ], "Zur Kenntnisnahme: Es wurde ein neues Dokument in die Akte " + doc.field[ 10 ] + " des Mandanten " + doc.field[ 2 ] + "/" + doc.field[ 1 ] + " importiert.", empfaenger, baseUri, authUsr, repo_id );
									
									empfaenger.remove( username );
								}
								else
								{
									//break;
								}
							}
						}
					}
		}
		
		
		}
		
		
		//////////////////////////////////////
		// Wenn ein Dokument in der Mandantenakte abgelegt wird (d.h. in die bekannten Dokumentarten importiert wird), sollen die "Postempfänger", d.h. die Personen, die im entsprechenden Eigenschaftsfeld der zugehörigen
		// Akte (Dauerakte, Beratungsakte, ...) hinterlegt sind, eine Benachrichtigung in ihren Postkorb (Kachel "Aufgaben") bekommen. ENDE
		//////////////////////////////////////
		
		
		
		
		
		//////////////////////////////////////
		// Wenn ein Dokument in der Mandantenakte abgelegt wird (d.h. in die bekannten Dokumentarten importiert wird), soll geprüft werden, ob das Dokument noch an weitere Stellen verknüpft werden soll - diese
		// Verknüpfungen sollen dann erzeugt werden START
		//////////////////////////////////////
		
		
		if ( true )
		{
		switch ( docTypeShort.id )
		{
			case "DDAUE":
			case "DABSC":
			case "DBERA":
			case "DSTEU":
			case "DBETR":
			case "DFIBU":
			case "DLOHN":
			case "DDEBD":
			case "DLSTD":
			case "DKRED": 
				if ( doc.field[ 48 ] )
				{
					// Unique-ID ist gesetzt => prüfe, ob das Dokument verknüpft werden soll:
					
					//def STATEMENT = "select doku_id_target_fol from mig_link_docs where Unique_ID_DOC = '" + doc.field[ 48 ] + "'";
					
					def STATEMENT = "select firmen_spezifisch.doku_id doku_id_target_fol from mig_link_docs_2 left join firmen_spezifisch on firmen_spezifisch.dok_dat_feld_10 = mig_link_docs_2.ddf10 \
										where mig_link_docs_2.Unique_ID_Doc = '" + doc.field[ 48 ] + "' \
										and mig_link_docs_2.ddf10 = firmen_spezifisch.dok_dat_feld_10 \
										and mig_link_docs_2.DDF3 = firmen_spezifisch.dok_dat_feld_3 \
										and (mig_link_docs_2.DDF4 = firmen_spezifisch.dok_dat_feld_4 or (mig_link_docs_2.DDF4 is null and firmen_spezifisch.dok_dat_feld_4 is null)) \
										and (mig_link_docs_2.DDF23 = firmen_spezifisch.dok_dat_feld_23 or (mig_link_docs_2.DDF23 is null and firmen_spezifisch.dok_dat_feld_23 is null)) \
										and (mig_link_docs_2.DDF17 = firmen_spezifisch.dok_dat_feld_17 or (mig_link_docs_2.DDF17 is null and firmen_spezifisch.dok_dat_feld_17 is null)) \
										and (mig_link_docs_2.DDF32 = firmen_spezifisch.dok_dat_feld_32 or (mig_link_docs_2.DDF32 is null and firmen_spezifisch.dok_dat_feld_32 is null)) \
										and ( firmen_spezifisch.doku_id != '" + doc.id + "') \
										and (firmen_spezifisch.kue_dokuart like 'A%') \
										order by doku_id";
					
					//d3.log.error( STATEMENT );
					
					def verknuepf_akten = d3.sql.executeAndGet( (String) STATEMENT );
					
					if ( verknuepf_akten.size() > 0 )
					{
						verknuepf_akten.each
						{
							//def ergebnis = d3.call.link_documents( it.doku_id_target_fol, doc.id, "Master", false, false );
							
							def insSTATEMENT = "insert into mig_multi_link_work (doku_id_father, doku_id_child) values ('" + it.doku_id_target_fol + "', '" + doc.id + "');";
							
							def insERG = d3.sql.execute( (String) insSTATEMENT );
							
							//xlog( d3, 2, insERG );
							
							if ( insERG != 1 )
							{
								xlog( d3, 2, "Es gab ein Problem beim Vorbereiten der Aktenverknuepfung zwischen [" + it.doku_id_target_fol + "] (Vater) und [" + doc.id + "] (Kind)." );
							}
							
							//if ( ergebnis != 0 )
							//{
							//	xlog( d3, 2, "Herstellen der zusaetzlichen Aktenverknuepfung zwischen Parent-Dok-ID [" + it.doku_id_target_fol + "] und Child-Dok-ID [" + doc.id + "] ist gescheitert: RC [" + ergebnis + "]" );
							//}
						}
						
					}
				}
		
		}
		
		}
		
		
		//////////////////////////////////////
		// Wenn ein Dokument in der Mandantenakte abgelegt wird (d.h. in die bekannten Dokumentarten importiert wird), soll geprüft werden, ob das Dokument noch an weitere Stellen verknüpft werden soll - diese
		// Verknüpfungen sollen dann erzeugt werden ENDE
		//////////////////////////////////////
		
		
		//////////////////////////////////////
		// Festhalten des Importzeitpunktes für Dokumente / Akten START
		//////////////////////////////////////
		
		doclog( d3, 4, "Import Dokument [" + doc.id + "] Dokumentart [" + docTypeShort.id + "] " );
		
		//////////////////////////////////////
		// Festhalten des Importzeitpunktes für Dokumente / Akten ENDE
		//////////////////////////////////////
		
		
		return 0;
	}
	
	
	@Entrypoint( entrypoint = "hook_validate_import_entry_10" )
	public int hookValidateImportEntry10( D3Interface d3, User user, DocumentType docType, Document doc, String nextcall )
	{
		d3.log.info("START | hookValidateImportEntry10 ");
		
		d3.log.info("ENDE | hookValidateImportEntry10 ");
		return 0;
	}
	
	
	@Entrypoint(entrypoint="hook_link_entry_30")
	public int linkEntry30 ( D3Interface d3, Document docFather, Document docChild )
	{
		//d3.log.info("START | linkEntry30 ");
		// Unterhalb der angegebenen Akten sollen keine Dokumente verknüpft werden können:
		
		// Die Prüfung wird nur durchgeführt, wenn das Dokument noch nicht verknüpft ist - nach der ersten Verknüpfung, die zwingend in der korrekten Akte erfolgen muss,
		// sind weitere Verknüpfungen wohin auch immer erlaubt.
		
		def ergebnis = d3.call.link_get_parents( docChild.id, "Master" );
		
		//d3.log.info("linkEntry30 Anzahl Elternelemente: " + ergebnis.length );
		
		if ( ( ergebnis.length == 0 ) && ( ! docChild.field[ 48 ] ) )
		{
		
			switch ( docChild.getType().getId() )
			{
				case "DBERA":
				case "DBETR":
				case "DDAUE":
				case "DDEBD":
				case "DFIBU":
				case "DABSC":
				case "DLOHN":
				case "DLSTD":
				case "DSTEU":
				
				switch ( docFather.getType().getId() )
				{
					case "AMAND":  // Mandantenakte
					case "ADAUR":  // Dauerakte
					case "ASTSA":  // Steuer-Sammelakte
					case "ALOSA":  // Lohnbuchhaltungs-Sammelakte
					case "AJASA":  // Jahresabschluss-Sammelakte
					case "AFBSA":  // Finanzbuchhaltungs-Sammelakte
					case "ABPSA":  // Betriebsprüfungs-Sammelakte
					case "ABESA":  // Beratungs-Sammelakte
					case "ABERB":  // Beratungsakte
					case "ABETR":  // Betriebspruefungsakte
					case "AFIBA":  // Finanzbuchhaltungsakte
					case "AJAAA":  // Jahresabschlussakte
					case "ALOJA":  // Lohnbuchhaltungs-Jahresakte
					case "ALBSA":  // Lohnbuchhaltungsstammdatenakte
					case "ASTEU":  // Steuerakte
				   
					return -1;
				}
				
				// Prüfen, ob das Kind-Dokument im richtigen Register abgelegt wurde
				// Jedes beim Kind gefüllte Register (gleich welcher Ebene) muss auch bei der Vaterakte mit dem gleichen Wert gefüllt sein
				
					//d3.log.info( docChild.id + " / " + docFather.id + ": Unterschied in DDF 3: " + docChild.field[ 3 ] + "/" + docFather.field[ 3 ] );
					//d3.log.info( docChild.id + " / " + docFather.id + ": Unterschied in DDF 4: " + docChild.field[ 4 ] + "/" + docFather.field[ 4 ] );
					//d3.log.info( docChild.id + " / " + docFather.id + ": Unterschied in DDF 23: " + docChild.field[ 23 ] + "/" + docFather.field[ 23 ] );
					//d3.log.info( docChild.id + " / " + docFather.id + ": Unterschied in DDF 17: " + docChild.field[ 17 ] + "/" + docFather.field[ 17 ] );
					//d3.log.info( docChild.id + " / " + docFather.id + ": Unterschied in DDF 32: " + docChild.field[ 32 ] + "/" + docFather.field[ 32 ] );
					
				// Oberregister
				if ( ! ( docChild.field[ 3 ] == docFather.field[ 3 ] ) )
				{
					return -192;
				}
				
				// Register
				if ( ! ( docChild.field[ 4 ] == docFather.field[ 4 ] ) )
				{
					return -192;
				}
				
				// Unterregister
				if ( ! ( docChild.field[ 23 ] == docFather.field[ 23 ] ) )
				{
					return -192;
				}
				
				// 2. Unterregister
				if ( ! ( docChild.field[ 17 ] == docFather.field[ 17 ] ) )
				{
					return -192;
				}
				
				// 3. Unterregister
				if ( ! ( docChild.field[ 32 ] == docFather.field[ 32 ] ) )
				{
					return -192;
				}
			}
		}
      
      
		
		return 0;
	}
	
	
	@Entrypoint(entrypoint="hook_upd_attrib_entry_20")
	public int upd_attrib_entry_20( D3Interface d3, Document doc, User user, DocumentType docType, DocumentType docTypeNew )
	{
		
		
		//////////////////////////////////////
		// Prüfen, ob in einem der Benutzerfelder eine E-Mail-Adresse angegeben wurde. Ist das der Fall, so wird der entsprechende Benutzer in der Benutzer-Tabelle gesucht und mit seinem Kürzel eingetragen. START
		//////////////////////////////////////
		
		if ( docType.id == "AMAND" )
		{
			
			// Hier wird für die Eigenschaft Geschäftsführer aus der Tribus-Schnittstelle das DDF45 gefüllt. Benutzt wird in der Akte das Feld 25. Gemacht wird diese Brücke, damit sich Änderungen 
			// an der Akte im DATEV nicht direkt in Aktenaktualisierungsjobs im d.3 manifestieren. Das gleiche Verfahren wird für den Mandatsverantwortlichen verwendet.
			
			
			
			///////////////////////////////////////////
			// DDF 25 / Geschäftsführer
			///////////////////////////////////////////
			def benutzername = "nicht ermittelbar";
			if ( doc.field[ 45 ] )
			{
				if ( doc.field[ 45 ].indexOf( "@" ) > 0 )
				{
					def sql_STATEMENT = "select realname + ' (' + benutzername + ')' as realbenutzername from benutzer where email = '" + doc.field[ 45 ] + "'";
					
					def sql_resultRows = d3.sql.executeAndGet( (String) sql_STATEMENT );
					
					if ( sql_resultRows.size() > 0 )
					{
						benutzername = sql_resultRows[ 0 ].realbenutzername;
					}
				}
			}
			doc.field[ 25 ] = benutzername;
			
			
			///////////////////////////////////////////
			// DDF 37 / Mandatsverantwortlicher
			///////////////////////////////////////////
			benutzername = "nicht ermittelbar";
			if ( doc.field[ 44 ] )
			{
				if ( doc.field[ 44 ].indexOf( "@" ) > 0 )
				{ 
					def sql_STATEMENT = "select realname + ' (' + benutzername + ')' as realbenutzername from benutzer where email = '" + doc.field[ 44 ] + "'";
					
					def sql_resultRows = d3.sql.executeAndGet( (String) sql_STATEMENT );
					
					if ( sql_resultRows.size() > 0 )
					{
						benutzername = sql_resultRows[ 0 ].realbenutzername;
					}
				}
			}
			doc.field[ 37 ] = benutzername;
			
			
			
			
		}
		
		//////////////////////////////////////
		// Prüfen, ob in einem der Benutzerfelder eine E-Mail-Adresse angegeben wurde. Ist das der Fall, so wird der entsprechende Benutzer in der Benutzer-Tabelle gesucht und mit seinem Kürzel eingetragen. ENDE
		//////////////////////////////////////
		
		////////////////////////////
		// Grundstücke sollen nur bei Dauerregisterakten angelegt werden können, wenn das Register "04.01 Grundstücke" ist START
		////////////////////////////
		
		
		
		if ( docType.id == "AREGS" )
		{
			// Prüfen, ob die Eigenschaft Grundstücke Werte enthält
			def gefunden = false;
			
			for ( int i = 1 ; i <= Integer.valueOf( d3.config.value( "CUR_60ER_FIELD_NR" ) ); i++ )
			{
				if ( doc.field[ 68 ][ i ] )
				{
					gefunden = true;
					break;
				}
			}
			
			
			if ( ( gefunden ) && ( doc.field[ 4 ].substring( 0, 13 ) != "04.01 Grundst" ) )
			{
				d3.log.info( "Grundstücke sind nur bei Daueraktenregisterakten mit dem Register '04.01 Grundstücke' anlegbar!" );
				return -177;
			}
			
		}
		
		
		
		////////////////////////////
		// Grundstücke sollen nur bei Dauerregisterakten angelegt werden können, wenn das Register "04.01 Grundstücke" ist ENDE
		////////////////////////////
		
		
		////////////////////////////
		// Vererben von Berechtigungen von einer Hauptakte (Dauerakte, Beratungsakte etc.) auf untergeordnete Akten + Dokumente START
		////////////////////////////
		
		if ( false ) // Logik ist ausgeschaltet
		{
		
		switch ( docTypeNew.id )
		{
			// Ausgangsrechnungsakte:
			case "AAURE":
			case "AAURR":
			case "AAURA":
			case "AAURU":
			case "AAUR2":
			// Beratungsakte:
			case "ABERB":
			case "ABERO":
			case "ABERA":
			case "ABEUR":
			case "ABEU2":
			// Betriebsprüfungsakte:
			case "ABETR":
			case "ABEOR":
			case "ABEPA":
			case "ABPUR":
			case "ABPU2":
			// Dauerakte:
			case "ADAUR":
			case "AOREG":
			case "AREGS":
			case "AUREG":
			case "AURG2":
			// Finanzbuchhaltungsakte:
			case "AFIBA":
			case "AFIOR":
			case "AFIRA":
			case "AFIUR":
			case "AFIU2":
			// Jahresabschlussakte:
			case "AJAAA":
			case "AJAOB":
			case "AJAAB":
			case "AJAUR":
			case "AJAU2":
			// Lohnbuchhaltungjahresakte:
			case "ALOJA":
			case "ALBOR":
			case "ALBRE":
			case "ALJUR":
			case "ALJR2":
			// Lohnbuchhaltungsstammdate:
			case "ALBSA":
			case "ALBSO":
			case "ALORE":
			case "ALOUR":
			case "ALBU2":
			// Steuerakte:
			case "ASTEU":
			case "ASTOR":
			case "ASTRA":
			case "ASTUR":
			case "ASTU2":
			
			// Kreditorakte:
			case "AKRED":
			case "AKROR":
			case "AKRER":
			case "AKREU":
			case "AKRU2":
			
			// Eigenverwaltungsakte:
			case "AEVAK":
			case "AEVOR":
			case "AEVRE":
			
				
				// Untergeordnete Akten/Dokumente ermitteln
				def unterdoks = d3.call.link_get_children( doc.id, "Master" );
				
				unterdoks.each
				{
					
					def currentDoc = d3.archive.getDocument( it );
					
					if ( currentDoc.field[ 10 ] == doc.field[ 10 ] )
					{
						//xlog( d3, 1, "Dokument: " + it );
						
						// Übernahme des Briefkopfs, falls beim Kind leer. Sollte eigentlich nicht notwendig sein, da Pflichtfeld. Im Testsystem gibt es aber auch
						// Akten, bei denen nachträglich als Pflichtfeld definierte Felder leer sind - das Feld Briefkopf ist so ein Fall.
						if ( ! currentDoc.field[ 42 ] )
						{
							//currentDoc.field[ 42 ] = doc.field[ 42 ];
						}
						
						if ( ! currentDoc.field[ 42 ] )
						{
							//currentDoc.field[ 42 ] = "Kleeberg";
						}
						
						//JFEL 06.05.2022: Test der Performance mit weniger Werten beim Schleifendurchlauf 
						//for ( int i = 1 ; i <= Integer.valueOf( d3.config.value( "CUR_60ER_FIELD_NR" ) ); i++ )
						//xlog( d3, 3, "(hook_upd_attrib_entry_20) Berechtigungen aktualisieren bei Dokument " + it + " Beginn" );
						//for ( int i = 1 ; i < 10 ; i++ )
						for ( int i = 1 ; i <= Integer.valueOf( d3.config.value( "CUR_60ER_FIELD_NR" ) ); i++ )
						{
							if ( ! doc.field[ 69 ][ i ] )
							{
								//break;
							}
							
							currentDoc.field[ 69 ][ i ] = doc.field[ 69 ][ i ];
						}
						//xlog( d3, 3, "(hook_upd_attrib_entry_20) Berechtigungen aktualisieren bei Dokument " + it + " Ende" );
						
						// Diese Felder müssen ebenfalls gesetzt werden, damit die Aktualisierung der untergeordneten Dokumente/Akten in jedem Fall funktioniert:
						//currentDoc.field[  2 ] = doc.field[  2 ];		// Mandantname
						//currentDoc.field[ 13 ] = doc.field[ 13 ];		// Mandantgruppennummer
						//currentDoc.field[ 21 ] = doc.field[ 21 ];		// Aktenname
						
						currentDoc.updateAttributes( "Master" );
						
					}
				}
				
				break;
		}
		
		
		
		}
		
		////////////////////////////
		// Vererben von Berechtigungen auf Hauptakte (Dauerakte, Beratungsakte etc.) auf untergeordnete Akten + Dokumente START
		////////////////////////////
			
		
		
		
		return 0;
	}
	
	
	@Entrypoint( entrypoint = "hook_link_exit_10" )
	public int hook_link_exit_10 ( D3Interface d3, Document docFather, Document docChild, Integer errorCode )
	{
		//xlog( d3, 3, "(hook_link_exit_10) Berechtigungen aktualisieren bei Dokument " + docChild.id );
		
		////////////////////////////
		// Vererben von Berechtigungen von einer Hauptakte (Dauerakte, Beratungsakte etc.) auf untergeordnete Akten + Dokumente START
		////////////////////////////
		
		// Ist der Vater eine Akte aus der Mandantenakte/Kreditorenakte, dann vererbe der Vater die Berechtigungen (DDF69) an das Kind (neue Dokument/Akte).
		
		if ( false )
		{
		switch ( docFather.getType().id )
		{
			// Ausgangsrechnungsakte:
			case "AAURE":
			case "AAURR":
			case "AAURA":
			case "AAURU":
			case "AAUR2":
			// Beratungsakte:
			case "ABERB":
			case "ABERO":
			case "ABERA":
			case "ABEUR":
			case "ABEU2":
			// Betriebsprüfungsakte:
			case "ABETR":
			case "ABEOR":
			case "ABEPA":
			case "ABPUR":
			case "ABPU2":
			// Dauerakte:
			case "ADAUR":
			case "AOREG":
			case "AREGS":
			case "AUREG":
			case "AURG2":
			// Finanzbuchhaltungsakte:
			case "AFIBA":
			case "AFIOR":
			case "AFIRA":
			case "AFIUR":
			case "AFIU2":
			// Jahresabschlussakte:
			case "AJAAA":
			case "AJAOB":
			case "AJAAB":
			case "AJAUR":
			case "AJAU2":
			// Lohnbuchhaltungjahresakte:
			case "ALOJA":
			case "ALBOR":
			case "ALBRE":
			case "ALJUR":
			case "ALJR2":
			// Lohnbuchhaltungsstammdate:
			case "ALBSA":
			case "ALBSO":
			case "ALORE":
			case "ALOUR":
			case "ALBU2":
			// Steuerakte:
			case "ASTEU":
			case "ASTOR":
			case "ASTRA":
			case "ASTUR":
			case "ASTU2":
			// Kreditorenakte:
			case "AKRED":
			case "AKROR":
			case "AKRER":
			case "AKREU":
			case "AKRU2":
			// Eigenverwaltungsakte:
			case "AEVAK":
			case "AEVOR":
			case "AEVRE":
			
				if ( docChild.field[ 10 ] == docFather.field[ 10 ] )
				{
					//JFEL 06.05.2022 Anpassung zum Test der Performance
					//for ( int i = 1 ; i < 10 ; i++ )
					for ( int i = 1 ; i <= Integer.valueOf( d3.config.value( "CUR_60ER_FIELD_NR" ) ); i++ )
					{
						if ( ! docFather.field[ 69 ][ i ] )
						{
							break;
						}
						
						docChild.field[ 69 ][ i ] = docFather.field[ 69 ][ i ];
					}
					
					docChild.updateAttributes( "Master" );
					
				}
				
		}
		
		
		}
		
		////////////////////////////
		// Vererben von Berechtigungen auf Hauptakte (Dauerakte, Beratungsakte etc.) auf untergeordnete Akten + Dokumente ENDE
		////////////////////////////
		
		
		////////////////////////////
		// Feststellen, wo das Dokument überall verknüpft ist und Eintragen dieser Verknüpfungen in verschiedene 60er-Felder START
		////////////////////////////
		
		switch ( docChild.getType().id )
		{
			case "DBERA":
			case "DBETR":
			case "DDAUE":
			case "DDEBD":
			case "DFIBU":
			case "DABSC":
			case "DLOHN":
			case "DLSTD":
			case "DSTEU":
				def ueberdoks = d3.call.link_get_parents( docChild.id, "Master" );
				
				def ziel_dok_ids = "";
				
				ueberdoks.each
				{
					xlog( d3, 4, " Kind: " + docChild.id + " Elternelement: " + it );
					
					ziel_dok_ids = ziel_dok_ids + "'" + it + "',";
				}
				ziel_dok_ids = ziel_dok_ids.substring( 0, ziel_dok_ids.length( ) - 1 );
				
				xlog( d3, 2, "Ziel-Dok_IDs: " + ziel_dok_ids );
				
				def STATEMENT = "select dok_dat_feld_1, dok_dat_feld_2, dok_dat_feld_10, dok_dat_feld_13, dok_dat_feld_21 from firmen_spezifisch where doku_id in ( " + ziel_dok_ids + " ) ";
				
				def resultRows = d3.sql.executeAndGet( STATEMENT );
				
				if ( resultRows.size() > 0 )
				{
					// Schreiben der Verknüpfungen an das Dokument:
					
					def currentDoc = d3.archive.getDocument( docChild.id );
					
					// Die Felder werden vor dem Füllen geleert, damit - für den Fall, dass weniger neue Werte reingeschrieben werden als vorher drin waren - keine
					// deplazierten Restwerte in den Feldern stehen bleiben. (Könnte man vielleicht auch eleganter lösen.)
					// Felder leeren:
					for ( int i = 1 ; i <= Integer.valueOf( d3.config.value( "CUR_60ER_FIELD_NR" ) ); i++ )
					{
						currentDoc.field[ 60 ][ i ] = ""; // Mandantennamen
						currentDoc.field[ 61 ][ i ] = ""; // Mandantennummern
						currentDoc.field[ 62 ][ i ] = ""; // Mandantengruppennummern
						currentDoc.field[ 63 ][ i ] = ""; // Aktennamen
						currentDoc.field[ 64 ][ i ] = ""; // Aktennummern
					}
					
					// Jetzt Felder füllen mit den gefundenen Werten:
					for ( int j = 1 ; j <= resultRows.size(); j++ )
					{
						currentDoc.field[ 60 ][ j ] = resultRows[ j - 1 ].dok_dat_feld_2; // Mandantennamen
						currentDoc.field[ 61 ][ j ] = resultRows[ j - 1 ].dok_dat_feld_1; // Mandantennummern
						currentDoc.field[ 62 ][ j ] = resultRows[ j - 1 ].dok_dat_feld_13; // Mandantengruppennummern
						currentDoc.field[ 63 ][ j ] = resultRows[ j - 1 ].dok_dat_feld_21; // Aktennamen
						currentDoc.field[ 64 ][ j ] = resultRows[ j - 1 ].dok_dat_feld_10; // Aktennummern
					}
					
					currentDoc.updateAttributes( "Master" );
					
				}
				
				break;
			
			
		}
		
		////////////////////////////
		// Feststellen, wo das Dokument überall verknüpft ist und Eintragen dieser Verknüpfungen in verschiedene 60er-Felder ENDE
		////////////////////////////
		
		
		
		//xlog( d3, 4, "1 *********************************************************" );
		//xlog( d3, 4, "hook_link_exit_10: " + docFather.id + " / " + docFather.getType().id + " => " + docChild.id + " / " + docChild.getType().id + " ENDE " );
		//xlog( d3, 4, "Mandatenakte " + docChild.field[ 1 ] + " / " + docChild.field[ 2 ] );
		
		
		return 0;
		
	}

	
	
	
	
	
	
	
	
	
	
	public static int createTask( D3Interface d3, User user, DocumentType docType, Document doc, String subject, String description, ArrayList<String> assignees, String baseUri, String authUsr, String repo_id )
	{
		//d3.log.info( "createTask !" );
		String assigneesString = "";
		
		assignees.each
		{
			assigneesString = assigneesString + "\"${it}\",";
		}
		
		if ( assigneesString.length() > 0 )
		{
			assigneesString = assigneesString.substring(0, assigneesString.length()-1);
		}
		
		CloseableHttpClient client = HttpClientBuilder.create( ).build( );

		try
		{
			
			UUID uuid = UUID.randomUUID();
			String randomUUIDString = uuid.toString();
			
			//Post Task
			HttpPost post = new HttpPost( baseUri + "/task/tasks" );
			
			def ddf4;
			if ( doc.field[ 4 ] == null )
			{
				ddf4 = "";
			}
			else
			{
				ddf4 = doc.field[ 4 ];
			}
			
			def ddf23;
			if ( doc.field[ 23 ] == null )
			{
				ddf23 = "";
			}
			else
			{
				ddf23 = doc.field[ 23 ];
			}
			
			def ddf17;
			if ( doc.field[ 17 ] == null )
			{
				ddf17 = "";
			}
			else
			{
				ddf17 = doc.field[ 17 ];
			}
			
			def ddf32;
			if ( doc.field[ 32 ] == null )
			{
				ddf32 = "";
			}
			else
			{
				ddf32 = doc.field[ 32 ];
			}
			
			//JSON Inhalt
			
			def lJsonString = """{
    								"subject" : "${subject}",
									"description" : "${description}",
    								"assignees" : [${assigneesString}],
									"correlationKey" : "${randomUUIDString}",
									"context" : {
											"key"  : "returnProcess",
											"type" : "process",
											"name" : "Import in Akte"
									},
									"metadata" : [
											{
												"key" : "mandantname",
												"caption" : "__Mandantname",
												"values" : ["${doc.field[2]}"]
											},
											{
												"key" : "aktennummer",
												"caption": "__Aktennummer",
												"values" : ["${doc.field[10]}"]
											},
											{
												"key" : "oberregister",
												"caption" : "_Oberregister",
												"values" : ["${doc.field[3]}"]
											},
											{
												"key" : "register",
												"caption" : "_Register",
												"values" : ["${ddf4}"]
											},
											{
												"key" : "unterregister",
												"caption" : "_Unterregister",
												"values" : ["${ddf23}"]
											},
											{
												"key" : "unterregister2",
												"caption" : "2. Unterregister",
												"values" : ["${ddf17}"]
											},
											{
												"key" : "unterregister3",
												"caption" : "3. Unterregister",
												"values" : ["${ddf32}"]
											}
									],
									"_links" : {
											"attachment" : { "href": "/dms/r/${repo_id}/o2/${doc.id()}"}
									}
								}""";

			StringEntity params = new StringEntity( lJsonString, StandardCharsets.UTF_8 );
			params.setContentType("application/json");
			
			post.addHeader("authorization", "Bearer ${authUsr}");
			post.addHeader("content-type", "application/json");
			post.addHeader("origin", baseUri );
			post.setEntity( params );
			CloseableHttpResponse response = client.execute( post );

			try
			{
				def statusCode = response.getStatusLine( ).getStatusCode( );
				
				if( statusCode != 200 && statusCode != "200" && statusCode != 201 && statusCode != "201" )
				{
					HttpEntity re = response.getEntity();
					def lErrMsg = "createOfficeTaskFinished - Error while trying to create Task! Status Code: " + statusCode + " / Response: " + re.getContent().text;
					d3.log.info( "createOfficeTaskFinished" + "" + lErrMsg + " -> " + lJsonString);
				}
			}
			finally
			{
				response.close();
			}
		}
		catch ( Exception e )
		{
			d3.log.error( "createOfficeTaskFinished" + "" + e.getMessage() );
		}
		finally
		{
			client.close();
		}
		
		return 0;
	}
	
	
	
	
	
	
	public String getUserIdpId( D3Interface d3, String UserName, String repo_id, String baseUri, String authUserApiKey )
	{
		
		CloseableHttpClient client = HttpClientBuilder.create( ).build( );
		String userId;
		
		try
		{
			//https://d3one-test.kleeberg.kleeberg.de/identityprovider/scim/users?filter=userName%20eq%20kleeberg%5Cdvelop
			HttpGet get = new HttpGet( baseUri + "/identityprovider/scim/users?filter=userName%20eq%20kleeberg%5C" + UserName );
			
			//JSON Inhalt
			get.addHeader( "authorization", "Bearer " + authUserApiKey );
			get.addHeader( "origin", baseUri );
			get.addHeader( "Accept", "application/json" );
			
			CloseableHttpResponse response = client.execute( get );
			
			
			
			try
			{
				def statusCode = response.getStatusLine( ).getStatusCode( );
				
				if( statusCode != 200 && statusCode != 201 ){
					d3.log.error("getUserIdpId -> Error while trying to read user " + UserName + " status code: " + statusCode );

					HttpEntity re = response.getEntity();
					InputStream errStream = re.getContent();
					String errContent = "";

					if( errStream != null && errStream.available() > 0 ){
						errContent = IOUtils.toString(errStream, StandardCharsets.UTF_8);
					}

					d3.log.error("getUserIdpId -> Error while trying to read user " + UserName + " response line: " + errContent);

					return "";
				}
				
				HttpEntity entity = response.getEntity( );

				String json = EntityUtils.toString( entity, StandardCharsets.UTF_8 );
				
				def jsonSlurper = new JsonSlurper();
				
				def returnwert = jsonSlurper.parseText( json );
				
				userId = returnwert.resources.id[ 0 ];
				
				
			}
			finally
			{
				response.close();
			}
		}
		catch ( IOException e )
		{
			e.printStackTrace();
		}
		finally
		{
			try
			{
				client.close();
			}
			catch (IOException e)
			{
				e.printStackTrace();
			}
		}
		
		return userId;
		
	}
	
	
	public int xlog( D3Interface d3, int loglevel, String logtext )
	{
		def logdatei		= "d:\\d3\\apps\\d3log.txt";
		def g_loglevel		= 5;
		def g_logdirect		= "BEIDE";  // BEIDE oder D3LOG oder DATEI
		def date			= new Date();
		def zeitstempel		= date.format( "yyyy.MM.dd HH:mm:ss", TimeZone.getTimeZone('CET') );
		def loglevel_lang	= "[INFO ]";
		
		
		
		
		
		if ( loglevel <= g_loglevel )
		{
			switch ( loglevel )
			{
				case 1:
					loglevel_lang   = "[FATAL]";
					
					if ( ( g_logdirect == "D3LOG" ) || ( g_logdirect == "BEIDE" ) )
					{
						d3.log.critical( logtext );
					}
					break;
				case 2:
					loglevel_lang   = "[ERROR]";
					
					if ( ( g_logdirect == "D3LOG" ) || ( g_logdirect == "BEIDE" ) )
					{
						d3.log.error( logtext );
					}
					break;
				case 3:
					loglevel_lang   = "[WARN ]";
					
					if ( ( g_logdirect == "D3LOG" ) || ( g_logdirect == "BEIDE" ) )
					{
						d3.log.warn( logtext );
					}
					break;
				case 4:
					loglevel_lang   = "[INFO ]";
					
					if ( ( g_logdirect == "D3LOG" ) || ( g_logdirect == "BEIDE" ) )
					{
						d3.log.info( logtext );
					}
					break;
				case 5:
					loglevel_lang   = "[DEBUG]";
					// Da die d.3 Server i.d.R. nicht im Debug-Modus laufen, erscheinen DEBUG-Meldungen nicht im Log.
					if ( ( g_logdirect == "D3LOG" ) || ( g_logdirect == "BEIDE" ) )
					{
						d3.log.debug( logtext );
					}
					break;
			}
			
		}
		
		if ( ( g_logdirect == "DATEI" ) || ( g_logdirect == "BEIDE" ) )
		{
			new File( logdatei ).append( zeitstempel + " " + loglevel_lang + " " + logtext + "\n", "UTF8" );
		}
		
		
		return 0;
	}
	
	
	public int doclog( D3Interface d3, int loglevel, String logtext )
	{
		def logdatei		= "d:\\d3\\apps\\doc_import_zeitpunkte.txt";
		def g_loglevel		= 5;
		def g_logdirect		= "BEIDE";  // BEIDE oder D3LOG oder DATEI
		def date			= new Date();
		def zeitstempel		= date.format( "yyyy.MM.dd HH:mm:ss", TimeZone.getTimeZone('CET') );
		def loglevel_lang	= "[INFO ]";
		
		
		
		
		
		if ( loglevel <= g_loglevel )
		{
			switch ( loglevel )
			{
				case 1:
					loglevel_lang   = "[FATAL]";
					
					if ( ( g_logdirect == "D3LOG" ) || ( g_logdirect == "BEIDE" ) )
					{
						d3.log.critical( logtext );
					}
					break;
				case 2:
					loglevel_lang   = "[ERROR]";
					
					if ( ( g_logdirect == "D3LOG" ) || ( g_logdirect == "BEIDE" ) )
					{
						d3.log.error( logtext );
					}
					break;
				case 3:
					loglevel_lang   = "[WARN ]";
					
					if ( ( g_logdirect == "D3LOG" ) || ( g_logdirect == "BEIDE" ) )
					{
						d3.log.warn( logtext );
					}
					break;
				case 4:
					loglevel_lang   = "[INFO ]";
					
					if ( ( g_logdirect == "D3LOG" ) || ( g_logdirect == "BEIDE" ) )
					{
						d3.log.info( logtext );
					}
					break;
				case 5:
					loglevel_lang   = "[DEBUG]";
					// Da die d.3 Server i.d.R. nicht im Debug-Modus laufen, erscheinen DEBUG-Meldungen nicht im Log.
					if ( ( g_logdirect == "D3LOG" ) || ( g_logdirect == "BEIDE" ) )
					{
						d3.log.debug( logtext );
					}
					break;
			}
			
		}
		
		if ( ( g_logdirect == "DATEI" ) || ( g_logdirect == "BEIDE" ) )
		{
			new File( logdatei ).append( zeitstempel + " " + loglevel_lang + " " + logtext + "\n", "UTF8" );
		}
		
		
		return 0;
	}
	
	
	
	
	
	
}