<?php
/**
 * @copyright (c) Kufer Software GmbH, Loisachstrasse 4, D-84453 Mühldorf
 */

class DBWorkBelegung extends DBWork
{
  public $dbanmstat;
  public $dbwteilnehmer;
  public $dbwkurse;
  public $dbwkinder;
  public $dbwBelegungKinder;
  public $expdata;

  protected static $_cache_BelegungCountByKnrArray = array();
  protected static $_cache_Anzahl_TN_Kinder_In_Warteliste = array();
  protected static $_cache_BelegungCountByFpFirma = array();
  protected static $_cache_Anzahlkinder = array();

  public function __construct($pDBTyp = 1, $pNewInstance = false, $pNoDependencies = false)
  {
    parent::__construct($pDBTyp, $pNewInstance);

    if (!$pNoDependencies) {
      $this->dbwteilnehmer = new DBWorkTeilnehmer($this->dbtyp, true);
      $this->dbwkurse = new DBWorkKurse($this->dbtyp, true);
      $this->dbwkinder = new DBWorkKinder($this->dbtyp, true);
      $this->dbwBelegungKinder = new DBWorkBelegung($this->dbtyp, true, true);
      $this->expdata = new ExportadapterDatamoduls();
    }

    $this->select
            = 'b.id, b.knr, b.tnr, b.bearbeiter, b.bearbdatum, b.anm_datum, b.anmeldeart, b.uebern_von, b.uebern_bis, b.uebern_jn, b.eintritt, b.austritt, '
            . 'b.ermgrund, b.erm_grund, b.entgelt, b.bet_offen, b.firma, b.firmabelegid, b.bemerkung, b.bemerk_ext, ' . $this->clob('b.info') . ', b.status_1, b.bank, b.blz, b.konto, b.konto_inh, '
            . 'b.rchg_datum, b.druckzeugnis, b.druckanmeld, b.bfbrfgedr1, b.bfbrfgedr2, b.bfbrfgedr3, b.bfbrfgedr4, b.bfbrfgedr5, b.bfbrfgedr6, '
            . 'b.rchgnr, b.belegnr, b.kassenz, b.zahlart, b.zahlnr, b.status_2, b.pauschal, b.betrag, b.warte_pool, b.teil_real, '
            . 'b.sofortzahl, b.vkz, b.ermproz, b.aufzjn, b.aufztext, b.massnahmennr, b.ratenzahlungjn, b.text1, b.text2, b.text3, b.text4, b.text5, '
            . 'b.text6, b.betrag1, b.betrag2, b.betrag3, b.betrag4, b.betrag5, b.betrag6, b.betrag7, b.betrag8, b.betrag9, b.gebuehrok, b.gebuehrbearb, '
            . 'b.mf_abh, b.mf_bva, b.mf_kostenbef, b.mf_kostenbef_typ, b.mf_einsttest, b.mf_abschtest, b.mf_anwtag1, b.mf_status, b.mf_bestnr, b.mf_fehlstdn, '
            . 'b.mf_fehlstdv, b.mf_fehlstdk, b.mf_abschorient, b.lastschr, b.entgelt, b.bet_offen, b.notenendedat, b.notenendema, b.niveau, b.notenende, b.abwzpid, '
            . 'b.notenende, b.punkte, b.pkt_ok_stat, b.pkt_ok_am, b.pkt_ok_von, b.hotel_info, b.historiekrit1, b.historiekrit2, b.historiekrit3, b.historiekrit4, b.historiekrit5, b.historiekrit6, '
            . 'b.historiekrit7, b.historiekrit8, b.historiekrit9, b.historiekrit10, b.historiekrit11, b.historiekrit12, b.historiekrit13, b.historiekrit14, b.historiekrit15, b.historiekrit16, b.iban, '
            . 'b.bic, b.mf_ok, b.prioanm, b.webinarlink, b.anm_quelle, b.fp_firma, b.bezug, b.bms, b.nuronline, b.info2doz, b.anm_bearbeiter ';
    
  }

  
  public function getNewObject()
  {
    $bel = new Belegung();
    $bel->teilnehmer = new Teilnehmer();
    $bel->kurs = new Kurs();

    return $bel;
  }

  public function getTableName(): string
  {
    return 'belegung';
  }

  
  public static function getDefaultInstance($pDBTyp = 1, $pNewInstance = false, $pNoDependencies = false)
  {
    static $instance = null;
    if (!is_null($instance)) {
      if ($instance->dbwkurse == null) {
        if (!$pNoDependencies 
            || $instance->dbtyp != $pDBTyp) { 
          $instance = new DBWorkBelegung($pDBTyp, $pNewInstance, $pNoDependencies);
        }
      }

      return $instance;
    }
    $instance = new DBWorkBelegung($pDBTyp, $pNewInstance, $pNoDependencies);

    return $instance;
  }

  
  public function getCurrentRow($pRefreshCache = false)
  {
    if (!isset($this->dbanmstat)) {
      $this->dbanmstat = new DBWorkHLStatusKZ($this->dbtyp, true);
      $this->dbanmstat->prepareListcompare();
    }
    $tmp = $this->getNewObject();
    $tmp->id = $this->getDatamodulValue('id');
    $tmp->knr = $this->getDatamodulValue('knr');
    $tmp->tnr = $this->getDatamodulValue('tnr');
    $tmp->bearbeiter = $this->getDatamodulValue('bearbeiter');
    $tmp->bearbdatum = $this->getDatamodulValue('bearbdatum');
    $tmp->anm_datum = $this->getDatamodulValue('anm_datum');
    $tmp->anmeldeart = $this->getDatamodulValue('anmeldeart');
    $tmp->uebern_von = $this->getDatamodulValue('uebern_von');
    $tmp->uebern_bis = $this->getDatamodulValue('uebern_bis');
    $tmp->uebern_jn = $this->getDatamodulValue('uebern_jn');
    $tmp->eintritt = $this->getDatamodulValue('eintritt');
    $tmp->austritt = $this->getDatamodulValue('austritt');
    $tmp->hotel_info = $this->getDatamodulValue('hotel_info');
    $tmp->ermgrund = $this->getDatamodulValue('ermgrund');
    $tmp->erm_grund = $this->getDatamodulValue('erm_grund');
    $tmp->entgelt = $this->getDatamodulValue('entgelt');
    $tmp->bet_offen = $this->getDatamodulValue('bet_offen');
    $tmp->firma = $this->getDatamodulValue('firma');
    $tmp->firmabelegid = $this->getDatamodulValue('firmabelegid');
    $tmp->bemerkung = $this->getDatamodulValue('bemerkung');
    $tmp->bemerk_ext = $this->getDatamodulValue('bemerk_ext'); 
    $tmp->bemerk_ext_default = (!empty($tmp->bemerk_ext)) ? $tmp->bemerk_ext
                               : '- aktuell sind keine Hinweise für Sie angegeben -';
    $tmp->info = $this->getDatamodulValue('info');
    $tmp->status = $this->getDatamodulValue('status_1');
    if ($tmp->status == '' || $tmp->status == ' ') {
      $tmp->status = 'A';
    }

    $tmp->invisibleStatus = $tmp->status;
    $tmp->bank = $this->getDatamodulValue('bank'); 
    $tmp->blz = $this->getDatamodulValue('blz'); 
    $tmp->konto = $this->getDatamodulValue('konto'); 
    $tmp->konto_inh = $this->getDatamodulValue('konto_inh'); 
    $tmp->rchg_datum = $this->getDatamodulValue('rchg_datum'); 
    $tmp->druckzeugnis = $this->getDatamodulValue('druckzeugnis'); 
    $tmp->druckanmeld = $this->getDatamodulValue('druckanmeld'); 
    $tmp->bfbrfgedr1 = $this->getDatamodulValue('bfbrfgedr1'); 
    $tmp->bfbrfgedr2 = $this->getDatamodulValue('bfbrfgedr2'); 
    $tmp->bfbrfgedr3 = $this->getDatamodulValue('bfbrfgedr3'); 
    $tmp->bfbrfgedr4 = $this->getDatamodulValue('bfbrfgedr4'); 
    $tmp->bfbrfgedr5 = $this->getDatamodulValue('bfbrfgedr5'); 
    $tmp->bfbrfgedr6 = $this->getDatamodulValue('bfbrfgedr6'); 
    $tmp->rchgnr = $this->getDatamodulValue('rchgnr'); 
    $tmp->belegnr = $this->getDatamodulValue('belegnr'); 
    $tmp->kassenz = $this->getDatamodulValue('kassenz'); 
    $tmp->zahlart = $this->getDatamodulValue('zahlart'); 
    $tmp->status_lang = $this->dbanmstat->getFieldbyID($tmp->status, 'kennz', 'text');
    $tmp->zahlnr = $this->getDatamodulValue('zahlnr');
    $tmp->status_2 = $this->getDatamodulValue('status_2');
    $tmp->pauschal = $this->getDatamodulValue('pauschal');
    $tmp->betrag = $this->getDatamodulValue('betrag');
    $tmp->warte_pool = $this->getDatamodulValue('warte_pool');
    $tmp->teil_real = $this->getDatamodulValue('teil_real');
    $tmp->sofortzahl = $this->getDatamodulValue('sofortzahl');
    $tmp->vkz = $this->getDatamodulValue('vkz');
    $tmp->ermproz = $this->getDatamodulValue('ermproz');
    $tmp->aufzjn = $this->getDatamodulValue('aufzjn');
    $tmp->aufztext = $this->getDatamodulValue('aufztext');
    $tmp->massnahmennr = $this->getDatamodulValue('massnahmennr');
    $tmp->ratenzahlungjn = $this->getDatamodulValue('ratenzahlungjn');
    $tmp->text1 = $this->getDatamodulValue('text1');
    $tmp->text2 = $this->getDatamodulValue('text2');
    $tmp->text3 = $this->getDatamodulValue('text3');
    $tmp->text4 = $this->getDatamodulValue('text4');
    $tmp->text5 = $this->getDatamodulValue('text5');
    $tmp->text6 = $this->getDatamodulValue('text6');
    $tmp->betrag1 = $this->getDatamodulValue('betrag1');
    $tmp->betrag2 = $this->getDatamodulValue('betrag2');
    $tmp->betrag3 = $this->getDatamodulValue('betrag3');
    $tmp->betrag4 = $this->getDatamodulValue('betrag4');
    $tmp->betrag5 = $this->getDatamodulValue('betrag5');
    $tmp->betrag6 = $this->getDatamodulValue('betrag6');
    $tmp->betrag7 = $this->getDatamodulValue('betrag7');
    $tmp->betrag8 = $this->getDatamodulValue('betrag8');
    $tmp->betrag9 = $this->getDatamodulValue('betrag9');
    $tmp->gebuehrok = $this->getDatamodulValue('gebuehrok');
    $tmp->gebuehrbearb = $this->getDatamodulValue('gebuehrbearb');
    $tmp->mf_ok = $this->getDatamodulValue('mf_ok');
    $tmp->mf_abh = $this->getDatamodulValue('mf_abh');
    $tmp->mf_bva = $this->getDatamodulValue('mf_bva');
    $tmp->mf_kostenbef = $this->getDatamodulValue('mf_kostenbef');
    $tmp->mf_kostenbef_typ = $this->getDatamodulValue('mf_kostenbef_typ');
    $tmp->mf_einsttest = $this->getDatamodulValue('mf_einsttest');
    $tmp->mf_abschtest = $this->getDatamodulValue('mf_abschtest');
    $tmp->mf_anwtag1 = $this->getDatamodulValue('mf_anwtag1');
    $tmp->mf_status = $this->getDatamodulValue('mf_status');
    $tmp->mf_bestnr = $this->getDatamodulValue('mf_bestnr');
    $tmp->mf_fehlstdn = $this->getDatamodulValue('mf_fehlstdn');
    $tmp->mf_fehlstdv = $this->getDatamodulValue('mf_fehlstdv');
    $tmp->mf_fehlstdk = $this->getDatamodulValue('mf_fehlstdk');
    $tmp->mf_abschorient = $this->getDatamodulValue('mf_abschorient');
    $tmp->lastschr = $this->getDatamodulValue('lastschr');
    $tmp->bezahlt = $this->mathop->floatToString($this->mathop->stringToFloat($this->getDatamodulValue('entgelt')) - $this->mathop->stringToFloat($this->getDatamodulValue('bet_offen')));


    $tmp->notenendedat = $this->getDatamodulValue('notenendedat');
    $tmp->notenendema = $this->getDatamodulValue('notenendema');
    $tmp->niveau = $this->getDatamodulValue('niveau');
    $tmp->notenende = $this->getDatamodulValue('notenende') == 'W' ? 'W' : 'F';

    $tmp->historiekrit1 = $this->getDatamodulValue('historiekrit1');
    $tmp->historiekrit2 = $this->getDatamodulValue('historiekrit2');
    $tmp->historiekrit3 = $this->getDatamodulValue('historiekrit3');
    $tmp->historiekrit4 = $this->getDatamodulValue('historiekrit4');
    $tmp->historiekrit5 = $this->getDatamodulValue('historiekrit5');
    $tmp->historiekrit6 = $this->getDatamodulValue('historiekrit6');
    $tmp->historiekrit7 = $this->getDatamodulValue('historiekrit7');
    $tmp->historiekrit8 = $this->getDatamodulValue('historiekrit8');
    $tmp->historiekrit9 = $this->getDatamodulValue('historiekrit9');
    $tmp->historiekrit10 = $this->getDatamodulValue('historiekrit10');
    $tmp->historiekrit11 = $this->getDatamodulValue('historiekrit11');
    $tmp->historiekrit12 = $this->getDatamodulValue('historiekrit12');
    $tmp->historiekrit13 = $this->getDatamodulValue('historiekrit13');
    $tmp->historiekrit14 = $this->getDatamodulValue('historiekrit14');
    $tmp->historiekrit15 = $this->getDatamodulValue('historiekrit15');
    $tmp->historiekrit16 = $this->getDatamodulValue('historiekrit16');

    $tmp->abwzpid = $this->getDatamodulValue('abwzpid');

    $tmp->iban = $this->getDatamodulValue('iban');
    $tmp->bic = $this->getDatamodulValue('bic');

    $tmp->prioanm = $this->getDatamodulValue('prioanm');
    $tmp->webinarlink = $this->getDatamodulValue('webinarlink');
    $tmp->anm_quelle = $this->getDatamodulValue('anm_quelle');
    $tmp->fp_firma = $this->getDatamodulValue('fp_firma');
    $tmp->bezug = $this->getDatamodulValue('bezug');
    $tmp->bms = $this->getDatamodulValue('bms');
    $tmp->nuronline = $this->getDatamodulValue('nuronline');
    $tmp->info2doz = $this->getDatamodulValue('info2doz');

    
    
    if (!in_array($tmp->status, array('A', 'T', 'P', '', ' ')) && isset($this->dbwteilnehmer)) {
      static $dbwBel2 = null;
      if ($dbwBel2 == null) {
        $dbwBel2 = new DBWorkBelegung($this->dbtyp, true);
      }

      $toolSettings = ToolSettingsAPI::getToolSettings(\ToolsAPI::TOOL_KURSUEBERSICHT_FA);
      $tnStatus = "'A','T',' ',''";
      if ($toolSettings->tnstatus != '') {
        $tnStatus = $toolSettings->tnstatus;
        $tnStatus = str_replace('P', '', $tnStatus);
        $tnStatus = StringOperations::convertArray2InList(\StringOperations::str_split($tnStatus));
        $tnStatus = str_replace('-', ' ', $tnStatus);
        if (StringOperations::strpos($tnStatus, 'A') !== false) {
          $tnStatus .= ", ''";
        }
      }

      $tmp->anzahl_ma_firma = $dbwBel2->getBelegungsCountbyKursFirmaTeilnehmerNrWithStatus($tmp->knr, $tmp->tnr, $tnStatus);
      $tmp->anzahl_ma_firma_platzreserv
                              = $dbwBel2->getBelegungsCountbyKursFirmaTeilnehmerNrWithStatus($tmp->knr, $tmp->tnr, '\'P\'');
    
    
    
    } else {
      $tmp->anzahl_ma_firma = 0;
      $tmp->anzahl_ma_firma_platzreserv = 0;
    }
    
    $tmp->punkte = $this->getDatamodulValue('punkte');
    $tmp->pkt_ok_stat = $this->getDatamodulValue('pkt_ok_stat');
    $tmp->pkt_ok_am = $this->getDatamodulValue('pkt_ok_am');
    $tmp->pkt_ok_von = $this->getDatamodulValue('pkt_ok_von');

    if (isset($this->dbwkinder)) {
      $this->expdata->datamoduls = static::getKinderForBelegung($tmp, $this->dbwteilnehmer, $this->dbwBelegungKinder, $this->dbwkinder);
      if (!empty($this->expdata->datamoduls)) {
        $this->expdata->filestream = '{%vorname%} {%name%} ({%gebdat%})';
        $this->expdata->replaceVarNames();
        $tmp->kinder_alle = implode('<br>', $this->expdata->resultlist);
        $tmp->kinderanzahl = count($this->expdata->resultlist);

        $datamodulErstesKind = $this->expdata->datamoduls[0];
        $tmp->erstesKind_Name = $datamodulErstesKind->getVarValue('name');
        $tmp->erstesKind_Vorname = $datamodulErstesKind->getVarValue('vorname');
        $tmp->erstesKind_Name_Vorname = $datamodulErstesKind->getVarValue('namevorname');
        $tmp->erstesKind_Name_Vorname_ohneKomma = $datamodulErstesKind->getVarValue('name_vorname_ohne_komma');
        $tmp->erstesKind_Vorname_Name_ohneKomma = $datamodulErstesKind->getVarValue('vorname_name_ohne_komma');
        $tmp->erstesKind_gebdat = $datamodulErstesKind->gebdat;
        
        if (count($this->expdata->datamoduls) > 1) {
          $datamodulZweitesKind = $this->expdata->datamoduls[1];
          $tmp->zweitesKind_Name = $datamodulZweitesKind->getVarValue('name');
          $tmp->zweitesKind_Vorname = $datamodulZweitesKind->getVarValue('vorname');
          $tmp->zweitesKind_Name_Vorname = $datamodulZweitesKind->getVarValue('namevorname');
          $tmp->zweitesKind_Name_Vorname_ohneKomma = $datamodulZweitesKind->getVarValue('name_vorname_ohne_komma');
          $tmp->zweitesKind_Vorname_Name_ohneKomma = $datamodulZweitesKind->getVarValue('vorname_name_ohne_komma');
          $tmp->zweitesKind_gebdat = $datamodulZweitesKind->gebdat;
        }
      }
    }

    $tmp->anm_bearbeiter = $this->getDatamodulValue('anm_bearbeiter');

    return $tmp;
  }

  
  public static function getKinderForBelegung(
    \Belegung $tmp,
    \DBWorkTeilnehmer $dbwTeilnehmer,
    \DBWorkBelegung $dbwBelegungKinder,
    \DBWorkKinder $dbwKinder
  ): array {
    if (System::isKuferSql5()) {
      $kindBelegungen = $dbwBelegungKinder->getKindBelgungenByTnrAndKnr($tmp->tnr, $tmp->knr);
      if (!empty($kindBelegungen)) {
        $kindBelegIds = array_map(function($kindBelegung) {
          return $kindBelegung->id;
        }, $kindBelegungen);

        return $dbwTeilnehmer->getTeilnehmerByBelegAry($kindBelegIds);
      }

      return array();
    } else {
      return $dbwKinder->getKinderbyBelegung($tmp->id);
    }
  }

