<?php
/*
 * Job zur einmaligen Import der Gehälter
 *
 * Aufruf (Encode / im Filenmae mit %2F):
 * php index.ci.php system/MigrateSalary/import filename
 *
 */
/*
AUFBAU CSV:
SVNR;Pers-Nr;Name;Dienstverhältnis;LA-Nr;Bezeichnung;2022-09-01;2022-10-01;2022-11-01;2022-12-01;2023-01-01;2023-02-01;2023-03-01
XXXX XXXXXX;00;Name;5;1000;Gehalt;1.111,10;1.211,10;1.311,10;1.411,10;1.511,10;1.611,10;1.711,10
*/

if (! defined('BASEPATH')) exit('No direct script access allowed');

class MigrateSalary extends CLI_Controller
{
	private $OE_DEFAULT = 'gst';
	private $GEHALT_BEGINN_SPALTE = 6; // Beginnend mit 0 => G
	private $INDEX_LOHNART = 4;
	private $INDEX_BEZEICHNUNG = 5;

	/**
	 * Constructor
	 */
	public function __construct()
	{
		parent::__construct();

		$this->load->model('vertragsbestandteil/Gehaltsbestandteil_model', 'GehaltsbestandteilModel');
		$this->load->model('vertragsbestandteil/Dienstverhaeltnis_model','DienstverhaeltnisModel');
		$this->load->model('vertragsbestandteil/Vertragsbestandteil_model','VertragsbestandteilModel');
		$this->load->model('vertragsbestandteil/VertragsbestandteilStunden_model','VertragsbestandteilStundenModel');
		$this->load->model('vertragsbestandteil/VertragsbestandteilFreitext_model','VertragsbestandteilFreitextModel');
		$this->load->model('vertragsbestandteil/VertragsbestandteilFunktion_model','VertragsbestandteilFunktionModel');

	}

	// -----------------------------------------------------------------------------------------------------------------
	// Public methods

	/**
	 * Everything has a beginning
	 */
	public function import($file)
	{

		// CSV Laden
		$file = urldecode($file);
		if($handle = fopen($file, "r"))
		{
			$csvrow = -1;
			$lastuser = '';
			$monate = array();
			$gehaltsarr = array();
			$gehaltsindex = 0;

			while (($data = fgetcsv($handle, null, ';')) !== FALSE)
			{
				$csvrow++;
				// Kopfzeile ueberspringen
				if($csvrow == 0)
				{
					for($i = $this->GEHALT_BEGINN_SPALTE; $i < count($data); $i++)
					{
						$monate[] = $data[$i];
					}
					continue;
				}

				// User zur SVNR ermitteln
				$svnr = str_replace(' ', '',$data[0]);
				$resultuser = $this->_getUser($svnr);

				if(!hasData($resultuser))
				{
					echo getError($resultuser);
					break;
				}

				$user = getData($resultuser)[0]->mitarbeiter_uid;
				echo "\nUser:".$user;

				if($user != $lastuser && $lastuser != '')
				{
					$this->_saveGehalt($lastuser, $gehaltsarr);
					$gehaltsarr = array();
					$gehaltsindex = 0;
					$lastuser = $user;
				}
				else
				{
					$lastuser = $user;
				}

				// Gehalt Clustern

				$monat = 0;
				for ($i = $this->GEHALT_BEGINN_SPALTE; $i < count($data); $i++)
				{
					if (count($gehaltsarr) == 0 && $data[$i] != '')
					{
						$gehaltsarr[$gehaltsindex]['betrag'] = $data[$i];
						$gehaltsarr[$gehaltsindex]['lohnart'] = $data[$this->INDEX_LOHNART];
						$gehaltsarr[$gehaltsindex]['bezeichnung'] = $data[$this->INDEX_BEZEICHNUNG];
						$gehaltsarr[$gehaltsindex]['beginn'] = $monate[$monat];
					}
					else
					{
						if ($data[$i] != ''
							&& isset($gehaltsarr[$gehaltsindex]) && isset($gehaltsarr[$gehaltsindex]['betrag'])
							&& $gehaltsarr[$gehaltsindex]['betrag'] == $data[$i])
						{
							// Gehalt bleibt gleich
						}
						else
						{
							if ($data[$i] != '')
							{
								// Gehalt hat sich geändert
								if ($monat != 0 && isset($gehaltsarr[$gehaltsindex]))
									$gehaltsarr[$gehaltsindex]['ende'] = $monate[$monat-1];

								$gehaltsindex++;

								$gehaltsarr[$gehaltsindex]['betrag'] = $data[$i];
								$gehaltsarr[$gehaltsindex]['lohnart'] = $data[$this->INDEX_LOHNART];
								$gehaltsarr[$gehaltsindex]['bezeichnung'] = $data[$this->INDEX_BEZEICHNUNG];
								$gehaltsarr[$gehaltsindex]['beginn'] = $monate[$monat];
							}
							elseif(isset($gehaltsarr[$gehaltsindex]))
							{
								// Gehalt wurde beendet
								if($monat!=0)
									$gehaltsarr[$gehaltsindex]['ende'] = $monate[$monat-1];
								$gehaltsindex++;
							}
						}
					}

					$monat++;
				}

				// Zeile zu Ende - Ende Datum setzen wenn nicht für alle Monate ein Eintrag vorhanden ist
				if($monat < count($monate) && isset($gehaltsarr[$gehaltsindex]))
					$gehaltsarr[$gehaltsindex]['ende'] = $monate[$monat-1];

			}
			$this->_saveGehalt($lastuser, $gehaltsarr);
		}
	}