  protected function postGetAllRowsHook($pDatamodules, $pRefreshCache = false)
  {
    $datamodules = parent::postGetAllRowsHook($pDatamodules, $pRefreshCache);

    
    $kurseByKnr = array();
    if (isset($this->dbwkurse)) {
      $kursnummern = ArrayOperations::mapAttribut($datamodules, 'knr');
      $kurse = $this->dbwkurse->getKurseByKursnummernKeepOrder($kursnummern, $pRefreshCache);
      $kurseByKnr = ArrayOperations::setAttributAsKey($kurse, 'id');
    }

    $teilnehmerByTnr = array();
    if (isset($this->dbwteilnehmer)) {
      $tnNummern = ArrayOperations::mapAttribut($datamodules, 'tnr');
      
      $tnNummern = array_filter($tnNummern, function($tnr) {return CleanOperations::isInt($tnr);});
      $teilnehmer = $this->dbwteilnehmer->getTeilnehmByIdArray($tnNummern);
      $teilnehmerByTnr = ArrayOperations::setAttributAsKey($teilnehmer, 'id');
    }

    foreach ($datamodules as $key => $belegung) {
      if (isset($kurseByKnr[$belegung->knr])) {
        $datamodules[$key]->kurs = $kurseByKnr[$belegung->knr];
      } else {
        $datamodules[$key]->kurs = null;
      }

      if (isset($teilnehmerByTnr[$belegung->tnr])) {
        $datamodules[$key]->teilnehmer = $teilnehmerByTnr[$belegung->tnr];
        if (trim($datamodules[$key]->teilnehmer->namevorname) === '') {
          $datamodules[$key]->teilnehmer->namevorname = 'Daten nicht im Web';
        }
        $datamodules[$key]->tn_namevorname_hauptteilnehmer = $datamodules[$key]->teilnehmer->namevorname;
        
        
        if (is_numeric($datamodules[$key]->firma) && $datamodules[$key]->firma > 0 && $datamodules[$key]->firma != $datamodules[$key]->tnr) {
          $haupttn = $this->dbwteilnehmer->getTeilnehm($datamodules[$key]->firma);
          $datamodules[$key]->tn_namevorname_hauptteilnehmer .= ' (' . $haupttn->namevorname . ')';

          
          
          $datamodules[$key]->tn_iban_hauptteilnehmer = $haupttn->iban;
          
          
          $datamodules[$key]->tn_mandatam_hauptteilnehmer = $haupttn->getVarValue('mandatam');
        }
      } else {
        $datamodules[$key]->teilnehmer = new Teilnehmer();
        $datamodules[$key]->teilnehmer->namevorname = 'Daten nicht im Web';
        $datamodules[$key]->tn_namevorname_hauptteilnehmer = $datamodules[$key]->teilnehmer->namevorname;
      }

      $datamodules[$key]->zahlungshinweis = $this->_getZahlungshinweis($datamodules[$key]);
    }

    return $datamodules;
  }

  
  private function _getZahlungshinweis($pBelegungsObj)
  {
    
    
    if ($this->mathop->stringToFloat($pBelegungsObj->entgelt) == 0) {
      
      if (in_array($pBelegungsObj->status, array('T', 'A', 'F'))) {
        return 'Dieser Kurs ist für Sie kostenlos.';
      } else {
        return 'Es sind noch keine Kursgebühren für Sie fällig.';
      }
    }
    
    elseif ($this->mathop->stringToFloat($pBelegungsObj->bet_offen) == 0) {
      return 'Wir haben die von Ihnen entrichtete Gebühr für diesen Kurs erhalten. Vielen Dank.';
    }
    
    elseif ($this->mathop->stringToFloat($pBelegungsObj->bet_offen) < 0) {
      
      return 'Rückerstattung erfolgt.';
    }
    
    elseif ($this->mathop->stringToFloat($pBelegungsObj->bezahlt) != 0) {
      if (DBWorkBASysSettings::isBlak()) {
        return 'Ihr Guthaben für den Kurs wurde angerechnet. Der Bankeinzug der restlichen Gebühr erfolgt zeitnah.';
      } else {
        return 'Wir haben Ihre Anzahlung zu diesem Kurs erhalten. Bitte entrichten Sie baldmöglichst die restliche Kursgebühr.';
      }
    }

    
    
    
    switch ($pBelegungsObj->zahlart) {
      
      case 'R':
        
        if (DateTimeOperations::isDateTimeEmptyOrDefault($pBelegungsObj->rchg_datum)) {
          return 'Es wurde Ihnen für diesen Kurs noch keine Rechnung versandt.';
        }
        
        else {
          return 'Die Rechnung für diesen Kurs wurde an Sie am ' . $pBelegungsObj->rchg_datum . ' versandt.';
        }
        
        
      case 'E':
        
        return 'Rückerstattung erfolgt.';
        
      case '':
      case ' ':
        
        if (!empty($pBelegungsObj->teilnehmer->konto) || !empty($pBelegungsObj->teilnehmer->iban)) {
          return 'Der Betrag wird per Lastschrift von Ihrem Konto eingezogen.';
        }

        
        

        
        
      case 'Ü':
      case 'G':
      default:
        return 'Bitte überweisen Sie die Gebühr dieses Kurses auf das Konto der Einrichtung';
    }
  }

  public function canupdate($varname)
  {
    switch ($varname) {
      default: return DBWork::canupdate($varname);
      case 'status_lang':
      case 'kurs':
      case 'teilnehmer':
      case 'kinder_alle':
      case 'kinderanzahl':
      case 'kindernamen':
      case 'bezahlt':
      case 'anzahl_ma_firma':
      case 'anzahl_weitereTn':
      case 'anzahl_ma_firma_platzreserv':
      case 'liste_ma_firma':
      case 'bemerk_ext_default':
      case 'invisibleStatus':
      case 'punkte':
      case 'entgelt_je_mitarbeiter':
      case 'tn_namevorname_hauptteilnehmer':
      case 'tn_iban_hauptteilnehmer':
      case 'tn_mandatam_hauptteilnehmer':
      case 'erstesKind_Name':
      case 'erstesKind_Vorname':
      case 'erstesKind_Name_Vorname':
      case 'erstesKind_Name_Vorname_ohneKomma':
      case 'erstesKind_Vorname_Name_ohneKomma':
      case 'erstesKind_gebdat':
      case 'zweitesKind_Name':
      case 'zweitesKind_Vorname':
      case 'zweitesKind_Name_Vorname':
      case 'zweitesKind_Name_Vorname_ohneKomma':
      case 'zweitesKind_Vorname_Name_ohneKomma':
      case 'zweitesKind_gebdat':
      case 'zahlungshinweis':
        return false;
    }
  }

  
  public function translateVarName($varname)
  {
    switch ($varname) {
      default: return DBWork::translateVarName($varname);
      case 'status': return 'status_1';
    }
  }

  public function getAllQuery(): SelectQueryBuilder
  {
    return $this->getSelectQueryBuilder()
        ->select($this->select)
        ->from('belegung', 'b')
        ->paramRaw('table', 'b');
  }

  public function getAllQueryWithTeilnehmerAndKurse(): \SelectQueryBuilder
  {
    return $this->getAllQuery()
      ->leftJoin('teilnehm t', 'b.tnr = t.nr')
      ->leftJoin('kurse k', 'b.knr = k.nr');
  }

  
  public static function getSearchSQL4TNStatus($praeffix, $tnstatus, bool $not = false)
  {
    $statusAry = array();
    $status = \StringOperations::str_split($tnstatus);
    foreach ($status as $char) {
      
      if ($char == '-') {
        continue;
      } elseif ($char == 'A') {
        $statusAry[] = 'A';
        $statusAry[] = '';
        $statusAry[] = ' ';
      } else {
        $statusAry[] = "$char";
      }
    }

    return ' AND ' . ($not ? 'NOT ' : '') . $praeffix . 'status_1 in (' . \StringOperations::convertArray2InList($statusAry) . ") \n ";
  }

  
  public function getSearchSQL($pPraeffix, $pPraeffixTn = 't.')
  {
    $praeffix = $this->dboperation->getString4Sql($pPraeffix);
    $praeffixTn = $this->dboperation->getString4Sql($pPraeffixTn);
    $sql = '';
    if ((isset($this->fromobject)) and (isset($this->toobject))) { 
      if (!empty($this->fromobject->status)) {
        $sql .= DBWorkBelegung::getSearchSQL4TNStatus($praeffix, $this->fromobject->status);
      }
      if (!empty($this->toobject->status)) {
        $sql .= DBWorkBelegung::getSearchSQL4TNStatus($praeffix, $this->toobject->status, true);
      }
      if (!empty($this->fromobject->anm_datum) && !empty($this->toobject->anm_datum)) {
        $datumVon = $this->datetimeop->getFormatDate4Server($this->fromobject->anm_datum);
        $datumBis = $this->datetimeop->getFormatDate4Server($this->toobject->anm_datum);
        $sql .= ' AND ' . $praeffix . 'anm_datum >= ' . $datumVon . ' AND ' . $praeffix . 'anm_datum <= ' . $datumBis . " \n ";
      }

      
      
      if (isset($this->fromobject->teilnehmer->name, $this->toobject->teilnehmer->name)
          && (trim($this->fromobject->teilnehmer->name) != '') && (trim($this->toobject->teilnehmer->name) != '')) {
        $sql .= ' AND ' . $this->dboperation->dbparser->caseInsensitiveCompOperation('>=', '', 'name', $this->fromobject->teilnehmer->name);
        $sql .= ' AND ' . $this->dboperation->dbparser->caseInsensitiveCompOperation('<=', '', 'name', $this->toobject->teilnehmer->name);
      } else {
        if (isset($this->fromobject->teilnehmer->name) && trim($this->fromobject->teilnehmer->name) != '') {
          $sql .= ' AND ' . $this->dboperation->dbparser->caseInsensitiveCompOperation('>=', '', 'name', $this->fromobject->teilnehmer->name);
        }
      }

      if (isset($this->fromobject->firma) && $this->fromobject->firma > 0) {
        $sql .= ' AND firma = ' . $this->fromobject->firma . ' ';
      }

      
      if (isset($this->fromobject->teilnehmer->email)) {
        $sql .= ' AND ' . $this->dboperation->dbparser->caseInsensitiveLike($praeffixTn, 'email_anzeige', $this->fromobject->teilnehmer->email) . ' ';
      }

      if (isset($this->fromobject->teilnehmer->mobil)) {
        $sql .= ' AND ' . $this->dboperation->dbparser->caseInsensitiveLike($praeffixTn, 'mobil_anzeige', $this->fromobject->teilnehmer->mobil) . ' ';
      }
      if (isset($this->fromobject->teilnehmer->telMobil)) {
        $operator = ' OR ';
        if ($this->fromobject->teilnehmer->tel === '' && $this->fromobject->teilnehmer->mobil === '') {
          $operator = ' AND ';
        }
        $sql .= ' AND (' . $this->dboperation->dbparser->caseInsensitiveLike($praeffixTn, 'tel_anzeige', $this->fromobject->teilnehmer->tel)
                . $operator . $this->dboperation->dbparser->caseInsensitiveLike($praeffixTn, 'tel2_anzeige', $this->fromobject->teilnehmer->tel2)
                . $operator . $this->dboperation->dbparser->caseInsensitiveLike($praeffixTn, 'mobil_anzeige', $this->fromobject->teilnehmer->mobil) . ') ';
      } elseif (isset($this->fromobject->teilnehmer->tel)) {
        $operator = ' OR ';
        if ($this->fromobject->teilnehmer->tel === '') {
          $operator = ' AND ';
        }
        $sql .= ' AND (' . $this->dboperation->dbparser->caseInsensitiveLike($praeffixTn, 'tel_anzeige', $this->fromobject->teilnehmer->tel)
                . $operator . $this->dboperation->dbparser->caseInsensitiveLike($praeffixTn, 'tel2_anzeige', $this->fromobject->teilnehmer->tel2) . ') ';
      }

      if (\DBWorkBASysSettings::isBlak() && isset($this->fromobject->kurs->other_kriterien) && $this->fromobject->kurs->other_kriterien != '') {
        switch ($this->fromobject->kurs->other_kriterien) {
          case 'infuture':
            $sql .= ' AND (' . $this->getSelectQueryBuilder()
                ->andExpr(function(\SelectQueryBuilder $builder) : SelectQueryBuilder {
                  return $builder
                    ->and('k.beginn_dat >= :datenow:')
                    ->addToWhere($this->dbwkurse->getSQLSpecialKursebyFlagsInKursId(array('E', 'L'), 'blak_kriterien', true));
                })
                ->orExpr(function(\SelectQueryBuilder $builder) use ($praeffix): \SelectQueryBuilder {
                  return $builder
                    ->addToWhere($praeffix . 'status_1 != \'T\'')
                    ->addToWhere($this->dbwkurse->getSQLSpecialKursebyFlagsInKursId(array('E', 'L'), 'blak_kriterien'));
                })
                ->getSQLCondition() . ')';

            break;
          case 'inpast':
            $sql .= ' AND (' . $this->getSelectQueryBuilder()
                ->andExpr(function(\SelectQueryBuilder $builder) : SelectQueryBuilder {
                  return $builder
                    ->and('k.ende_dat < :datenow:')
                    ->addToWhere($this->dbwkurse->getSQLSpecialKursebyFlagsInKursId(array('E', 'L'), 'blak_kriterien', true));
                })
                ->orExpr(function(\SelectQueryBuilder $builder) use ($praeffix): \SelectQueryBuilder {
                  return $builder
                    ->addToWhere($praeffix . 'status_1 = \'T\'')
                    ->addToWhere($this->dbwkurse->getSQLSpecialKursebyFlagsInKursId(array('E', 'L'), 'blak_kriterien'));
                })
              ->getSQLCondition() . ')';

            break;
        }
      }

      $this->dbwkurse->newSearch();
      if (\DBWorkBASysSettings::isBlak()) {
        $otherKriterien = $this->fromobject->kurs->other_kriterien ?? null;
      }
      $this->dbwkurse->fromobject = $this->fromobject->kurs;
      $this->dbwkurse->toobject = $this->toobject->kurs;
      if (\DBWorkBASysSettings::isBlak()) {
        $this->dbwkurse->fromobject->other_kriterien = ''; 
      }
      $sql .= ' ' . $this->dbwkurse->getSearchSQL('k.') . ' ';
      if (\DBWorkBASysSettings::isBlak()) {
        assert(isset($otherKriterien));
        $this->fromobject->kurs->other_kriterien = $otherKriterien;
      }
    }

    return $sql;
  }

  
  public function getBelegung($pBelegId, $pRefreshCache = false)
  {
    $belegId = $this->dboperation->getInt4Sql($pBelegId);

    static $cache = array();
    if (!isset($cache[$belegId]) || $pRefreshCache) {
      $this->dboperation->clear();
      $sql = 'SELECT ' . $this->select . ' FROM belegung b '
             . ' LEFT JOIN teilnehm t ON(b.tnr=t.nr) '
             . ' LEFT JOIN kurse k ON(b.knr=k.nr) '
             . ' WHERE b.id = ' . $belegId;
      $this->dboperation->query($sql);
      $cache[$belegId] = $this->getFirstRow();
    }

    return clone $cache[$belegId];
  }

  
  public function getBelegungenByIds($pIds, bool $pBeruecksichtigeSuche = false)
  {
    if (!is_array($pIds)) {
      throw new InvalidArgumentExceptionExtended('$pIds', $pIds, 'Der Parameter $pIds muss ein Array sein.');
    }

    if (empty($pIds)) {
      return array();
    }

    foreach ($pIds as &$val) {
      $val = (int)$val;
    }

    
    $builder = $this->getAllQueryWithTeilnehmerAndKurse()
      ->and('b.id IN (:belIds:)')
      ->paramIntArray('belIds', $pIds)
      ->orderBySrcCode($this->getCompleteOrderByDefault('b.id'));

    if ($pBeruecksichtigeSuche) {
      $builder = $builder->and($this->getSearchSQL('b.'));
    }

    $this->dboperation->clear();
    $this->dboperation->query($builder->getSQL());

    return $this->getAllRows();
  }

  public function findByFilterQuery(\Kufer\Web\Classes\Dbfilter\BelegungenSQLFilter $filter): \SelectQueryBuilder
  {
    $cond = $filter->createSql($this->dboperation);

    return $this->getAllQuery()
      ->and($cond);
  }

  
  public function findByFilter(\Kufer\Web\Classes\Dbfilter\BelegungenSQLFilter $filter): array
  {
    $builder = $this->findByFilterQuery($filter);

    $this->dboperation->clear();
    $this->dboperation->query($builder->getSQL());

    return $this->getAllRows();
  }

  
  public function findIdsByFilter(\Kufer\Web\Classes\Dbfilter\BelegungenSQLFilter $filter): array
  {
    $builder = $this->findByFilterQuery($filter)
      ->select(':table:.id');

    $this->dboperation->clear();
    $this->dboperation->query($builder->getSQL());

    return $this->getAllRowsSingleColumn('id');
  }

  
  public function countByFilter(\Kufer\Web\Classes\Dbfilter\BelegungenSQLFilter $filter): int
  {
    $builder = $this->findByFilterQuery($filter)
      ->select('COUNT(*) as anzahl');

    $this->dboperation->clear();
    $this->dboperation->query($builder->getSQLForInnerQuery());

    $this->dboperation->selectrow(0);

    return (int)$this->getValue('anzahl', \DatamodulVarType::TYPE_INT);
  }

  
  public function getBelegungenbyTeilnehmerNRLimit($pUser_Id, $start_belegung, $limit = 0, $forward = true, $pOhneStornoStatus = false, $pNotBuildSeitenIndexAry = false)
  {
    $sqlstr = 'SELECT ' . $this->select . ' FROM belegung b LEFT JOIN teilnehm t ON(b.tnr=t.nr)
                             LEFT JOIN kurse k ON(b.knr=k.nr) ';
    if (!$this->admin) {
      $user_id = $this->dboperation->getInt4Sql($pUser_Id);
      $sqlstr .= '  INNER JOIN web_users wu ON (b.tnr=wu.tnr AND wu.id=' . $user_id . ") \n ";
    }

    
    $sqlstr .= 'LEFT OUTER JOIN kurse_aa kaa on k.nr=kaa.nr ';

    $sqlstr .= "  WHERE 1=1 \n" . $this->getSearchSQL('b.');

    
    if ($pOhneStornoStatus) {
      $sqlstr .= " AND b.status_1 not in ('S','Z') ";
    }

    
    
    
    
    
    
    
    
    

    $sqlstr .= $this->getCompleteOrderByDefault('b.id');
    if ($this->getOrderbyDefault('b.id') != 'b.id') {
      $sqlstr .= ', b.id';
    }
    $this->dboperation->clear();
    $this->dboperation->query($sqlstr);

    
    
    
    if (! $pNotBuildSeitenIndexAry) {
      $this->_buildSeitenIndexAry($this->dboperation->rowcount(), $limit);
    }
    if (!empty($start_belegung) && $start_belegung->id != '') {
      return $this->getLimitRows($limit, $forward, 'id', $start_belegung->id);
    } else {
      return $this->getLimitRows($limit, $forward);
    }
  }

  
  public function getKursNrFromBelegungNrAryAndKursFilterQuery($belegungNrAry, $dbwKurse): SelectQueryBuilder
  {
    $builder = $this->getKursNrFromBelegungNrAryQuery($belegungNrAry);

    return $builder->addToWhere($dbwKurse->getSearchSQL('k.'));
  }

  
  public function getKursNrFromBelegungNrAryAndKursFilter($belegungNrAry, $dbwKurse): array
  {
    $builder = $this->getKursNrFromBelegungNrAryAndKursFilterQuery($belegungNrAry, $dbwKurse);
    $this->dboperation->clear();
    $this->dboperation->query($builder->getSQL());

    return $this->getAllRowsSingleColumn('knr');
  }

  
  public function getKursNrFromBelegungNrAryQuery($belegungNrAry): SelectQueryBuilder
  {
    $builder = $this->getSelectQueryBuilder()
        ->select('DISTINCT(b.knr)')
        ->from('belegung', 'b')
        ->leftJoin('teilnehm t', 'b.tnr = t.nr')
        ->leftJoin('kurse k', 'b.knr = k.nr')
        ->join('kurse_aa kaa', 'kaa.nr = knr');

    if (empty($belegungNrAry)) {
      return $builder->and('1 = 0');
    }

    return $builder
        ->and('b.id IN (:belegungen:)')
        ->addToWhere($this->getSearchSQL('b.'))
        ->paramStringArray('belegungen', $belegungNrAry);
  }

  
  public function getKursNrFromBelegungNrAry($belegungNrAry)
  {
    $builder = $this->getKursNrFromBelegungNrAryQuery($belegungNrAry);
    $this->dboperation->clear();
    $this->dboperation->query($builder->getSQL());

    return $this->getAllRowsSingleColumn('knr');
  }

  
  public function getKursNrWhereFirmaAngemeldet($pKnrAry, $pFirma)
  {
    if (empty($pKnrAry)) {
      return array();
    }
    $knrIn = " IN ('" . implode("', '", $this->dboperation->getStrings4Sql($pKnrAry)) . "') ";

    $cleanFirma = $this->dboperation->getInt4Sql($pFirma);

    $sql = 'SELECT DISTINCT(b.knr) FROM belegung b WHERE (b.firma = ' . $cleanFirma . ' OR b.tnr = ' . $cleanFirma . ') AND b.knr ' . $knrIn . ' '
                             . 'AND (b.status_1 IN (' . ConstantOperations::getStatusangemeldetMitFirmaSQLStr() . ') OR b.status_1 IS NULL) ';

    $this->dboperation->clear();
    $this->dboperation->query($sql);

    return $this->getAllRowsSingleColumn('knr');
  }

  
  public function getBelegungCountTotalbyTeilnehmerNR($pUser_Id)
  {
    $sqlstr = "SELECT count(*) as anzahl FROM belegung b LEFT JOIN teilnehm t ON(b.tnr=t.nr) \n
                               LEFT JOIN kurse k ON(b.knr=k.nr) \n";
    if (!$this->admin) {
      $user_id = $this->dboperation->getInt4Sql($pUser_Id);
      $sqlstr .= '  INNER JOIN web_users wu ON (b.tnr=wu.tnr AND wu.id=' . $user_id . ") \n ";
    }
    $sqlstr .= "  WHERE 1=1 \n" . $this->getSearchSQL('b.');

    $this->dboperation->clear();
    $this->dboperation->query($sqlstr);
    $this->dboperation->selectrow(0);

    return $this->getDatamodulValue('anzahl');
  }

  
  public function getBelegungenbyTeilnehmerNR($pTeilnehmer_Id, array $pNurStatus = array())
  {
    return $this->getBelegungenbyTeilnehmerNrArray(array($pTeilnehmer_Id), $pNurStatus);
  }

  
  public function getBelegungenIdsByTeilnehmerId($pTeilnehmer_Id, array $pNurStatus = array())
  {
    $query = $this->getBelegungenByTeilnehmerIdsArrayQuery(array($pTeilnehmer_Id), $pNurStatus)
      ->select('b.id');

    $this->dboperation->clear();
    $this->dboperation->query($query->getSQL());

    return $this->getAllRowsSingleColumn('id');
  }

  
  public function getBelegungByTeilnehmerIdAndKurs(string $knr, $tnId, array $pNurStatus = array()): \Belegung
  {
    $query = $this->getBelegungenByTeilnehmerIdsArrayQuery(array($tnId), $pNurStatus)
      ->and('k.nr = :knr:')
      ->paramString('knr', $knr);

    $this->dboperation->clear();
    $this->dboperation->query($query->getSQLForInnerQuery());

    return $this->getFirstRow();
  }

  
  public function hasBelegungenByTeilnehmerIdAndKurs(string $knr, $pTeilnehmer_Id, array $pNurStatus = array()): bool
  {
    $query = $this->getBelegungenByTeilnehmerIdsArrayQuery(array($pTeilnehmer_Id), $pNurStatus)
      ->select('COUNT(*) AS anzahl')
      ->and('k.nr = :knr:')
      ->paramString('knr', $knr);

    $this->dboperation->clear();
    $this->dboperation->query($query->getSQLForInnerQuery());

    $this->dboperation->selectNextRow();

    return $this->getValue('anzahl', \DatamodulVarType::TYPE_INT) > 0;
  }

  
  public function getBelegungenByTeilnehmerIdsArrayQuery($pTeilnehmerIdArr, array $pNurStatus = array()): \SelectQueryBuilder
  {
    $builder = $this->getAllQuery()
      ->leftJoin('teilnehm t', 'b.tnr = t.nr')
      ->leftJoin('kurse k', 'b.knr = k.nr')
      ->leftOuterJoin('kurse_aa kaa', 'b.knr = kaa.nr');

    $tnIds = array_map(static function($id) {
      return $id instanceof \Kufer\Web\Classes\Identifier\Identifier ? $id->getId() : $id;
    }, $pTeilnehmerIdArr);

    $varIdAry = $builder->uniqueVar();
    $builder = $builder
      ->and("b.tnr IN (:$varIdAry:)")
      ->paramIntArray($varIdAry, $tnIds);

    if (!empty($pNurStatus)) {
      $statusVar = $builder->uniqueVar();
      $builder = $builder
        ->and("b.status_1 IN (:$statusVar:)")
        ->paramStringArray($statusVar, $pNurStatus);
    }

    return $builder
      ->addToWhere($this->getSearchSQL('b.'))
      ->orderBySrcCode($this->getCompleteOrderByDefault('b.id'));
  }

  
  public function getBelegungenbyTeilnehmerNrArray($pTeilnehmerIdArr, array $pNurStatus = array())
  {
    if (empty($pTeilnehmerIdArr)) {
      return array();
    }

    $builder = $this->getBelegungenByTeilnehmerIdsArrayQuery($pTeilnehmerIdArr, $pNurStatus);

    $this->dboperation->clear();
    $this->dboperation->query($builder->getSQL());

    return $this->getAllRows();
  }