	/**
	 * Ermittelt das passende Dienstverhaeltnis uns speichert den
	 * Gehaltsbestandteil
	 */
	private function _saveGehalt($uid, $gehaltsarr)
	{
		$failed = false;
		$this->db->trans_begin();

		foreach($gehaltsarr as $row_gehalt)
		{
			//var_dump($row_gehalt);
			$auszahlungen = 14;
			$dvid = '';
			$vbsid = '';
			$typ = '';
			$allin = false;

			//DV und VBS Ermitteln
			$dv = $this->DienstverhaeltnisModel->getDVByPersonUID($uid, $this->OE_DEFAULT, $row_gehalt['beginn']);

			// Wenn keiner gefunden wird oder mit Monatsersteln nur ein externer gefunden wird, weitersuchen ob im Monat noch ein
			// "richtiger" Vertrag startet
			if (!hasData($dv) || getData($dv)[0]->vertragsart_kurzbz='externerLehrender')
			{
				$date = new DateTime($row_gehalt['beginn']);
				$date->modify('last day of this month');
				$last_day_this_month = $date->format('Y-m-d');

				// Wenn mit Monatsersten kein DV gefunden wird, wird stattdessen mit Monatsletzten gesucht um DVs zu finden
				// für Personen die erst später im Monat in ihr DV einsteigen
				$dv = $this->DienstverhaeltnisModel->getDVByPersonUIDOverlapping($uid, $this->OE_DEFAULT, $row_gehalt['beginn'], $last_day_this_month);

				if (!hasData($dv))
				{
					echo "\nKein passendes DV gefunden für User ".$uid." und Datum ".$row_gehalt['beginn']." -> ROLLBACK\n";
					$failed = true;
					break;
				}
				else
				{
					$resultdata = getData($dv);
					foreach($resultdata as $dvdata)
					{
						// Externer DV wird in Monatsmitte zu echten DV - daher weitersuchen bei externenDVs da
						// diese sowieso kein Gehalt zugeordnet haben
						if($dvdata->vertragsart_kurzbz != 'externerLehrender')
						{
							$dvid = $dvdata->dienstverhaeltnis_id;
							// Gehaltsstart wird auf den Start des DV korrigiert wenn nicht der Monatserste
							// nur wenn das Beginndatum vor dem DV-Start liegt da sonst das Datum korrigiert wird
							// wenn der Vertragsbestandteil wechselt
							if($row_gehalt['beginn'] < $dvdata->von)
								$row_gehalt['beginn'] = $dvdata->von;
							break;
						}
					}
				}
			}
			else
			{
				$resultdata = getData($dv);

				if (count($resultdata) == 1)
					$dvid = $resultdata[0]->dienstverhaeltnis_id;
			}

			if ($dvid == '')
			{
				echo "Kein oder mehrere DVs gefunden -> ROLLBACK";
				$failed = true;
				break;
			}

			$allin = $this->_isAllIn($dvid, $row_gehalt['beginn']);

			$db = new DB_Model();

			$resultVBS = $this->_getVBS($dvid, $row_gehalt['beginn']);

			if (hasData($resultVBS))
			{
				$vbsid = getData($resultVBS)[0]->vertragsbestandteil_id;
				$vbsbis = getData($resultVBS)[0]->bis;
			}
			else
			{
				echo "Vertragsbestandteil fuer $uid DV $dvid wurde nicht gefunden mit Beginn ".$row_gehalt['beginn']."-> ROLLBACK";
				$failed = true;
				break;
			}

			if ($row_gehalt['lohnart'] == 1000)
			{
				if($allin)
					$typ = 'grundgehalt';
				else
					$typ = 'basisgehalt';
			}
			elseif ($row_gehalt['lohnart']==1041 // 14x
				|| $row_gehalt['lohnart']==1042  // 12x
				|| $row_gehalt['lohnart']==3410)  // USTDPausch
			{
				$typ = 'zusatzvereinbarung';

				// Freitextbestandteil anlegen fuer die Zulage
				// Gaehalt wird der Zuglage zugeordnet

				$data = array(
					'dienstverhaeltnis_id' => $dvid,
					'von' => $row_gehalt['beginn'],
					'vertragsbestandteiltyp_kurzbz' => 'freitext',
					'insertamum' => date('Y-m-d H:i:s'),
					'insertvon' => 'MigrateSalary'
				);
				if (isset($row_gehalt['ende']) && $row_gehalt['ende']!='')
					$data['bis'] = $row_gehalt['ende'];

				$resultVBS = $this->VertragsbestandteilModel->Insert($data);
				if(!isSuccess($resultVBS))
				{
					echo "VBS kann nicht erstellt werden -> ROLLBACK";
					$failed = true;
					break;
				}
				$vbsid = getData($resultVBS);

				$data = array(
					'vertragsbestandteil_id' => $vbsid,
					'freitexttyp_kurzbz' => 'zusatzvereinbarung',
					'titel' => $row_gehalt['bezeichnung'],
					'anmerkung' => $row_gehalt['bezeichnung'],
				);
				$resultVBSFreitext = $this->VertragsbestandteilFreitextModel->Insert($data);
				if(!isSuccess($resultVBSFreitext))
				{
					echo "VBS Freitext Zusatz kann nicht erstellt werden -> ROLLBACK";
					$failed = true;
					break;
				}
			}
			elseif ($row_gehalt['lohnart']==9999) // All-In Custom Lohnart nicht per Default vorhanden
			{
				$typ = 'zulage';

				// Freitextbestandteil anlegen fuer die Zulage
				// Gaehalt wird der Zuglage zugeordnet

				$data = array(
					'dienstverhaeltnis_id' => $dvid,
					'von' => $row_gehalt['beginn'],
					'vertragsbestandteiltyp_kurzbz' => 'freitext',
					'insertamum' => date('Y-m-d H:i:s'),
					'insertvon' => 'MigrateSalary'
				);
				if (isset($row_gehalt['ende']) && $row_gehalt['ende']!='')
					$data['bis'] = $row_gehalt['ende'];

				$resultVBS = $this->VertragsbestandteilModel->Insert($data);
				if(!isSuccess($resultVBS))
				{
					echo "VBS AllIn kann nicht erstellt werden -> ROLLBACK";
					$failed = true;
					break;
				}
				$vbsid = getData($resultVBS);

				$data = array(
					'vertragsbestandteil_id' => $vbsid,
					'freitexttyp_kurzbz' => 'allin',
					'titel' => $row_gehalt['bezeichnung'],
					'anmerkung' => $row_gehalt['bezeichnung'],
				);
				$resultVBSFreitext = $this->VertragsbestandteilFreitextModel->Insert($data);
				if(!isSuccess($resultVBSFreitext))
				{
					echo "VBS Freitext AllIn Zusatz kann nicht erstellt werden -> ROLLBACK";
					$failed = true;
					break;
				}
			}
			elseif($row_gehalt['lohnart']==5500) // ATZ
			{
				$typ = 'lohnausgleichatz';
			}
			else
			{
				$typ = 'unbekannt - '.$row_gehalt['lohnart'];
				echo "\nGehaltstyp unbekannt Lohnart: ".$row_gehalt['lohnart']." -> ROLLBACK";
				$failed = true;
				break;
			}

			// Zulage 12x und Zulage 14x aus der Bezeichnung ermitteln
			if(strstr($row_gehalt['bezeichnung'], '12x'))
			{
				$auszahlungen = 12;
			}

			// Format ist 7.777,77 und wird umformattiert in 7777.77
			$betrag = str_replace('.','', $row_gehalt['betrag']);
			$betrag = str_replace(',','.',$betrag);

			$data = array(
				'dienstverhaeltnis_id' => $dvid,
				'vertragsbestandteil_id' => $vbsid,
				'gehaltstyp_kurzbz' => $typ,
				'von' => $row_gehalt['beginn'],
				'grundbetrag' => $betrag,
				'betrag_valorisiert' => $betrag,
				'anmerkung' => $row_gehalt['bezeichnung'],
				'valorisierung' => true,
				'auszahlungen' => $auszahlungen,
				'insertamum' => date('Y-m-d H:i:s'),
				'insertvon' => 'MigrateSalary',
				'updateamum' => date('Y-m-d H:i:s'),
				'updatevon' => 'MigrateSalary'
			);

			if (isset($row_gehalt['ende']) && $row_gehalt['ende'] != '')
			{
				// Im Ende steht noch der Monatserste des letzten Monats
				// Das muss geaendert werden auf den Monatsletzten oder das Ende des DVs
				$date = new DateTime($row_gehalt['ende']);
				$date->modify('last day of this month');
				$last_day_this_month = $date->format('Y-m-d');

				// Wenn das Dienstverhaeltnis in diesem Monat endet und nicht der Monatsletzte ist,
				// dann muss hier das Ende Datum des DV stehen bzw das Ende
				// oder das Ende des VBS falls die Person in der Monatsmitte Stunden wechselt
				$data['bis'] = $last_day_this_month;

				// Wenn der Vertragsbestandteil endet bevor das Gehalt endet, dann wir das Gehaltsende auf VBS Ende gesetzt
				//echo "Ende des VBS: $vbsbis Ende des Gehalt: ".$data['bis'];
				if ($vbsbis != '' && $vbsbis < $data['bis'])
				{
					$data['bis'] = $vbsbis;
					//echo "Gehalt auf vbs ende gesetzt";
				}
			}

			$ret = $this->GehaltsbestandteilModel->insert($data,
				$this->GehaltsbestandteilModel->getEncryptedColumns()
			);
		}

		if(!$failed)
		{
			$this->db->trans_commit();
		}
		else
		{
			echo "ROLLBACK";
			$this->db->trans_rollback();
		}
	}