  public function getBelegungsIdsByTeilnehmerNrArray($pTeilnehmerIdArr, array $pNurStatus = array())
  {
    if (empty($pTeilnehmerIdArr)) {
      return array();
    }

    $builder = $this->getBelegungenByTeilnehmerIdsArrayQuery($pTeilnehmerIdArr, $pNurStatus);
    $builder->select('b.id');

    $this->dboperation->clear();
    $this->dboperation->query($builder->getSQL());

    return $this->getAllRowsSingleColumn('id');
  }

  public function getAbwZahlerBelegungsIdsForTeilnehmer($pTeilnehmer_Id)
  {
    $teilnehmer_id = $this->dboperation->getInt4Sql($pTeilnehmer_Id);
    if (System::isKuferSql5()) {
      $sql = 'SELECT b.id FROM belegung b LEFT JOIN zahlung z ON(z.belegid=b.id) '
           . 'LEFT JOIN kurse k ON(b.knr=k.nr) '
           . 'LEFT JOIN kurse_aa kaa on k.nr=kaa.nr ' . " \n "
           . 'WHERE z.ZPF = ' . $teilnehmer_id . ' AND b.tnr != ' . $teilnehmer_id . ' '
           . $this->getSearchSQL('b.')
           . $this->getCompleteOrderByDefault('b.id');
    } else {
      $sql = 'SELECT b.id FROM belegung b LEFT JOIN teilnehm t ON(b.tnr=t.nr) '
           . 'LEFT JOIN kurse k ON(b.knr=k.nr) '
           . 'LEFT JOIN kurse_aa kaa on k.nr=kaa.nr ' . " \n "
           . 'WHERE b.KontoInh LIKE \'(%' . $teilnehmer_id . ')\' AND b.tnr != ' . $teilnehmer_id . ' '
           . $this->getSearchSQL('b.')
           . $this->getCompleteOrderByDefault('b.id');
    }
    $this->dboperation->clear();
    $this->dboperation->query($sql);

    $return = $this->getAllRowsSingleColumn('id');
    $this->dboperation->clear();

    return $return;
  }

  
  public function getBelegungsIdsbyTeilnehmerNR($pTeilnehmer_Id)
  {
    if (is_null($pTeilnehmer_Id)) {
      return array();
    }

    $pTeilnehmer_Id = \Kufer\Web\Classes\Identifier\IdentifierFactory::createFromIdIfNecessary($pTeilnehmer_Id);
    if ($pTeilnehmer_Id->isEmpty(true)) {
      return array();
    }

    $teilnehmer_id = $this->dboperation->getInt4Sql($pTeilnehmer_Id->getId());
    $sql = 'SELECT b.id FROM belegung b LEFT JOIN teilnehm t ON(b.tnr=t.nr) '
                                     . 'LEFT JOIN kurse k ON(b.knr=k.nr) '
                                     . 'LEFT JOIN kurse_aa kaa on k.nr=kaa.nr ' . " \n "
                               . 'WHERE b.tnr = ' . $teilnehmer_id . ' ' . $this->getSearchSQL('b.')
                               . $this->getCompleteOrderByDefault('b.id');

    $this->dboperation->clear();
    $this->dboperation->query($sql);
    $return = $this->getAllRowsSingleColumn('id');
    $this->dboperation->clear();

    return $return;
  }

  
  public function getBelegungsIdsbyKursTeilnNR($pTeilnehmerId, $pKursId)
  {
    $teilnehmerId = $this->dboperation->getInt4Sql($pTeilnehmerId);
    $kursId = $this->dboperation->getString4Sql($pKursId);
    $sql = 'SELECT b.id FROM belegung b LEFT JOIN teilnehm t ON(b.tnr=t.nr) '
                                     . 'LEFT JOIN kurse k ON(b.knr=k.nr) '
                                     . 'LEFT JOIN kurse_aa kaa on k.nr=kaa.nr ' . " \n "
                               . 'WHERE b.tnr = ' . $teilnehmerId
                               . ' AND b.knr =\'' . $kursId . '\'' . $this->getSearchSQL('b.')
                               . $this->getCompleteOrderByDefault('b.id');

    $this->dboperation->clear();
    $this->dboperation->query($sql);

    $belIdAry = $this->getAllRowsSingleColumn('id');
    $this->dboperation->clear();

    return $belIdAry;
  }

  
  public function getBelegungenByKursIdQuery(string $kursId): \SelectQueryBuilder
  {
    $builder = $this->getAllQuery()
      ->leftJoin('kurse k', 'b.knr=k.nr')
      ->leftOuterJoin('kurse_aa kaa', 'k.nr=kaa.nr')
      ->leftJoin('teilnehm t', 'b.tnr=t.nr')
      ->and('b.knr IS NOT NULl')
      ->and('b.knr = :kursId:')
      ->addToWhere($this->getSearchSQL('b.'))
      ->addToWhere($this->getNichtKindBelegungenSQLPart())
      ->orderBySrcCode($this->getCompleteOrderByDefault('b.id'))
      ->paramString('kursId', $kursId);

    if ($this->hasOrderByFirma()) {
      
      
      
      
      
      $dbwBez = \DBWorkBeziehung::getDefaultInstance($this->dbtyp);
      $builderBez = $dbwBez->getSQLQuery4ArtZwischenTeilnehmern(3)
        ->and('bz.nr2 = t.nr')
        ->select('bz.nr1');

      $builder = $builder
        ->leftOuterJoin('teilnehm fa', 'fa.nr IN (:firmaBezJoin:)')
        ->paramSelectQuery('firmaBezJoin', $builderBez);
    }

    return $builder;
  }

  public function hasOrderByFirma(): bool
  {
    foreach ($this->getOrderbyObjects() as $orderByObj) {
      $name = $orderByObj->getNameMitPrefix();

      if (preg_match('/^fa\\./', $name)) {
        return true;
      }
    }

    return false;
  }

  
  public function getBelegungsIdsbyKursNR($pKursId): array
  {
    $builder = $this->getBelegungenByKursIdQuery($pKursId)
      ->select('b.id');

    $this->dboperation->clear();
    $this->dboperation->query($builder->getSQL());

    $belIdAry = $this->getAllRowsSingleColumn('id');
    $this->dboperation->clear();

    
    return array_unique($belIdAry);
  }

  
  public function getCountTNinWartelisteByKurs($pKnr, $pNurOnlineteilnahme = false, $pRefreshCache = false)
  {
    $warteListeAry = $this->getCountTnInWartelisteByKursen(array($pKnr), $pNurOnlineteilnahme, false, $pRefreshCache);

    return $warteListeAry[$pKnr];
  }

  
  public function getCountTnInWartelisteByKursen($pKnrs, $pNurOnlineteilnahme = false, $pCountKinderInsteadOfTn = false, $pRefreshCache = false)
  {
    if (!is_array($pKnrs)) {
      throw new InvalidArgumentException('$pKnrs ist kein Array');
    }

    $result = array();

    $knrs = array();
    foreach ($pKnrs as $knr) {
      $cleanKnr = $this->dboperation->getString4Sql($knr);
      if ($pRefreshCache || !isset(self::$_cache_Anzahl_TN_Kinder_In_Warteliste[$cleanKnr . '|' . $pCountKinderInsteadOfTn . '|' . $pNurOnlineteilnahme])) {
        $knrs[] = $cleanKnr;
        self::$_cache_Anzahl_TN_Kinder_In_Warteliste[$cleanKnr . '|' . $pCountKinderInsteadOfTn . '|' . $pNurOnlineteilnahme] = 0;
      }
      $result[$cleanKnr] = self::$_cache_Anzahl_TN_Kinder_In_Warteliste[$cleanKnr . '|' . $pCountKinderInsteadOfTn . '|' . $pNurOnlineteilnahme];
    }

    if (empty($knrs)) {
      return $result;
    }

    $sqlstr = "SELECT count(*) as anzahl, b.knr FROM belegung b \n";
    $sqlstr .= ' LEFT JOIN kurse k ON b.knr = k.nr ';
    $sqlstr .= " WHERE b.status_1 = 'W' AND b.knr IN ('" . implode("','", $knrs) . "') "
               . ($pCountKinderInsteadOfTn ? $this->getKindBelegungenSQLPart(false) : $this->getNichtKindBelegungenSQLPart(false))
               . self::getSqlPartNurOnlineteilname($pNurOnlineteilnahme)
               . ' GROUP BY b.knr;';

    $this->dboperation->clear();
    $this->dboperation->query($sqlstr);
    $rowcount = $this->dboperation->rowcount();
    for ($i = 0; $i < $rowcount; $i++) {
      $this->dboperation->selectrow($i);
      $knr = $this->getDatamodulValue('knr');
      self::$_cache_Anzahl_TN_Kinder_In_Warteliste[$knr . '|' . $pCountKinderInsteadOfTn . '|' . $pNurOnlineteilnahme] = $this->dboperation->fieldbyname('anzahl');
      $result[$knr] = self::$_cache_Anzahl_TN_Kinder_In_Warteliste[$knr . '|' . $pCountKinderInsteadOfTn . '|' . $pNurOnlineteilnahme];
    }

    return $result;
  }

  
  public function countAngemeldeteTnByKnr($pKnr, $pMitStatusP = true, $pPOhneAnmArtI = false)
  {
    $knr = $this->dboperation->getString4Sql($pKnr);

    $sql = 'SELECT COUNT(b.id) as anzahl '
        . 'FROM belegung b '
        . 'LEFT JOIN kurse k ON b.knr = k.nr '
        . 'WHERE b.knr = \'' . $knr . '\' '
        . 'AND ( b.status_1 IN (\'\',\' \', \'A\', \'T\') '
        . $this->getNichtKindBelegungenSQLPart(false);

    if ($pMitStatusP) {
      $sql .= 'OR ( b.status_1 = \'P\' ';
      if ($pPOhneAnmArtI) {
        $sql .= 'AND NOT b.anmeldeart = \'I\' ';
      }
      $sql .= ') ';
    }
    $sql .= ') ';
    $sql .= 'GROUP BY b.knr';

    $this->dboperation->clear();
    $this->dboperation->query($sql);

    $count = $this->dboperation->rowcount();
    if ($count > 0) {
      $this->dboperation->selectrow(0);
      $anzahl = $this->dboperation->fieldbyname('anzahl');
    } else {
      $anzahl = 0;
    }

    return $anzahl;
  }

  
  public function getFirstWartelistenBelegung($pKnr)
  {
    $tmp = $this->getWartelistenBelegungen($pKnr, 1);

    return $tmp[0] ?? $this->getNewObject();
  }

  
  public function getWartelistenBelegungen($pKnr, $pAnzahl, $pTnr = -1)
  {
    $knr = $this->dboperation->getString4Sql($pKnr);
    $tnr = $this->dboperation->getInt4Sql($pTnr);

    if ($pTnr == -1) {
      $sql = 'SELECT ' . $this->select . " FROM belegung b WHERE b.knr='$knr' AND b.status_1 = 'W' ";
    } else {
      $sql = 'SELECT ' . $this->select . " FROM belegung b WHERE b.knr='$knr' AND b.status_1 = 'W' AND b.firma != $tnr ";
    }
    $sql .= 'ORDER BY b.id ASC;';
    $this->dboperation->clear();
    $this->dboperation->query($sql);
    $result = array();
    $this->dboperation->resetToFirstRow();
    while ($this->dboperation->selectNextRow()) {
      $result[] = $this->getCurrentRow();
    }

    return $result;
  }

  
  public function getBelegungenByKursNRAndFirmaQuery($pKnr, $pTnr): SelectQueryBuilder
  {
    return $this->getAllQuery()
        ->and('b.knr = :knr:')
        ->and('b.tnr = :tnr:')
        ->and('b.status_1 = :status:')
        ->paramString('knr', $pKnr)
        ->paramInt('tnr', $pTnr)
        ->paramString('status', 'F');
  }

  
  public function getBelegungenByKursNRAndFirma($pKnr, $pTnr)
  {
    $builder = $this->getBelegungenByKursNRAndFirmaQuery($pKnr, $pTnr);

    $this->dboperation->clear();
    $this->dboperation->query($builder->getSQL());

    return $this->getAllRows();
  }

  
  public function getFirstBelegungByKursNRAndFirma($pKnr, $pTnr): ?\Belegung
  {
    $builder = $this->getBelegungenByKursNRAndFirmaQuery($pKnr, $pTnr);

    $this->dboperation->clear();
    $this->dboperation->query($builder->getSQL());

    return $this->getFirstRow();
  }

  
  public function getBelegungenByKursNRAndTnrQuery($pKnr, $pTnr, $pNurAngemeldete = false): SelectQueryBuilder
  {
    return $this->getBelegungenbyKursNRQuery($pKnr, $pNurAngemeldete, true)
        ->and('b.tnr = :tnr:')
        ->paramInt('tnr', $pTnr);
  }

  
  public function getBelegungenByKursNRAndTnr($pKnr, $pTnr, $pNurAngemeldete = false)
  {
    $builder = $this->getBelegungenByKursNRAndTnrQuery($pKnr, $pTnr, $pNurAngemeldete);

    $this->dboperation->clear();
    $this->dboperation->query($builder->getSQL());

    return $this->getAllRows();
  }

  
  public function getBelegungenbyKursNRQuery($pKnr, $pNurAngemeldete = false, $pAddFirma = false)
  {
    $builder = $this->getBelegungenByKursIdQuery($pKnr);

    if ($pNurAngemeldete) {
      
      if ($pAddFirma) {
        $statusSQLArray = \implode(',', ConstantOperations::getStatusangemeldetMitFirmaArray());
      } else {
        $statusSQLArray = \implode(',', ConstantOperations::getStatusangemeldetArray());
      }

      $builder = $builder->and('(b.status_1 IN (:anmeldeStatusAry:) OR b.status_1 IS NULL)')
          ->paramRaw('anmeldeStatusAry', $statusSQLArray);
    }

    return $builder;
  }

  
  public function getBelegungenbyKursNR($pKnr, $pNurAngemeldete = false, $pAddFirma = false)
  {
    $builder = $this->getBelegungenbyKursNRQuery($pKnr, $pNurAngemeldete, $pAddFirma);

    $this->dboperation->clear();
    $this->dboperation->query($builder->getSQL());

    return \ArrayOperations::uniqueByKey($this->getAllRows(), 'id');
  }

  
  public function getBelegungenIdsbyKursNR($pKnr, $pNurAngemeldete = false, $pAddFirma = false)
  {
    $builder = $this->getBelegungenbyKursNRQuery($pKnr, $pNurAngemeldete, $pAddFirma)
        ->select('b.id');

    $this->dboperation->clear();
    $this->dboperation->query($builder->getSQL());

    $belIdAry = $this->getAllRowsSingleColumn('id');
    $this->dboperation->clear();

    return $belIdAry;
  }

  
  public function getBelegungenbyKursTeilnehmerNR($pKurs_Id, $pTeilnehmer_Id, $pRefreshCache = false)
  {
    $kurs_id = $this->dboperation->getString4Sql($pKurs_Id);
    $teilnehmer_id = $this->dboperation->getInt4Sql($pTeilnehmer_Id);
    static $cache = array();
    $arrayKey = $kurs_id . '_' . $teilnehmer_id;
    if (!$pRefreshCache && isset($cache[$arrayKey])) {
      return $cache[$arrayKey];
    }
    $this->dboperation->clear();
    $sql = 'SELECT ' . $this->select . " FROM belegung b LEFT JOIN teilnehm t ON(b.tnr=t.nr)\n
            LEFT JOIN kurse k ON(b.knr=k.nr) WHERE b.knr = '" . $kurs_id . "'\n
            AND b.tnr = " . $teilnehmer_id . " \n " . $this->getSearchSQL('b.')
            . $this->getCompleteOrderByDefault('b.id');
    $this->dboperation->query($sql);
    $cache[$arrayKey] = $this->getAllRows();

    return $cache[$arrayKey];
  }

  
  public function getBelegungenbyKurseAndTeilnehmer($pKursNrAry, $pTeilnehmerNr)
  {
    $teilnehmer_id = $this->dboperation->getInt4Sql($pTeilnehmerNr);
    $this->dboperation->clear();
    $sql = 'SELECT ' . $this->select . " FROM belegung b LEFT JOIN teilnehm t ON(b.tnr=t.nr)\n
            LEFT JOIN kurse k ON(b.knr=k.nr) WHERE b.knr in('" . implode("', '", $pKursNrAry) . "')\n
            AND b.tnr = " . $teilnehmer_id . " \n " . $this->getSearchSQL('b.')
            . $this->getCompleteOrderByDefault('b.id');

    $this->dboperation->query($sql);

    return $this->getAllRows();
  }

  
  public function getBelegungenbyKursAndTeilnehmerAry($pKursNr, $pTeilnehmerNrAry)
  {
    $cleanKursNr = $this->dboperation->getString4Sql($pKursNr);
    $this->dboperation->clear();
    $sql = 'SELECT ' . $this->select . " FROM belegung b LEFT JOIN teilnehm t ON(b.tnr=t.nr)\n
            LEFT JOIN kurse k ON(b.knr=k.nr) WHERE b.tnr in('" . implode("', '", $pTeilnehmerNrAry) . "')\n
            AND b.knr = '" . $cleanKursNr . "' \n " . $this->getSearchSQL('b.')
            . $this->getCompleteOrderByDefault('b.id');

    $this->dboperation->query($sql);

    return $this->getAllRows();
  }

  public function getBelegungenbyKurseAndTeilnehmerAry($pKursNrAry, $pTeilnehmerNrAry)
  {
    $this->dboperation->clear();
    $sql = 'SELECT ' . $this->select . " FROM belegung b LEFT JOIN teilnehm t ON(b.tnr=t.nr)\n
            LEFT JOIN kurse k ON(b.knr=k.nr) WHERE b.tnr in('" . implode("', '", $pTeilnehmerNrAry) . "')\n
            AND b.knr in('" . implode("', '", $pKursNrAry) . "')\n " . $this->getSearchSQL('b.')
            . $this->getCompleteOrderByDefault('b.id');

    $this->dboperation->query($sql);

    return $this->getAllRows();
  }

  public function getBelegungenIdsByKursAry($pKursAry)
  {
    $this->dboperation->clear();
    $sql = "SELECT b.id FROM belegung b LEFT JOIN teilnehm t ON(b.tnr=t.nr)\n
            LEFT JOIN kurse k ON(b.knr=k.nr) WHERE b.knr in('" . implode("', '", $pKursAry) . "')\n"
            . $this->getSearchSQL('b.')
            . $this->getNichtKindBelegungenSQLPart()
            . $this->getCompleteOrderByDefault('b.id');

    $this->dboperation->query($sql);

    $belIdAry = $this->getAllRowsSingleColumn('id');
    $this->dboperation->clear();

    return $belIdAry;
  }

  public function getBelegungenByKursAry($pKursAry)
  {
    $this->dboperation->clear();
    $sql = 'SELECT ' . $this->select . " FROM belegung b LEFT JOIN teilnehm t ON(b.tnr=t.nr)\n
            LEFT JOIN kurse k ON(b.knr=k.nr) WHERE b.knr in('" . implode("', '", $pKursAry) . "')\n"
            . $this->getSearchSQL('b.')
            . $this->getNichtKindBelegungenSQLPart()
            . $this->getCompleteOrderByDefault('b.id');
    $this->dboperation->query($sql);

    return $this->getAllRows();
  }