	/**
	 * Prueft ob ein AllIn Vertrag vorhanden ist
	 */
	private function _isAllIn($dvid, $datum)
	{
		$db = new DB_Model();

		$qry = "
			SELECT
				*
			FROM
				hr.tbl_vertragsbestandteil
				JOIN hr.tbl_vertragsbestandteil_freitext USING(vertragsbestandteil_id)
			WHERE
				dienstverhaeltnis_id=".$db->escape($dvid)."
				AND vertragsbestandteiltyp_kurzbz='freitext'
				AND ".$db->escape($datum)." BETWEEN von AND COALESCE(bis, '2999-12-31')
				AND freitexttyp_kurzbz='allin'";

		$resultAllIn = $db->execReadOnlyQuery($qry);

		if (hasData($resultAllIn))
			return true;
		else
			return false;
	}

	private function _getVBS($dvid, $datum)
	{
		$db = new DB_Model();

		$qry = "
			SELECT
				*
			FROM
				hr.tbl_vertragsbestandteil
			WHERE
				dienstverhaeltnis_id=".$db->escape($dvid)."
				AND vertragsbestandteiltyp_kurzbz='stunden'
				AND ".$db->escape($datum)." BETWEEN von AND COALESCE(bis, '2999-12-31')";

		$resultVBS = $db->execReadOnlyQuery($qry);

		return $resultVBS;
	}

	/**
	 * Ermittelt den User zu einer SVNR
	 */
	private function _getUser($svnr)
	{
		$db = new DB_Model();

		$qry = "
		SELECT
			mitarbeiter_uid
		FROM
			public.tbl_person
			JOIN public.tbl_benutzer using(person_id)
			JOIN public.tbl_mitarbeiter ON(uid=mitarbeiter_uid)
		WHERE
			tbl_person.svnr = ". $db->escape($svnr)."
			AND EXISTS(
				SELECT
					1
				FROM
					hr.tbl_dienstverhaeltnis
				WHERE
					mitarbeiter_uid=tbl_mitarbeiter.mitarbeiter_uid
					AND oe_kurzbz=". $db->escape($this->OE_DEFAULT)."
			)
		ORDER BY tbl_benutzer.aktiv DESC
		LIMIT 1;
		";

		$result = $db->execReadOnlyQuery($qry);

		if (hasdata($result))
		{
			return $result;
		}
		else
			return error('Kein Benutzer mit DV und SVNR:'.$svnr.' gefunden');
	}
}