  private function getBelegungsCountbyKursFirmaTeilnehmerNrWithStatus($pKurs_Id, $pTeilnehmer_Id, $pStatus)
  {
    $kurs_id = $this->dboperation->getString4Sql($pKurs_Id);
    $teilnehmer_id = $this->dboperation->getInt4Sql($pTeilnehmer_Id);
    $this->dboperation->clear();
    $this->dboperation->query("SELECT status_1 FROM belegung b
                               WHERE b.knr    = '" . $kurs_id . "'
                               AND b.firma    = " . $teilnehmer_id . '
                               AND b.status_1 IN (' . $pStatus . ') ');

    return $this->dboperation->rowcount();
  }

  
  public function getBelegungen4MehrfachOrFirma($pKnr, $pHauptTnr, $pStatus, $pBelId, $pFirma)
  {
    $knr = $this->dboperation->getString4Sql($pKnr);
    $hauptTnr = $this->dboperation->getString4Sql($pHauptTnr);
    $selectShort = 'b.id, b.knr, b.tnr, b.firma, b.status_1 ';
    $this->dboperation->clear();

    
    
    
    
    
    $andSqlPart4Bel = '';
    
    if ($pHauptTnr !== $pFirma) {
      $andSqlPart4Bel = ' AND b.id = ' . $pBelId;
    }

    $sql = 'SELECT ' . $selectShort . ' FROM belegung b  WHERE b.knr =\'' . $knr . '\' AND (b.firma=' . $hauptTnr
           . ' AND b.status_1 IN (' . $pStatus . ') OR (b.tnr=' . $hauptTnr . $andSqlPart4Bel . '))';
    

    $this->dboperation->query($sql);

    $ary = array(); 
    $rows = $this->dboperation->rowcount();
    for ($i = 0; $i < $rows; $i++) {
      $this->dboperation->selectrow($i);
      
      $tmp = new stdClass();
      $tmp->id = $this->getDatamodulValue('id');
      $tmp->knr = $this->getDatamodulValue('knr');
      $tmp->tnr = $this->getDatamodulValue('tnr');
      $tmp->status = $this->getDatamodulValue('status_1');
      $tmp->firma = $this->getDatamodulValue('firma');
      array_push($ary, $tmp);
    }

    return $ary;
  }

  
  public function insertBelegung($belegung, $pTeilnehmerUpdate = true)
  {
    $belegung->id = $this->insertRecord('belegung', 'id', 'knr', true);
    $this->saveChanging('belegung', '', '', $belegung->id, 'id', 'I', SessionOperations::isReplikat());
    $orgbelegung = $this->getBelegung($belegung->id);
    
    
    if ($belegung->status == 'A' && $orgbelegung->status == 'A') {
      $orgbelegung->status = '';
    }
    $this->updateObject($belegung, $orgbelegung, 'belegung', 'id', 'A');
    if (($belegung->teilnehmer != null) && ($belegung->teilnehmer->id > 0)) {
      
      
      if ($pTeilnehmerUpdate) {
        $this->dbwteilnehmer->updateTeilnehmer($belegung->teilnehmer, false, null, true);
      }
    }
    if (($belegung->kurs != null) && ($belegung->kurs->id != '')) {
      $this->dbwkurse->updateKurs($belegung->kurs);
    }
    $this->setActionIDs();

    return $belegung->id;
  }

  
  public function updateBelegung($belegung, $pStatus5 = null, $pRefreshCache = false)
  {
    $orgbelegung = $this->getBelegung($belegung->id, $pRefreshCache);
    $this->updateObject($belegung, $orgbelegung, 'belegung', 'id', 'U', false, $pStatus5);
    $this->setActionIDs();
  }

  
  public function deleteBelegung($pBelegungID)
  {
    $belegungID = $this->dboperation->getInt4Sql($pBelegungID);
    $this->dboperation->clear();
    $this->dboperation->execute('DELETE FROM belegung WHERE id = ' . $belegungID);
    $this->saveChanging('belegung', '', '', "'" . $belegungID . "'", '', 'D');
    $this->setActionIDs();
  }

  
  public function belegungExists($pBelegungID)
  {
    $belegungID = $this->dboperation->getInt4Sql($pBelegungID);
    $this->dboperation->clear();
    $this->dboperation->query('SELECT b.id FROM belegung b WHERE id = ' . $belegungID);

    return $this->dboperation->rowcount() > 0;
  }

  
  public function updateObject($editobj, $orgobj, $tablename, $idfield, $sqltyp = 'U', $pDontProtocol = false, $pStatus5 = null)
  {
    if (is_null($pStatus5)) {
      $status = SessionOperations::isReplikat();
    } else {
      $status = $pStatus5;
    }

    if (get_class($editobj) == get_class($orgobj)) {
      $fieldcount = $editobj->getVarCount();
      for ($i = 0;$i < $fieldcount;$i++) {
        $varname = $editobj->getVarName($i);
        if ($this->canupdate($varname)) {
          if (($editobj->getVarValue($varname) !== $orgobj->getVarValue($varname))
                || ($orgobj->getVarValue($varname) === '')) {
            
            if (!$pDontProtocol) {
              $this->saveChanging(
                $tablename,
                $orgobj->getVarValue($varname),
                $editobj->getVarValue($varname),
                $this->getSQLValue($idfield, $orgobj),
                $this->translateVarName($varname),
                $sqltyp,
                $status
              );
            }
            $this->updateChanging(
              $this->getSQLValue($idfield, $orgobj),
              $this->translateVarName($idfield),
              $tablename,
              $this->translateVarName($varname),
              $this->getSQLValue($varname, $editobj)
            );
          }
        }
      }
      $this->executeUpdateBuffer(
        $this->getSQLValue($idfield, $orgobj),
        $this->translateVarName($idfield),
        $tablename
      );
    }
  }

  
  public function getBelegungCountByKnr($pKnr, $pNurAngemeldete = true, $pNurOnlineteilnahme = false, $pRefreshCache = false)
  {
    $result = $this->getBelegungCountByKnrArray(array($pKnr), $pNurAngemeldete, $pNurOnlineteilnahme, $pRefreshCache);

    return $result[$pKnr];
  }

  
  public function getBelegungCountByFpFirma($pKatId, $pFirmaTnr, $pRefreshCache = false)
  {
    $katid = $this->dboperation->getInt4Sql($pKatId);
    $firma = $this->dboperation->getInt4Sql($pFirmaTnr);

    $cacheKey = $katid . '|' . $firma;

    if ($pRefreshCache || !array_key_exists($cacheKey, self::$_cache_BelegungCountByFpFirma)) {
      $sql = 'SELECT count(b.id) anmeldungen FROM belegung b '
              . "WHERE b.knr in (select kk.knr from kurse_kategorien kk where kk.kategorie_id = $katid)"
              . ' AND (b.status_1 in (' . ConstantOperations::getStatusangemeldetSQLStr() . ') OR b.status_1 is null)'
              . ' AND b.fp_firma = ' . $firma;

      $this->dboperation->clear();
      $this->dboperation->query($sql);
      $this->dboperation->selectrow(0);

      $anmeldungen = $this->dboperation->fieldbyname('anmeldungen');
      self::$_cache_BelegungCountByFpFirma[$cacheKey] = $anmeldungen;
    }

    return self::$_cache_BelegungCountByFpFirma[$cacheKey];
  }

  
  public function getBelegungCountByKnrArray($pKursnummern, $pNurAngemeldete = true, $pNurOnlineteilnahme = false, $pRefreshCache = false)
  {
    if (!is_array($pKursnummern) || empty($pKursnummern)) {
      return array();
    }

    $result = array();

    $knrs = array();
    foreach ($pKursnummern as $knr) {
      $cleanKnr = $this->dboperation->getString4Sql($knr);
      if ($pRefreshCache || !isset(self::$_cache_BelegungCountByKnrArray[$cleanKnr . '|' . $pNurAngemeldete . '|' . $pNurOnlineteilnahme])) {
        $knrs[] = $cleanKnr;
        self::$_cache_BelegungCountByKnrArray[$cleanKnr . '|' . $pNurAngemeldete . '|' . $pNurOnlineteilnahme] = 0;
      }
      $result[$cleanKnr] = self::$_cache_BelegungCountByKnrArray[$cleanKnr . '|' . $pNurAngemeldete . '|' . $pNurOnlineteilnahme];
    }

    if (empty($knrs)) {
      return $result;
    }

    $sql = 'SELECT b.knr, count(b.id) anmeldungen FROM belegung b '
             . 'LEFT JOIN kurse k ON b.knr = k.nr '
             . 'WHERE b.knr IN (' . StringOperations::convertArray2InList($knrs) . ') '
             . $this->getNichtKindBelegungenSQLPart(false);
    if ($pNurAngemeldete) {
      $sql .= ' AND (b.status_1 IN (' . ConstantOperations::getStatusangemeldetSQLStr() . ') OR b.status_1 is null)';
    }

    $sql .= self::getSqlPartNurOnlineteilname($pNurOnlineteilnahme);
    $sql .= ' GROUP BY b.knr';

    $this->dboperation->clear();
    $this->dboperation->query($sql);

    $count = $this->dboperation->rowcount();
    for ($i = 0; $i < $count; $i++) {
      $this->dboperation->selectrow($i);
      $anmeldungen = $this->dboperation->fieldbyname('anmeldungen');
      $knr = $this->getDatamodulValue('knr');
      self::$_cache_BelegungCountByKnrArray[$knr . '|' . $pNurAngemeldete . '|' . $pNurOnlineteilnahme] = $anmeldungen;
      $result[$knr] = self::$_cache_BelegungCountByKnrArray[$knr . '|' . $pNurAngemeldete . '|' . $pNurOnlineteilnahme];
    }

    return $result;
  }

  
  public function getTeilnehmerBelegungenByFirmaKursQuery($pFirmaTnr, $pKursNr = '', $pStatusList = array(), $pNegateStatusList = false): SelectQueryBuilder
  {
    $builder = $this->getSelectQueryBuilder()
        ->select($this->select)
        ->from('belegung', 'b');
    if ($pFirmaTnr == 0) {
      return $builder->and('1 = 0');
    }

    $builder = $builder->and('b.firma = :firmaTnr:')
        ->paramInt('firmaTnr', $pFirmaTnr);

    if (!empty($pKursNr)) {
      $builder = $builder->and('b.knr = :kursNr:')
          ->paramString('kursNr', $pKursNr);
    }

    if (!empty($pStatusList)) {
      $builder = $builder->and('b.status_1 ' . ($pNegateStatusList ? 'NOT ' : '') . 'IN(:statusList:)')
          ->paramStringArray('statusList', $pStatusList);
    }

    return $builder;
  }

  
  public function getTeilnehmerBelegungenByFirmaKurs($pFirmaTnr, $pKursNr = '', $pStatusList = array(), $pNegateStatusList = false)
  {
    $builder = $this->getTeilnehmerBelegungenByFirmaKursQuery($pFirmaTnr, $pKursNr, $pStatusList, $pNegateStatusList);
    $this->dboperation->clear();
    $this->dboperation->query($builder->getSQL());

    return $this->getAllRows();
  }

  
  public function setEintrittTeilReal($pKnr, $pAuchAustrittSetzen)
  {
    $anwTablename = 'anw';
    $anwExtraTablename = 'anw_extra';

    $dbwanw2 = new DBWorkAnwesenheit2();
    if ($dbwanw2->isZweiteTabelleVerfuegbar()) {
      $anwTablename = 'anw2';
      $anwExtraTablename = 'anw_extra2';
    }
    
    $statement = 'UPDATE belegung SET';
    $statement .= ' eintritt=' . $this->dboperation->dbparser->IsNull(
      "(SELECT MIN(kt.datum) FROM kurstage kt INNER JOIN $anwTablename ka ON (ka.aktid=kt.id)"
          . ' WHERE (kt.knr=belegung.knr) AND (ka.abelegid=belegung.id) AND ('
          . $this->dboperation->dbparser->isNull('kt.ausf', "' '")
          . "<>'A')"
          . ' AND ((' . $this->dboperation->dbparser->IsNull('ka.astatus', "' '")
          . "<>' ') OR ((SELECT COUNT(*) FROM $anwExtraTablename e WHERE (e.eanwid = ka.id) and ("
          . $this->dboperation->dbparser->IsNull('e.estatus', "' '")
          . "<>' '))>0)))",
      'belegung.eintritt'
    );
    $statement .= ',teil_real=' . $this->dboperation->dbparser->IsNull('(SELECT COUNT(DISTINCT kt.datum) FROM kurstage kt'
          . " INNER JOIN $anwTablename a ON (a.aktid=kt.id) WHERE (a.abelegid=belegung.id)"
          . ' AND ((' . $this->dboperation->dbparser->IsNull('a.astatus', "' '")
          . ' IN (SELECT ' . $this->dboperation->dbparser->IsNull('status', "' '")
          . ' FROM anw_hl_gruende WHERE ' . $this->dboperation->dbparser->IsNull('anwesend', "' '")
          . "='W')))"
          . " OR ((SELECT COUNT(*) FROM $anwExtraTablename e WHERE (e.eanwid=a.id) and ("
          . $this->dboperation->dbparser->IsNull('e.estatus', "' '")
          . ' IN (SELECT ' . $this->dboperation->dbparser->IsNull('status', "' '")
          . ' FROM anw_hl_gruende WHERE (' . $this->dboperation->dbparser->IsNull('anwesend', "' '")
          . "='W'))))>0))", '0');
    if ($pAuchAustrittSetzen) {
      $statement .= ',austritt=' . $this->dboperation->dbparser->IsNull('(SELECT MAX(kt.datum) FROM kurstage kt'
          . " INNER JOIN $anwTablename a ON (a.aktid=kt.id) WHERE (kt.knr=belegung.knr) AND (a.abelegid=belegung.id)"
          . ' AND (' . $this->dboperation->dbparser->IsNull('kt.ausf', "' '")
          . "<>'A')"
          . ' AND ((' . $this->dboperation->dbparser->IsNull('a.astatus', "' '")
          . "<>' ')"
          . " OR ((SELECT COUNT(*) FROM $anwExtraTablename e WHERE (e.eanwid=a.id) and ("
          . $this->dboperation->dbparser->IsNull('e.estatus', "' '")
          . " <> ''))>0)))", 'belegung.eintritt');
    }
    $statement .= " WHERE (belegung.knr='$pKnr') AND (" . $this->dboperation->dbparser->IsNull('belegung.Status_1', "' '")
              . "<>'F')";
    $this->dboperation->clear();
    $this->dboperation->execute($statement);
    
    if (!SessionOperations::isReplikat()) {
      $sql = "SELECT bamf FROM kurse WHERE nr = '$pKnr'";
      $this->dboperation->clear();
      $this->dboperation->query($sql);
      $this->dboperation->selectrow(0);
      $bamf = $this->getDatamodulValue('bamf') == 'W';
      if ($bamf) {
        $isOracle = $this->dboperation->getDBName() == 'ORACLE';
        $statement = 'UPDATE belegung SET ';
        $statement .= 'mf_anwtag1=' . $this->dboperation->dbparser->IsNull('(SELECT'
            . ($isOracle ? '' : ' top 1')
            . ' (CASE WHEN ' . $this->dboperation->dbparser->IsNull('a.astatus', "' '")
            . " IN ('A','X','E','U')"
            . ' THEN (CASE ' . $this->dboperation->dbparser->IsNull('a.astatus', "' '")
            . " WHEN 'A' THEN 'X' ELSE " . $this->dboperation->dbparser->IsNull('a.astatus', "' '") . ' END)'
            . " ELSE ' ' END)"
            . " FROM $anwTablename a"
            . ' INNER JOIN kurstage kt ON (kt.id=a.aktid)'
            . ' WHERE (a.abelegid=belegung.id)'
            . ($isOracle ? ' AND (ROWNUM<=1)' : '')
            . ' AND (kt.id IN (SELECT '
            . ($isOracle ? 'MIN(kt2.id)' : 'TOP 1 kt2.id')
            . ' FROM kurstage kt2 WHERE (kt2.knr=kt.knr) AND ('
            . $this->dboperation->dbparser->IsNull('kt2.ausf', "' '")
            . "<>'A') AND (" . $this->dboperation->dbparser->IsNull('kt2.datum', $this->datetimeop->getFormatDate4Server(DEFAULTDATE))
            . '>' . $this->datetimeop->getFormatDate4Server(DEFAULTDATE)
            . ') '
            . ($isOracle ? 'HAVING MIN(kt2.datum)=MIN(kt2.datum)' : 'ORDER BY kt2.datum,kt2.zeit_beg,kt2.zeit_ende')
            . '))'
            . ')', "' '");
        $statement .= ',mf_fehlstdn=' . $this->dboperation->dbparser->IsNull('(SELECT'
            . $this->dboperation->dbparser->IsNull('SUM(kt.minuten*1.0/45)*1.0', '0.0')
            . " FROM $anwTablename a"
            . ' INNER JOIN kurstage kt ON (kt.id=a.aktid)'
            . ' WHERE (a.abelegid=belegung.id)'
            . ' AND (' . $this->dboperation->dbparser->IsNull('kt.ausf', "' '")
            . " <>'A')"
            . ' AND (' . $this->dboperation->dbparser->IsNull('a.astatus', "' '")
            . "<>'A')"
            . ' AND ('
            . $this->dboperation->dbparser->IsNull('a.astatus', "' '")
            . "<>'E'))", '0.0');
        $statement .= ',mf_fehlstdv=' . $this->dboperation->dbparser->IsNull('(SELECT '
            . $this->dboperation->dbparser->IsNull('SUM(kt.minuten*1.0/45)*1.0', '0.0')
            . " FROM $anwTablename a"
            . ' INNER JOIN kurstage kt ON (kt.id=a.aktid)'
            . ' WHERE (a.abelegid=belegung.id)'
            . ' AND ('
            . $this->dboperation->dbparser->IsNull('kt.ausf', "' '")
            . "<>'A')"
            . ' AND (' . $this->dboperation->dbparser->IsNull('a.astatus', "' '")
            . "='E'))", '0.0');
        $statement .= ',mf_fehlstdk=' . $this->dboperation->dbparser->IsNull('(SELECT '
            . $this->dboperation->dbparser->IsNull('SUM(kt.minuten*1.0/45)*1.0', '0.0')
            . ' FROM kurstage kt'
            . ' WHERE (kt.knr=belegung.knr)'
            . ' AND (' . $this->dboperation->dbparser->IsNull('kt.ausf', "' '")
            . "<>'A')"
            . ' AND (' . $this->dboperation->dbparser->IsNull('kt.datum', $this->datetimeop->getFormatDate4Server(DEFAULTDATE))
            . '>belegung.austritt))', '0.0');
        $statement .= " WHERE (belegung.knr='" . $pKnr . "') AND ("
            . $this->dboperation->dbparser->IsNull('belegung.status_1', "' '")
            . "<>'F')";
        $this->dboperation->clear();
        $this->dboperation->execute($statement);
      }
    }
  }

  
  public function isTeilEinerMehrfachAnmeldung($pBelegId)
  {
    $belegId = $this->dboperation->getInt4Sql($pBelegId);
    $sqlPart = '';
    if (System::isKuferSql5()) {
      $sqlPart = ' AND b.bezug NOT IN (3, 4)'; 
    }

    $sql = 'SELECT count(*) AS anzahl FROM belegung b WHERE b.id=' . $belegId
        . ' AND (' . $this->dboperation->dbparser->isNull('firma', '0') . ' > 0' . $sqlPart
        . ' OR EXISTS (SELECT firma FROM belegung b1 WHERE b1.knr=b.knr AND b1.firma = b.tnr AND b.id = ' . $belegId . $sqlPart . '))';

    $this->dboperation->clear();
    $this->dboperation->query($sql);
    $this->dboperation->selectrow(0);

    return $this->getDatamodulValue('anzahl') > 0;
  }

  
  public function getFirmaBelegungenByTeilnehmerBelegung($belegung)
  {
    $subselect = new SelectQueryBuilder($this->dboperation);
    $subselect->select('firma')
              ->from('belegung b2')
              ->where('b2.tnr=:tnr: AND b2.knr=:knr: AND b2.firma != 0 AND b2.id =:id:')
              ->paramInt('tnr', $belegung->tnr)
              ->paramString('knr', $belegung->knr)
              ->paramInt('id', $belegung->id);

    $query = new SelectQueryBuilder($this->dboperation);
    $query->select($this->select)
              ->from('belegung b')
              ->where('b.tnr IN (:subselect:) AND b.status_1=\'F\' AND b.knr=:knr:')
              ->paramRaw('subselect', $subselect->getSQLForInnerQuery())
              ->paramString('knr', $belegung->knr);

    $this->dboperation->clear();
    $this->dboperation->query($query->getSQL());

    return $this->getAllRows();
  }

  
  public function IsElternKindanmeldung($pBelegung)
  {
    if (System::isKuferSql5()) {
      $result = $pBelegung->isElternKindAnmeldung();
    } else {
      $kinder = $this->dbwkinder->getKinderbyBelegung($pBelegung->id);
      $result = !empty($kinder);
    }

    return $result;
  }

  
  public function doFirmenStorno($pBelegung, $pAbmeldegrund, $pBearbeiterkuerzel = '')
  {
    $bearbeiterKuerzel = $pBearbeiterkuerzel != '' ? $pBearbeiterkuerzel : 'WT';
    $isReplikat = SessionOperations::isReplikat();
    $belegungen = $this->getTeilnehmerBelegungenByFirmaKurs($pBelegung->tnr, $pBelegung->knr);
    $dbwZahlung = new DBWorkZahlung($this->dbtyp, true);

    $this->dboperation->beginTransaction();
    $dbwZahlung->dboperation->beginTransaction();

    $this->_storniereFirmenMitarbeiter($pBelegung, $belegungen, $pAbmeldegrund, $bearbeiterKuerzel, $isReplikat, $dbwZahlung);

    
    $pBelegung->status = 'S';
    $pBelegung->entgelt = 0;
    $pBelegung->bet_offen = 0;
    $pBelegung->bemerkung = KUFERTOOLS . ' Storno' . ($pAbmeldegrund != '' ? ' - Grund: ' . $pAbmeldegrund : '')
        . ($pBelegung->bemerkung != '' ? ' (' . $pBelegung->bemerkung . ')' : '');
    $this->updateBelegung($pBelegung, $isReplikat);

    
    $zahlungen = $dbwZahlung->getZahlungJournalByBelegId($pBelegung->id, true);
    foreach ($zahlungen as $zahlung) {
      if ($zahlung->sollist != 'N' && $zahlung->sollist != 'V') {
        $zahlung->dp = 'S';
        $zahlung->invisibleDP = 'S'; 

        $neueZahlung = $zahlung->copy(); 
        $neueZahlung->id = 0;
        if ($zahlung->betrag == '0,00') {
          $neueZahlung->betrag = '0,00';
        } else {
          $neueZahlung->betrag = MathOperations::floatToString(-1 * MathOperations::stringToFloat($neueZahlung->betrag));
        }
        $neueZahlung->org_zahlid = $zahlung->id;
        $neueZahlung->text = 'Storno von ' . $zahlung->text;
        $neueZahlung->datum = DateTimeOperations::getDateNow();
        $neueZahlung->uhrzeit = DateTimeOperations::getTimeNow();
        $neueZahlung->bearbdatum = DateTimeOperations::getDateTimeNow();
        $neueZahlung->bearbeiter = $bearbeiterKuerzel;

        $dbwZahlung->updateZahlung($zahlung, $isReplikat);
        $dbwZahlung->insertZahlung($neueZahlung, $isReplikat);
      }
    }

    
    $dbwZahlung->neutralerZahlungssatz(
      $pBelegung->knr,
      $pBelegung->tnr,
      $pBelegung->id,
      null,
      'Stornierung',
      11,
      'F->S',
      'F->S',
      $bearbeiterKuerzel
    );

    $dbwZahlung->dboperation->commitTransaction();
    $this->dboperation->commitTransaction();

    if (!$isReplikat) {
      $dbwKurse = new DBWorkKurse(2);
      $dbwKurse->updateTeilAkt($pBelegung->knr);
    }
  }

  
  public function doStornoFirmenMitarbeiter($pBelegung, $pZuStornierendeBelegungen, $pAbmeldegrund, $pBearbeiterkuerzel)
  {
    $bearbeiterKuerzel = $pBearbeiterkuerzel != '' ? $pBearbeiterkuerzel : 'WT';
    $isReplikat = SessionOperations::isReplikat();

    $dbwZahlung = new DBWorkZahlung($this->dbtyp, true);

    $this->dboperation->beginTransaction();
    $dbwZahlung->dboperation->beginTransaction();

    $this->_storniereFirmenMitarbeiter($pBelegung, $pZuStornierendeBelegungen, $pAbmeldegrund, $bearbeiterKuerzel, $isReplikat, $dbwZahlung);

    $dbwZahlung->dboperation->commitTransaction();
    $this->dboperation->commitTransaction();

    if (!$isReplikat) {
      $dbwKurse = new DBWorkKurse(2);
      $dbwKurse->updateTeilAkt($pBelegung->knr);
    }
  }

  
  public function _storniereFirmenMitarbeiter($pFirmenBelegung, $pZuStornierendeBelegungen, $pAbmeldegrund, $bearbeiterKuerzel, $isReplikat, $dbwZahlung)
  {
    foreach ($pZuStornierendeBelegungen as $mitarbeiterBelegung) {
      if ($mitarbeiterBelegung->status !== 'S') {
        $statusWechsel = $mitarbeiterBelegung->status;
        if ($statusWechsel == '' || $statusWechsel == ' ') {
          $statusWechsel = 'A';
        }
        $statusWechsel .= '->S';

        
        $mitarbeiterBelegung->bemerkung = KUFERTOOLS . ' Storno' . ($pAbmeldegrund != '' ? ' - Grund: ' . $pAbmeldegrund : '')
          . ($mitarbeiterBelegung->bemerkung != '' ? ' (' . $mitarbeiterBelegung->bemerkung . ')' : '');
        $mitarbeiterBelegung->entgelt = 0;
        $mitarbeiterBelegung->bet_offen = 0;
        $mitarbeiterBelegung->status = 'S';
        $this->updateBelegung($mitarbeiterBelegung, $isReplikat);


        
        $dbwZahlung->neutralerZahlungssatz(
          $pFirmenBelegung->knr,
          $mitarbeiterBelegung->tnr,
          $mitarbeiterBelegung->id,
          null,
          'Stornierung',
          11,
          $statusWechsel,
          $statusWechsel,
          $bearbeiterKuerzel
        );

        
        $dbwZahlung->neutralerZahlungssatz(
          $pFirmenBelegung->knr,
          $pFirmenBelegung->tnr,
          $pFirmenBelegung->id,
          null,
          'Mitarbeiter: ' . $mitarbeiterBelegung->teilnehmer->name . ', ' . $mitarbeiterBelegung->teilnehmer->vorname,
          18,
          $statusWechsel,
          '', 
          $bearbeiterKuerzel,
          $mitarbeiterBelegung->tnr
        );
      }
    }
  }

  
  public function doStorno($pBelegId, $pStatus, $pAbmeldegrund, $pBearbeiterKuerzel = '', $pAustritt = null)
  {
    $belegId = $this->dboperation->getInt4Sql($pBelegId);

    $belegung = $this->getBelegung($belegId);

    $zahlungen = ZahlungAPI::getZahlungen4Storno($belegung, $pStatus, $pBearbeiterKuerzel);
    $zahlungenToUpdate = $zahlungen['update'];
    $zahlungenToInsert = $zahlungen['insert'];

    $kursgebuehr = 0;
    $bemerkung = KUFERTOOLS . ' Storno' . ($pAbmeldegrund != '' ? ' - Grund: ' . $pAbmeldegrund : '')
            . ($belegung->bemerkung != '' ? ' (' . $belegung->bemerkung . ')' : '');

    $this->fillBelegung4StatusAendern($belegung, $pStatus, false, $kursgebuehr, $bemerkung, $pAustritt);
    $this->doStatusAendern($belegung, $zahlungenToInsert, $zahlungenToUpdate);
  }

  
  public function doStornoKursMitAboGebuehr($pBelegId, $pStornoGrund, $pAustritt)
  {
    $belegId = $this->dboperation->getInt4Sql($pBelegId);
    $austritt = $this->dboperation->getString4Sql($pAustritt);
    if ($austritt == '') {
      $austritt = DateTimeOperations::getDateNow();
    }

    $belegung = $this->getBelegung($belegId);
    $belegung->bemerkung = KUFERTOOLS . ' Storno' . ($pStornoGrund != '' ? ' - Grund: ' . $pStornoGrund : '')
            . ($belegung->bemerkung != '' ? ' (' . $belegung->bemerkung . ')' : '');
    $belegung->austritt = $austritt;
    $this->updateBelegung($belegung, SessionOperations::isReplikat());
  }

  
  public function doUmmeldeStorno($pBelegId, $pAustritt, $pZielKursNr)
  {
    $belegId = $this->dboperation->getInt4Sql($pBelegId);
    $austritt = $this->dboperation->getString4Sql($pAustritt);

    $isReplikat = SessionOperations::isReplikat();

    $belegung = $this->getBelegung($belegId);

    $hasKursAboGebuehren = APIGebuehren::hasKursFortlaufendeGebuehren($belegung->kurs->id);

    
    if ($hasKursAboGebuehren) {
      $belegung->austritt = ($austritt != '' ? $austritt : DateTimeOperations::getDateNow());
    } else {
      $belegung->status = 'U';
      $belegung->entgelt = 0;
      $belegung->bet_offen = 0;
    }

    $belegung->bemerkung = KUFERTOOLS . ' umgemeldet in ' . $pZielKursNr . ' ' . ($belegung->bemerkung != '' ? ' (' . $belegung->bemerkung . ')' : '');
    $this->dboperation->beginTransaction();

    $this->updateBelegung($belegung, $isReplikat);

    
    if (!$isReplikat && !$hasKursAboGebuehren) {
      $dbwKurse = new DBWorkKurse(2);
      $dbwKurse->updateTeilAkt($belegung->knr);
    }
    $this->dboperation->commitTransaction();
  }

  
  public function doStatusAendern($pBelegung, $pZahlungenToInsert, $pZahlungenToUpdate)
  {
    $isReplikat = SessionOperations::isReplikat();
    $this->dboperation->beginTransaction();

    $this->updateBelegung($pBelegung, $isReplikat);

    $dbwZahlung = new DBWorkZahlung(1, true);
    $dbwZahlung->dboperation->beginTransaction();

    foreach ($pZahlungenToUpdate as $zahlung) {
      $dbwZahlung->updateZahlung($zahlung, true);
    }
    foreach ($pZahlungenToInsert as $zahlung) {
      $dbwZahlung->insertZahlung($zahlung, true);
    }

    $dbwZahlung->dboperation->commitTransaction();
    $this->dboperation->commitTransaction();

    
    
    
    if (!$isReplikat) {
      $dbwKurse = new DBWorkKurse(2);
      $dbwKurse->updateTeilAkt($pBelegung->knr);
    }
  }

  
  public function fillBelegung4StatusAendern(
    $pBelegung,
    $pStatusNeu,
    $pAnmeldedatumNeuSetzen,
    $pKursGebuehr = null,
    $pBemerkung = null,
    $pAustritt = null,
    $addGeld = false
  ) {
    $pBelegung->status = $this->dboperation->getString4Sql($pStatusNeu);
    if (isset($pKursGebuehr)) {
      $kursGebuehr = $this->dboperation->getString4Sql($pKursGebuehr);
      if ($addGeld) {
        $pBelegung->entgelt = MathOperations::floatToString(MathOperations::stringToFloat($pBelegung->entgelt) + MathOperations::stringToFloat($kursGebuehr));
        $pBelegung->bet_offen = MathOperations::floatToString(MathOperations::stringToFloat($pBelegung->bet_offen) + MathOperations::stringToFloat($kursGebuehr));
      } else {
        $pBelegung->entgelt = $kursGebuehr;
        $pBelegung->bet_offen = $kursGebuehr;
      }
    }
    if ($pAnmeldedatumNeuSetzen) {
      $pBelegung->anm_datum = \DateTimeOperations::getDateTimeNow();
    }
    if (isset($pBemerkung)) {
      $pBelegung->bemerkung = $this->dboperation->getString4Sql($pBemerkung);
    }
    if (isset($pAustritt)) {
      $austritt = $pAustritt !== '' ? $pAustritt : DateTimeOperations::getDateNow();
      $austritt = $this->dboperation->getString4Sql($austritt);
      $pBelegung->austritt = $austritt;
    }
  }

  
  public function changeWarteListenStatus($pBelegung, $pBearbeiterkuerzel)
  {
    
    $isReplikat = SessionOperations::isReplikat();
    $pBelegung->status = 'P';
    
    

    
    $statusWechsel = $pBelegung->status;
    if ($statusWechsel == '' || $statusWechsel == ' ') {
      $statusWechsel = 'W';
    }
    $statusWechsel .= '->P';

    $pBelegung->bemerkung = KUFERTOOLS . ': Statuswechsel W->P, am ' . DateTimeOperations::getDateNow() . ' benachrichtigt'
        . ($pBelegung->bemerkung != '' ? ' (' . $pBelegung->bemerkung . ')' : '');
    $this->dboperation->beginTransaction();

    $this->updateBelegung($pBelegung, $isReplikat);

    
    $dbwZahlung = new DBWorkZahlung(1, true);
    $dbwZahlung->dboperation->beginTransaction();
    
    $zahlungen = $dbwZahlung->getZahlungJournalByBelegId($pBelegung->id, true);
    $neutrZahlung = $dbwZahlung->getNeutralenZahlungssatz(
      $zahlungen[0]->knr,
      $zahlungen[0]->tnr,
      $zahlungen[0]->belegid,
      null,
      'Statuswechsel W->P',
      11,
      $statusWechsel,
      $statusWechsel,
      $pBearbeiterkuerzel
    );
    $dbwZahlung->insertZahlung($neutrZahlung, true);
    $dbwZahlung->dboperation->commitTransaction();

    $this->dboperation->commitTransaction();
  }

  
  public function getPunkteInfo4KnrTnr($pKnr, $pTnr)
  {
    $pTnr = \Kufer\Web\Classes\Identifier\IdentifierFactory::createFromIdIfNecessary($pTnr);
    $tnr = $this->dboperation->getInt4Sql($pTnr->getId());
    $knr = $this->dboperation->getString4Sql($pKnr);
    $sql = 'SELECT b.id, b.status_1, b.pkt_ok_stat, b.pkt_ok_von, b.pkt_ok_am, b.punkte, (CASE '
    . $this->dboperation->dbparser->isNull('b.punkte', '0') . ' '
    . 'WHEN 0 THEN (select k.punkte from kurse k where k.nr = b.knr) ELSE b.punkte END) AS resultierendePunkte '
    . 'from belegung b where b.knr=' . "'$knr' and b.tnr='$tnr'";

    $this->dboperation->clear();
    $this->dboperation->query($sql);
    $result = $this->getNewObject();
    if ($this->dboperation->rowcount() > 0) {
      $this->dboperation->selectrow(0);
      $result->id = $this->getDatamodulValue('id');
      $result->tnr = $tnr;
      $result->knr = $knr;
      $result->punkte = $this->getDatamodulValue('resultierendePunkte');
      $result->pkt_ok_stat = $this->getDatamodulValue('pkt_ok_stat');
      $result->pkt_ok_am = $this->getDatamodulValue('pkt_ok_am');
      $result->pkt_ok_von = $this->getDatamodulValue('pkt_ok_von');
      
      $result->status = $this->getDatamodulValue('status_1');
    }

    return $result;
  }

  
  public function getNiveauByTnr($pTnr)
  {
    $tnr = $this->dboperation->getInt4Sql($pTnr);
    $sql = 'select max(niveau) as niveau from belegung where tnr=' . $tnr;
    $this->dboperation->clear();
    $this->dboperation->query($sql);
    $result = '';
    if ($this->dboperation->rowcount() > 0) {
      $this->dboperation->selectrow(0);
      $result = $this->getDatamodulValue('niveau');
    }

    return $result;
  }

  
  public function getNiveauByTnrFachb($pTnr, $pFachb)
  {
    $tnr = $this->dboperation->getInt4Sql($pTnr);
    $fachb = $this->dboperation->getString4Sql($pFachb);
    $sql = 'select max(niveau) as niveau from belegung b where b.tnr=' . $tnr;
    $sql .= ' and b.knr in (select nr from kurse k where k.fachb = \'' . $fachb . '\')';
    $this->dboperation->clear();
    $this->dboperation->query($sql);
    $result = '';
    if ($this->dboperation->rowcount() > 0) {
      $this->dboperation->selectrow(0);
      $result = $this->getDatamodulValue('niveau');
    }

    return $result;
  }

  
  public function getRollenByBelegId($pBelegId = null)
  {
    static $_dbw = null;
    if (is_null($_dbw)) {
      $_dbw = new DBWorkHLRolle($this->dbtyp, true);
    }

    return $_dbw->getRollenByBelegId($pBelegId);
  }

  
  public function getBelegIds4TeilnehmerBkBvTn($bkbvtnAry)
  {
    if (!is_array($bkbvtnAry) || empty($bkbvtnAry)) {
      return array();
    }

    $tnrZbTuples = array_map(function($bkbvtn) {
      return ' ( ' . $bkbvtn->tnr . ', ' . $bkbvtn->zb . ' ) ';
    }, $bkbvtnAry);
    $tnrZbList = implode(', ', $tnrZbTuples); 

    
    
    
    
    $sql = ' SELECT DISTINCT b.id ';
    $sql .= ' FROM belegung b ';
    $sql .= ' JOIN kurse k ON b.knr = k.nr ';
    $sql .= ' JOIN teilnehm t ON b.tnr = t.nr ';
    $sql .= ' JOIN kurse_kategorien kk ON kk.knr = k.nr ';
    $sql .= ' JOIN kategorien kat ON kat.id = kk.kategorie_id ';
    $sql .= ' WHERE (b.tnr, kat.vaterid) IN ( '; 
    $sql .= $tnrZbList;
    $sql .= ' ) ';
    $sql .= $this->getSearchSQL('b.');
    $sql .= $this->getCompleteOrderByDefault('b.id');

    $this->dboperation->clear();
    $this->dboperation->query($sql);

    return $this->getAllRowsSingleColumn('id');
  }

  
  public static function getNichtKindBelegungenSQLPart($pAlleBelegungenKinderkurs = true, $pPraefixKurs = 'k.')
  {
    if (System::isKuferSql5()) {
      $sqlPartKinderkurs = '';
      if ($pAlleBelegungenKinderkurs) {
        $sqlPartKinderkurs = ' OR ' . $pPraefixKurs . 'typ = \'K\'';
      }

      return ' AND ((b.firma = 0 OR b.firma IS NULL OR b.bezug != 3 OR bezug IS NULL)' . $sqlPartKinderkurs . ') ';
    }

    return '';
  }

  
  public static function getKindBelegungenSQLPart($pOhneBelegungenKinderkurs = true, $pPraefixKurs = 'k.')
  {
    if (System::isKuferSql5()) {
      $sqlPartKinderkurs = '';
      if ($pOhneBelegungenKinderkurs) {
        $sqlPartKinderkurs = ' AND ' . $pPraefixKurs . 'typ != \'K\'';
      }

      return ' AND (b.firma > 0 OR b.firma = -1) AND b.bezug = 3 ' . $sqlPartKinderkurs;
    }

    return '';
  }

  
  public function getKindBelgungenByTnrAndKnr($pTnr, $pKnr)
  {
    $tnr = $this->dboperation->getInt4Sql($pTnr);
    $knr = $this->dboperation->getString4Sql($pKnr);

    $sql = 'SELECT ' . $this->select . ' FROM belegung b'
           . ' WHERE b.knr = \'' . $knr . '\''
           . ' AND b.firma = ' . $tnr . ' AND b.bezug = 3'
            . $this->getCompleteOrderByDefault('id');

    $this->dboperation->clear();
    $this->dboperation->query($sql);

    return $this->getAllRows();
  }

  
  public function getKinderAnzahlByKursIds($pKursIds, $pNurAngemeldete = true, $pNurOnlineteilnahme = false, $pRefreshCache = false)
  {
    if (!is_array($pKursIds) || empty($pKursIds)) {
      return array();
    }

    $result = array();
    $knrs = array();
    foreach ($pKursIds as $knr) {
      $cleanKnr = $this->dboperation->getString4Sql($knr);
      if ($pRefreshCache || !isset(self::$_cache_Anzahlkinder[$cleanKnr . '|' . $pNurAngemeldete . '|' . $pNurOnlineteilnahme])) {
        $knrs[] = $cleanKnr;
        self::$_cache_Anzahlkinder[$cleanKnr . '|' . $pNurAngemeldete . '|' . $pNurOnlineteilnahme] = 0;
      }
      $result[$cleanKnr] = self::$_cache_Anzahlkinder[$cleanKnr . '|' . $pNurAngemeldete . '|' . $pNurOnlineteilnahme];
    }

    if (empty($knrs)) {
      return $result;
    }

    $sqlPartNurAngemeldete = '';
    if ($pNurAngemeldete) {
      $sqlPartNurAngemeldete = ' AND (b.status_1 IN (' . ConstantOperations::getStatusangemeldetSQLStr() . ') OR b.status_1 IS NULL) ';
    }

    $sql = 'SELECT b.knr, count(b.id) kinderanzahl '
           . 'FROM belegung b '
           . 'LEFT JOIN kurse k ON b.knr = k.nr '
           . 'WHERE b.knr IN (' . StringOperations::convertArray2InList($knrs) . ') '
            . $sqlPartNurAngemeldete
            . self::getSqlPartNurOnlineteilname($pNurOnlineteilnahme)
            . $this->getKindBelegungenSQLPart(false)
           . 'GROUP BY b.knr';

    $this->dboperation->clear();
    $this->dboperation->query($sql);

    $count = $this->dboperation->rowcount();
    for ($i = 0; $i < $count; $i++) {
      $this->dboperation->selectrow($i);
      $knr = $this->dboperation->fieldbyname('knr');
      self::$_cache_Anzahlkinder[$knr . '|' . $pNurAngemeldete . '|' . $pNurOnlineteilnahme] = $this->dboperation->fieldbyname('kinderanzahl');
      $result[$knr] = self::$_cache_Anzahlkinder[$knr . '|' . $pNurAngemeldete . '|' . $pNurOnlineteilnahme];
    }

    return $result;
  }

  
  public function getKinderAnzahlByKnr($pKnr, $pNurAngemeldete = true, $pNurOnlineteilnahme = false, $pRefreshCache = false)
  {
    $result = $this->getKinderAnzahlByKursIds(array($pKnr), $pNurAngemeldete, $pNurOnlineteilnahme, $pRefreshCache);

    return $result[$pKnr];
  }

  
  public function getCountKinderInWartelisteByKursen($pKnrs, $pNurOnlineteilnahme = false, $pRefreshCache = false)
  {
    return $this->getCountTnInWartelisteByKursen($pKnrs, $pNurOnlineteilnahme, true, $pRefreshCache);
  }

  
  public function getCountKinderInWartelisteByKnr($pKnr, $pNurOnlineteilnahme = false, $pRefreshCache = false)
  {
    $result = $this->getCountKinderInWartelisteByKursen(array($pKnr), $pNurOnlineteilnahme, $pRefreshCache);

    return $result[$pKnr];
  }

  
  public function getLatestAnmeldungByKnrAndTnrQuery($pTnr, $pKnr)
  {
    return $this->getAllQuery()
        ->and('b.tnr = :tnr:')
        ->and('b.knr = :knr:')
        ->paramInt('tnr', $pTnr)
        ->paramString('knr', $pKnr)
        ->orderByDesc('b.anm_datum');
  }

  
  public function getLatestAnmeldungByKnrAndTnr($pTnr, $pKnr)
  {
    $builder = $this->getLatestAnmeldungByKnrAndTnrQuery($pTnr, $pKnr);

    $this->dboperation->clear();
    $this->dboperation->query($builder->getSQL());

    return $this->getFirstRow();
  }

  public function checkMahnstufenForTeilnehmer(int $tnr, array $mahnstufen): bool
  {
    $belegungen = $this->getBelegungenbyTeilnehmerNR($tnr);
    foreach ($belegungen as $belegung) {
      if (in_array($belegung->bms, $mahnstufen)) {
        return true;
      }
    }

    return false;
  }

  protected function translateVarNameForOrderBy($varname)
  {
    if ($varname == 'ort') {
      return 'k.ort';
    }
    if ($varname == 'nr') {
      return 'k.nr';
    }

    return parent::translateVarNameForOrderBy($varname);
  }

  public static function getSqlPartNurOnlineteilname(bool $nurOnlineteilnahme): string
  {
    if ($nurOnlineteilnahme) {
      return " AND b.nuronline = 'W' ";
    } else {
      return " AND (b.nuronline is NULL OR b.nuronline != 'W') ";
    }
  }
}