<?php
/*=======================================================================
 *
 * caglobal.inc.php
 *
 * Autor: Carsten Annacker
 *
 =======================================================================*/

include_once("../include/dbglobal.inc.php");
include_once("../jobs/job_courier.inc.lib.php");
include_once("../include/global.inc.php");
include_once("../include/services_func.inc.php");
include_once("../include/calendar.inc.php");

/**
 *  Indexkonstanten für Frames, Forms und Formularelemente
 *
 *  Wenn sich die Anordnung von Formularelementen in den 
 *  HTML-Dateien ändert, müssen die hier aufgeführten
 *  Konstanten angepasst werden, sonst funktionieren die
 *  betroffenen Funktionen nicht mehr.
 *
 *  Diese Werte müssen UNBEDINGT mit denen übereinstimmen,
 *  die in 'lib_globals.js' definiert sind, da sie auch in
 *  javascript benötigt werden!
 *
 *  Anm.: Durch die Verwendung von Klartextnamen könnte man
 *  diese Konstanten umgehen. Dies führt aber leider zu Proble-
 *  men, wenn der Code "obfuscated" wird.
 */

//define ("JOB_TOUR", 1);       // Frame
//define ("TOURFORM", 1);       // Form
//define ("VON_CSC_ID", 0);     // Element
////define ("JB_COSTSPLIT", 31);
//define ("JB_CASH", 31);
//define ("JOB_OPTIONS", 2);    // Frame
//define ("TOUROPTIONS", 0);    // Form
//define ("CR_ID_ORDER", 0);    // Element
//define ("JB_WAITSTORNO", 2);  // -"- ...
//define ("JB_WAITTIME_HOUR", 12);
//define ("JB_WAITTIME_MINUTE", 13);
//define ("JB_WEIGHT", 3);
//define ("VHT_ID", 14);
//define ("DAYIDX", 4);
//define ("MONIDX", 5);
//define ("YEARIDX", 6);
//define ("HOURIDX", 8);
//define ("MINUTEIDX", 9);
//define ("RHYTHMIDX", 15);
//define ("SAVEDTOUR", 10);
//define ("JB_FIXPRICE", 11);
//define ("JB_TOURNAME", 16);
//define ("JOBLIST", 18);
//define ("AFTERWARDS", 19);
//define ("JB_GLOBALJOB", 20);
//define ("JB_FREETEXT_1", 26);

define ("JL_CSC_ID", 0);      // jobList Indices
define ("JL_TR_COMP", 1);
define ("JL_TR_PERSON", 2);
define ("JL_AD_STREET", 3);
define ("JL_TR_HSNO", 4);
define ("JL_AD_COUNTRY", 5);
define ("JL_AD_ZIPCODE", 6);
define ("JL_AD_CITY", 7);
define ("JL_TR_REMARK", 8);
define ("JL_TR_PHOTO", 9);
define ("JL_TR_COMMISSION_NO", 10);
define ("JL_TR_TRACKING", 11);
define ("JL_HIDE_TR_REMARK", 12);
define ("JL_TR_WARE_FROM", 13);
define ("JL_TR_WARE_TO", 14);
define ("JL_CSC_ID_PAYER", 15);
define ("JL_TR_MEDIATIONAREA_ID", 16);
define ("JL_TR_ID", 17);

/**
 *  Weitere Konstanten
 *
 */

define("GETDATAHTMLTPL", "../jobs/get_data.tpl.htm");

/**
 *  Funktionen
 *
 */

function getTourData($jb_id, $tr_sort, $dbh_tr = "tour")
{
  global $db, $_copy_jobs_flag, $jb_storno, $_copy_jobs_flag_ori, $phpVersion;

  // Name der Tabellen
  if (!(isset($_copy_jobs_flag) && $_copy_jobs_flag == true) || (isset($jb_storno) && $jb_storno > 0) ||
    (isset($_copy_jobs_flag_ori) && $_copy_jobs_flag_ori == true)):
    $_tour_table = $dbh_tr;
  else:
    $_tour_table = "tour_backup";
  endif;
  // Tour-Daten holen
  $sqlquery = "SELECT csc_id, tr_comp, tr_person, tr_remark, tr_hsno, ad_id, tr_status, tr_ware_from_to, tr_commission_no, tr_mediationarea_id, tr_status, tr_sign, tr_signname, tr_finishtime, tr_id " .
    "FROM $_tour_table WHERE jb_id = '$jb_id' AND tr_sort = '$tr_sort'";

//  $result = $db->dbQ($sqlquery);
  $result = $db->query($sqlquery);
  if ($row = ($phpVersion >= "8.0" ? $result->fetch_assoc() : $result->fetchRow())):
      $csc_id = $row["csc_id"];
      $tr_comp = $row["tr_comp"];
      $tr_person = $row["tr_person"];
      $tr_remark = $row["tr_remark"];
      $tr_hsno = $row["tr_hsno"];
      $tr_status = $row["tr_status"];
      $tr_ware_from_to = $row["tr_ware_from_to"];
      $tr_commission_no = $row["tr_commission_no"];
      $tr_mediationarea_id = $row["tr_mediationarea_id"];
      $tr_status = $row["tr_status"];
      $tr_sign = $row["tr_sign"];
      $tr_signname = $row["tr_signname"];
      $tr_finishtime = $row["tr_finishtime"];
      $tr_id = $row["tr_id"];
      $ad_id = $row["ad_id"];
  endif;

//  $row = $db->getRow($sqlquery);
//  if (DB::isError($row)) reportDie ("$PHP_SELF: '$sqlquery'" . $row->getMessage());
      
  // Adress-Daten holen
  list($ad_street, $ad_zipcode, $ad_city, $ad_country) =
    getFieldsValueFromId("address", "ad_id", $ad_id,
      array("ad_street", "ad_zipcode", "ad_city", "ad_country"));
//  if (!(isset($_copy_jobs_flag) && $_copy_jobs_flag == true)):
//  else:
    $tr_comp    = my_str_check($tr_comp);
    $tr_person  = my_str_check($tr_person);
    $ad_street  = my_str_check($ad_street);
    $tr_hsno    = my_str_check($tr_hsno);
    $ad_zipcode = my_str_check($ad_zipcode);
    $ad_city    = my_str_check($ad_city);
    $ad_country = my_str_check($ad_country);
    $tr_remark  = my_str_check($tr_remark);
    $tr_mediationarea_id = my_str_check($tr_mediationarea_id);
    $tr_sign    = my_str_check($tr_sign);
//  endif;
  return(array($csc_id, $tr_comp, $tr_person, $ad_street, $tr_hsno,
    $ad_zipcode, $ad_city, $ad_country, $tr_remark, $tr_status, $tr_ware_from_to, $tr_commission_no, $tr_mediationarea_id, $tr_status, $tr_sign, $tr_signname, $tr_finishtime, $tr_id));
}

function getJobChildren($jb_id, $dbh_jb, $no_dates = "false")
{
  global $db, $phpVersion;

  $tmp_add_jb_ids = "";
  $tmp_add_sids = "";
  $tmp_add_prices = "";
  $jb_totalprice = "";
  
  // Alle Unteraufträge dieses Auftrages finden
  $sqlquery = "SELECT jb_id, cr_sid, jb_fixprice FROM $dbh_jb WHERE jb_id_parent = '$jb_id'";
  $res = $db->query($sqlquery);
  if (DB::isError($res)) reportDie ("$PHP_SELF: '$sqlquery': " . $res->getMessage());
  while ($row = ($phpVersion >= "8.0" ? $res->fetch_assoc() : $res->fetchRow())):
    // Der Unterauftrag hat noch einen eigenen Unterauftrag (Gegenbeleg)
    $sqlquery = "SELECT jb_id FROM $dbh_jb WHERE jb_id_parent = '" . $row['jb_id'] . "'";
//    $result = $db->dbQ($sqlquery);
    $result = $db->query($sqlquery);
//    $rowSub = $result->fetch_assoc();
    $rowSub = ($phpVersion >= "8.0" ? $result->fetch_assoc() : $result->fetchRow());
    // Daten zusammenstellen, die an den Calculator durchgereicht werden    

    if ($tmp_add_jb_ids != "")
      $tmp_add_jb_ids .= "¹";

    if ($no_dates != "true") // in dem Fall "true" wird eine Konserve geladen, die natürlich mit leeren Jobnummern erstellt werden muss!
      $tmp_add_jb_ids .= $row['jb_id'] . "²" . $rowSub["jb_id"];
    if ($tmp_add_sids != "")
      $tmp_add_sids .= "¹";
    $tmp_add_sids .= $row['cr_sid'];
    $jb_fixprice = $row['jb_fixprice'];
    if ($jb_fixprice == 0) $jb_fixprice = "";
    if ($jb_fixprice != 0)
      $jb_fixprice = str_replace(".", ",", sprintf("%01.2f", $jb_fixprice));
    if ($tmp_add_prices != "")
      $tmp_add_prices .= "¹";
    $tmp_add_prices .= $jb_fixprice;
  endwhile;
  $res->free();
  return(array($tmp_add_jb_ids, $tmp_add_sids, $tmp_add_prices));
}

function updateJobChildren($jb_id, $jb_finishtime, $cr_id, $cr_sid)
{
  global $db, $phpVersion;

  // Alle Unteraufträge dieses Auftrages finden die Gegenbelege anpassen
  $sqlquery = "SELECT jb_id, cr_sid FROM job WHERE jb_id_parent = '$jb_id'";
  $res = $db->query($sqlquery);
  if (DB::isError($res)) reportDie ("$PHP_SELF: '$sqlquery': " . $res->getMessage());
  while ($row = ($phpVersion >= "8.0" ? $res->fetch_assoc() : $res->fetchRow())):
    // Der Unterauftrag hat noch einen eigenen Unterauftrag (Gegenbeleg)
    $sqlquery = "SELECT jb_id FROM job WHERE jb_id_parent = '" . $row['jb_id'] . "'";
    $rowSub = $db->getRow($sqlquery);
    if (DB::isError($rowSub)) reportDie ("$PHP_SELF: '$sqlquery'" . $rowSub->getMessage());
    // beim gefundenen Job das Fahrzeug ändern ...
    updateStmt("job", "jb_id", $rowSub['jb_id'], array("cr_id", $cr_id, "cr_sid", $cr_sid, "jb_finishtime", $jb_finishtime));
  endwhile;
  $res->free();
}

function deleteJobChildren($jb_id)
{
  global $db, $phpVersion;

  if (existsEntry("job", array("jb_id", $jb_id))) {
    // Alle Unteraufträge dieses Auftrages finden und löschen
    $sqlquery = "SELECT jb_id FROM job WHERE jb_id_parent = '$jb_id'";
    $res = $db->query($sqlquery);
    if (DB::isError($res)) reportDie ("$PHP_SELF: '$sqlquery': " . $res->getMessage());
    while ($row = ($phpVersion >= "8.0" ? $res->fetch_assoc() : $res->fetchRow())):
      // Der Unterauftrag hat noch einen eigenen Unterauftrag (Gegenbeleg)
      $sqlquery = "SELECT jb_id FROM job WHERE jb_id_parent = '" . $row['jb_id'] . "'";
      $rowSub = $db->getRow($sqlquery);
      if (DB::isError($rowSub)) reportDie ("$PHP_SELF: '$sqlquery'" . $rowSub->getMessage());
      // die beiden gefunden Jobs löschen ...
      deleteStmt("job", "jb_id = " . $row['jb_id']);
      deleteStmt("tourservice", "jb_id = " . $row['jb_id'] );
      deleteStmt("tour", "jb_id = " . $row['jb_id'] );
      deleteStmt("genericdatacontainer", "gdc_obj_type = 'jb' AND gdc_obj_id = " . $row['jb_id'] . " AND gdc_gen_fieldname = 'jb_toll'");
      deleteStmt("job", "jb_id = " . $rowSub['jb_id']);
      deleteStmt("tourservice", "jb_id = " . $rowSub['jb_id']);
      deleteStmt("tour", "jb_id = " . $rowSub['jb_id']);    
      deleteStmt("genericdatacontainer", "gdc_obj_type = 'jb' AND gdc_obj_id = " . $rowSub['jb_id'] . " AND gdc_gen_fieldname = 'jb_toll'");
    endwhile;
    $res->free();
  }
}

function copyTourData($jb_id, $jb_id_target)
{
  global $db;
  
  $i = 1;
  do {
    if (existsEntry("tour", array("jb_id", $jb_id, "tr_sort", $i))):
      $tourFound = 1;
      $sqlquery = "SELECT csc_id, tr_comp, tr_person, tr_phone, tr_remark, tr_hsno, ad_id, tr_status, tr_ware_from_to, tr_commission_no, tr_mediationarea_id " .
        "FROM tour WHERE jb_id = '$jb_id' AND tr_sort = '$i'";
      $row = $db->getRow($sqlquery);
      if (DB::isError($row)) reportDie ("$PHP_SELF: '$sqlquery'" . $row->getMessage());
      if (existsEntry("tour", array("jb_id", $jb_id_target, "tr_sort", $i))):
        deleteStmt("tour", "jb_id = $jb_id_target AND tr_sort = $i" . $tmp_add_jb_idsArr[$i]);
      endif;
      insertStmt("tour", 
        array("jb_id", $jb_id_target, "tr_sort", $i,
        "csc_id", $row["csc_id"], "tr_comp", my_str_check($row["tr_comp"]), "tr_person", my_str_check($row["tr_person"]), "tr_phone", my_str_check($row["tr_phone"]), "tr_remark", my_str_check($row["tr_remark"]),
        "tr_hsno", my_str_check($row["tr_hsno"]), "tr_status", "1", "tr_ware_from_to", $row["tr_ware_from_to"], "tr_commission_no", my_str_check($row["tr_commission_no"]), 
        "tr_mediationarea_id", $row["tr_mediationarea_id"], "ad_id", $row["ad_id"]));
    else:
      $tourFound = 0;
    endif;
    $i++;
  } while ($tourFound == 1);
}

function saveJobChildren($jb_id, $jb_dataArr, $tmp_add_jb_ids, $tmp_add_sids, $tmp_add_prices, $jb_markup, $tmp_discount_rate, $jb_serviceprice)
{
  global $db, $hq_id;

  if (getParameterValue("0", "INV_CHILDREN_DISCOUNT", $hq_id) != "1")
    $tmp_discount_rate = 0;

  $tmp_add_jb_idsArr = array_filter(explode("¹", $tmp_add_jb_ids));
  $maxcount = count($tmp_add_jb_idsArr);
  $tmp_add_sidsArr = array_filter(explode("¹", $tmp_add_sids));
  if (count($tmp_add_sidsArr) > $maxcount)
    $maxcount = count($tmp_add_sidsArr);
  $tmp_add_pricesArr = array_filter(explode("¹", $tmp_add_prices));
  if (count($tmp_add_pricesArr) > $maxcount)
    $maxcount = count($tmp_add_pricesArr);
  $jobHasChildren = false;

  if ($maxcount > 0):
    // die Datumse...
    $jb_ordertime = getFieldValueFromId("job", "jb_id", $jb_id, "jb_ordertime");
    $jb_taketime = getFieldValueFromId("job", "jb_id", $jb_id, "jb_taketime");
    $jb_finishtime = getFieldValueFromId("job", "jb_id", $jb_id, "jb_finishtime");
    $jb_invtext_cr = getFieldValueFromId("job", "jb_id", $jb_id, "jb_invtext_cr");
    $hq_id = getFieldValueFromId("job", "jb_id", $jb_id, "hq_id");
    $today = getdate();
    $jb_booktime = $today['year'] . "-" . $today['mon'] . "-" . $today['mday'] . " " .
      $today['hours'] . ":" . $today['minutes'] . ":" . $today['seconds'];
    $formattedLine = "Unternehmerverrechnung zu Auftrag Nr. " . $jb_id;
    while (strlen($formattedLine) < getParameterValue("0", "INV_MAXCOLS_EXPORT", $hq_id)):
      $formattedLine .= " ";
    endwhile;    
    // Rechnungste der Unteraufträge, Datumse hinzufügen    
    array_push ($jb_dataArr, "jb_invtext", $formattedLine . "\n" . (getParameterValue("0", "INV_CHILD_NOFREETEXT", $hq_id) == '1' ? my_str_check($jb_invtext_cr) : ""),
      "jb_ordertime", $jb_ordertime, "jb_taketime", $jb_taketime, "jb_finishtime", $jb_finishtime, "jb_booktime", $jb_booktime);
    // Daten des Hauptunternehmers für Belastungen
    $main_cr_sid = getFieldValueFromId("job", "jb_id", $jb_id, "cr_sid");
    $main_cr_id = getFieldValueFromId("job", "jb_id", $jb_id, "cr_id");
    // Der Komplettbetrag der Maut wird (vorerst) nur für den ersten Child-Auftrag gespeichert
    $jb_toll = $db->getOne("SELECT gdc_content FROM genericdatacontainer WHERE gdc_obj_type = 'jb' AND gdc_obj_id = " . $jb_id . " AND gdc_gen_fieldname = 'jb_toll'");
  
    for ($i = 0; $i < $maxcount; $i++):
      // jb_id für Beleg und Gegenbeleg extrahieren
      $tmp_add_jb_idsSubArr = array_filter(explode("²", $tmp_add_jb_idsArr[$i]));
      // Preis formatieren
      $tmp_add_pricesArr[$i] = (float) str_replace(",", ".", $tmp_add_pricesArr[$i]);  
      // get cr_id from cr_sid
      $tmp_cr_id = getFieldValueFromId("couriervehicle", "crvh_sid", $tmp_add_sidsArr[$i], "cr_id");

      $jb_subtotal = round($tmp_add_pricesArr[$i] * (1 - ($tmp_discount_rate / 100)), 2);
      $jb_totalprice = round($jb_subtotal * (1 + ($jb_markup / 100)), 2);
      $jb_subtotal += $jb_serviceprice;
      $jb_totalprice += $jb_serviceprice;
      $jb_cr_price_sum += $jb_totalprice;
      // prepare data for positive and negative jobs
      $tmp_jb_dataArr1 = array_merge($jb_dataArr, array("csc_id_payer", getParameterValue("0", "CSC_ID_PAYER_CALCULATOR", $hq_id), "jb_totalprice", $jb_totalprice, "jb_cr_price", $jb_totalprice,
        "jb_fixprice", $tmp_add_pricesArr[$i], "jb_subtotalprice", $jb_subtotal, "jb_serviceprice", $jb_serviceprice, "jb_markup", $jb_markup,
        "cr_id", $tmp_cr_id, "cr_sid", $tmp_add_sidsArr[$i], "cr_id_order", $tmp_cr_id, "jb_id_parent", $jb_id, "jb_createtime", date("Y-m-d H:i:s")));
      $tmp_jb_dataArr2 = array_merge($jb_dataArr, array("csc_id_payer", getParameterValue("0", "CSC_ID_PAYER_CALCULATOR", $hq_id), "jb_totalprice", ($jb_totalprice * -1), "jb_cr_price", ($jb_totalprice * -1),
        "jb_fixprice", ($tmp_add_pricesArr[$i] * -1), "jb_subtotalprice", ($jb_subtotal * -1),  "jb_serviceprice", ($jb_serviceprice * -1), "jb_markup", $jb_markup,
        "cr_id", $main_cr_id, "cr_sid", $main_cr_sid, "cr_id_order", $main_cr_id, "jb_createtime", date("Y-m-d H:i:s")));
      $tmp_tourservice_dataArr1 = array("csc_id", getParameterValue("0", "CSC_ID_PAYER_CALCULATOR", $hq_id), "tr_sort", "0",
        "srv_id", "0", "trs_srv_name", "Fixpreis", "srvt_id", "0", "trs_srvt_name", "", 
        "trs_price", round($tmp_add_pricesArr[$i] * (1 + ($jb_markup / 100)), 2), "trs_discount", $tmp_discount_rate);
      $tmp_tourservice_dataArr2 = array("csc_id", getParameterValue("0", "CSC_ID_PAYER_CALCULATOR", $hq_id), "tr_sort", "0",
        "srv_id", "0", "trs_srv_name", "Fixpreis", "srvt_id", "0", "trs_srvt_name", "", 
        "trs_price", (round($tmp_add_pricesArr[$i] * (1 + ($jb_markup / 100)), 2) * -1), "trs_discount", $tmp_discount_rate);
      $tmp_tourservice_dataArr11 = array();
      $tmp_tourservice_dataArr21 = array();
      if ($jb_serviceprice > 0) {
        $tmp_tourservice_dataArr11 = array("csc_id", getParameterValue("0", "CSC_ID_PAYER_CALCULATOR", $hq_id), "tr_sort", "0",
          "srv_id", "0", "trs_srv_name", "Servicepreis", "srvt_id", "0", "trs_srvt_name", "", 
          "trs_price", $jb_serviceprice, "trs_discount", $tmp_discount_rate);
        $tmp_tourservice_dataArr21 = array("csc_id", getParameterValue("0", "CSC_ID_PAYER_CALCULATOR", $hq_id), "tr_sort", "0",
          "srv_id", "0", "trs_srv_name", "Servicepreis", "srvt_id", "0", "trs_srvt_name", "", 
          "trs_price", ($jb_serviceprice * -1), "trs_discount", $tmp_discount_rate);
      }
      // write / update / delete jobs
      if ($tmp_add_jb_idsArr[$i] == "" && $tmp_add_sidsArr[$i] != ""):
        // neuer Kinder-Job -> neuer Auftrag
        // Gutschrift beim Sub-Unternehmer
        insertStmt("job", $tmp_jb_dataArr1);
        $jbIdNew = getLastInsertId();
        array_push ($tmp_tourservice_dataArr1, "jb_id", $jbIdNew);
        insertStmt("tourservice", $tmp_tourservice_dataArr1);
        if (count($tmp_tourservice_dataArr11) > 0) {
          array_push ($tmp_tourservice_dataArr11, "jb_id", $jbIdNew);
          insertStmt("tourservice", $tmp_tourservice_dataArr11);
		}
        copyTourData($jb_id, $jbIdNew);
        if ($i == 0 && $jb_toll != ""):
          insertStmt("genericdatacontainer", array("gdc_obj_type", "jb", "gdc_obj_id", $jbIdNew, "gdc_gen_fieldname", "jb_toll", "gdc_content", trim($jb_toll), "gdc_context", ''));
        endif;
        // Belastung beim Haupt-Unternehmer
        array_push ($tmp_jb_dataArr2, "jb_id_parent", $jbIdNew);
        insertStmt("job", $tmp_jb_dataArr2);
        $jbIdNew = getLastInsertId();
        array_push ($tmp_tourservice_dataArr2, "jb_id", $jbIdNew);
        insertStmt("tourservice", $tmp_tourservice_dataArr2);
        if (count($tmp_tourservice_dataArr12) > 0) {
          array_push ($tmp_tourservice_dataArr12, "jb_id", $jbIdNew);
          insertStmt("tourservice", $tmp_tourservice_dataArr12);
		}
        copyTourData($jb_id, $jbIdNew);
        if ($i == 0 && $jb_toll != ""):
          insertStmt("genericdatacontainer", array("gdc_obj_type", "jb", "gdc_obj_id", $jbIdNew, "gdc_gen_fieldname", "jb_toll", "gdc_content", trim($jb_toll) * -1, "gdc_context", ''));
        endif;
        // und merken
        $jobHasChildren = true;
      endif;
      if ($tmp_add_jb_idsArr[$i] != "" && $tmp_add_sidsArr[$i] == ""):
        // alter Kinder-Job wurde gelöscht -> Auftrag löschen
        // Gutschrift löschen
        deleteStmt("job", "jb_id = " . $tmp_add_jb_idsSubArr[0]);
        deleteStmt("tourservice", "jb_id = " . $tmp_add_jb_idsSubArr[0]);
        deleteStmt("tour", "jb_id = " . $tmp_add_jb_idsSubArr[0]);
        deleteStmt("genericdatacontainer", "gdc_obj_type = 'jb' AND gdc_obj_id = " . $tmp_add_jb_idsSubArr[0] . " AND gdc_gen_fieldname = 'jb_toll'");
        // Belastung löschen
        deleteStmt("job", "jb_id = " . $tmp_add_jb_idsSubArr[1]);
        deleteStmt("tourservice", "jb_id = " . $tmp_add_jb_idsSubArr[1]);
        deleteStmt("tour", "jb_id = " . $tmp_add_jb_idsSubArr[1]);
        deleteStmt("genericdatacontainer", "gdc_obj_type = 'jb' AND gdc_obj_id = " . $tmp_add_jb_idsSubArr[1] . " AND gdc_gen_fieldname = 'jb_toll'");
      endif;
      if ($tmp_add_jb_idsArr[$i] != "" && $tmp_add_sidsArr[$i] != ""):
        // alter Kinder-Job, könnte aber geändert worden sein -> Auftrag updaten
        // Gutschrift updaten
        updateStmt("job", "jb_id", $tmp_add_jb_idsSubArr[0], $tmp_jb_dataArr1);
        updateStmt("tourservice", "jb_id", $tmp_add_jb_idsSubArr[0], $tmp_tourservice_dataArr1, "trs_srv_name = 'Fixpreis'");
        deleteStmt("tourservice", "jb_id = " . $tmp_add_jb_idsSubArr[0] . " AND trs_srv_name = 'Servicepreis'");
        if (count($tmp_tourservice_dataArr11) > 0) {
          array_push ($tmp_tourservice_dataArr11, "jb_id", $tmp_add_jb_idsSubArr[0]);
          insertStmt("tourservice", $tmp_tourservice_dataArr11);
		}
        copyTourData($jb_id, $tmp_add_jb_idsSubArr[0]);
        // 31.08.2021: Ein updateStmt auf jb_toll reicht nicht, wenn es jb_toll noch gar nicht gab!
        // Deshalb erst löschen (falls doch schon da), dann neu anlegen
        deleteStmt("genericdatacontainer", "gdc_obj_type = 'jb' AND gdc_obj_id = " . $tmp_add_jb_idsSubArr[0] . " AND gdc_gen_fieldname = 'jb_toll'");
        if ($i == 0 && $jb_toll != ""):
          insertStmt("genericdatacontainer", array("gdc_obj_type", "jb", "gdc_obj_id", $tmp_add_jb_idsSubArr[0], "gdc_gen_fieldname", "jb_toll", "gdc_content", trim($jb_toll), "gdc_context", ''));
        endif;
//        updateStmt("genericdatacontainer", "gdc_obj_id", $tmp_add_jb_idsSubArr[0], array("gdc_content", trim($jb_toll)) ,"gdc_obj_type = 'jb' AND gdc_gen_fieldname = 'jb_toll'");
        // Belastung updaten
        updateStmt("job", "jb_id", $tmp_add_jb_idsSubArr[1], $tmp_jb_dataArr2);
        updateStmt("tourservice", "jb_id", $tmp_add_jb_idsSubArr[1], $tmp_tourservice_dataArr2, "trs_srv_name = 'Fixpreis'");
        deleteStmt("tourservice", "jb_id = " . $tmp_add_jb_idsSubArr[1] . " AND trs_srv_name = 'Servicepreis'");
        if (count($tmp_tourservice_dataArr21) > 0) {
          array_push ($tmp_tourservice_dataArr21, "jb_id", $tmp_add_jb_idsSubArr[2]);
          insertStmt("tourservice", $tmp_tourservice_dataArr21);
		}
        copyTourData($jb_id, $tmp_add_jb_idsSubArr[1]);
        updateStmt("genericdatacontainer", "gdc_obj_id", $tmp_add_jb_idsSubArr[1], array("gdc_content", trim($jb_toll) * -1) ,"gdc_obj_type = 'jb' AND gdc_gen_fieldname = 'jb_toll'");
        // und merken
        $jobHasChildren = true;
      endif;
    endfor;    
  endif;
  // Wert "-1" in Feld "jb_id_parent" schreiben, damit die Anzeige in den Auftragslisten vereinfacht wird
  if ($jobHasChildren)
    updateStmt("job", "jb_id", $jb_id, array("jb_id_parent", -1, "jb_cr_price", $jb_cr_price_sum));
  else
    updateStmt("job", "jb_id", $jb_id, array("jb_id_parent", 0));
}

function saveJobInsurance($jb_id_ori, $csc_id_payer, $vht_id, $jb_ordertime, $jb_value_of_goods, $jb_insurance_rate, $special_case)
{
  global $db, $hq_id, $usr_id;
//  $jb_id_pattern = 0;
//  $insurance_factor = 0;
// Wenn größer als Bus, dann nicht möglich?!?
// Kein Fuhrlohn?

//STB972105 => getParameterValue("0", "MASK_INSURANCE_DEBITOR", $hq_id)
//Konserven für
//PKW (PKW / Kombi) 17623966
//Kastenwagen (Kastenwagen / Bus) 18882311
//Berechnung automatisch statt Taschenrechner
// bis 9999,99 Euro = Auftragsnr. in Dispo Info

  if ($jb_value_of_goods == "" || $jb_value_of_goods == 0 || $jb_id_ori == "" || $jb_insurance_rate == 0)
    return;

  $jb_insurance_rates = array(
    1 => array(0.070, "Warengruppe 1, innerdeutscher Transport", 0.19), // BRD Warengruppe I
    2 => array(0.175, "Warengruppe 2, innerdeutscher Transport", 0.19), // BRD Warengruppe II
    3 => array(0.085, "Warengruppe 1, innereuropäischer Transport", 0), // Europa ohne GUS Warengr. I
    4 => array(0.200, "Warengruppe 2, innereuropäischer Transport", 0), // Europa ohne GUS Warengr. II
    5 => array(0.070, "innerdeutschem Botendienst", 0.19) // PKW Botendienst BRD 
  );

  $minimum_insurance = 10;
  $insurance_tax = $jb_insurance_rates[$jb_insurance_rate][2];
  $minimum_insurance *= (1 + $insurance_tax);
  $vht_id_insurance = 999;
  $cr_sid_insurance = getFieldValueFromId("headquarters", "hq_id", "$hq_id", "hq_mnemonic") . ($vht_id >= 7 ? "1777" : "1888");
//  $cr_sid = $db->getOne("SELECT crvh_sid FROM couriervehicle, courier WHERE couriervehicle.cr_id = courier.cr_id AND hq_id = " . $hq_id . " AND (crvh_sid LIKE '%1666%' OR crvh_sid LIKE '%1555%') ORDER BY crvh_sid DESC");
  $cr_id_insurance = $db->getOne("SELECT cr_id FROM couriervehicle WHERE crvh_sid = '" . $cr_sid_insurance . "'\n");
  $jb_status_insurance = ($special_case == 1 ? 1 : 2);

  $jb_fixpriceInsurance = ceil($jb_value_of_goods / 100 * $jb_insurance_rates[$jb_insurance_rate][0] * (1 + $insurance_tax) * 100) / 100;
  if ($jb_fixpriceInsurance < $minimum_insurance)
    $jb_fixpriceInsurance = $minimum_insurance;
  $jb_finishtime = $db->getOne("SELECT jb_createtime FROM job WHERE jb_id = " . $jb_id_ori);
  insertStmt("job",
    array("hq_id", $hq_id, "vht_id", $vht_id_insurance, "csc_id_payer", $csc_id_payer, "jb_ordertime", $jb_ordertime, "jb_reserv", 0, "cr_id", $cr_id_insurance, "cr_sid", $cr_sid_insurance, "cr_id_order",
      $cr_id_insurance, "jb_cr_filter", "", "jb_cr_filter_opt", "", "jb_waitstorno", 0, "jb_taketime", $jb_finishtime, "jb_status", $jb_status_insurance, "jb_incomplete", "1", "jb_globaljob", 0,
      "jb_finishtime", $jb_finishtime, "emp_id", $usr_id, "jb_fixprice", $jb_fixpriceInsurance, "jb_totalprice", $jb_fixpriceInsurance, "jb_subtotalprice", $jb_fixpriceInsurance,
      "jb_mediationarea_id", 0, "jb_mediationarea_name", "", "jb_sales_tax_rate", 19, "jb_sales_tax_rate_sign", "V", "jb_freetext_1",
      "Gebuchte Transportversicherung zu Auftrag " . $jb_id_ori . " mit " . str_replace(".", ",", sprintf("%01.2f", $jb_value_of_goods)) . " EUR Warenwert bei ". $jb_insurance_rates[$jb_insurance_rate][1] .
      " (" . str_replace(".", ",", $jb_insurance_rates[$jb_insurance_rate][0]) ."% Prämie vom Warenwert" . 
      ($insurance_tax > 0 ? " zzgl. " . ($insurance_tax * 100) . "% Versicherungssteuer" : "") .
      " - Mindestprämie " . str_replace(".", ",", sprintf("%01.2f", $minimum_insurance)) . " EUR)",      
      "jb_freetext_2", "²²²", "jb_tourdata", ".|.|DE", "jb_createtime", date("Y-m-d H:i:s"), "jb_id_parent", 0,
      "jb_dispoinfo", "HV zu " . $jb_id_ori, "jb_timeunits", 2, "jb_booktime", date("Y-m-d H:i:s")));
  $jbIdInsurance = getLastInsertId();

  $adIdInsurance = $db->getOne("SELECT ad_id FROM address WHERE ad_street = '.' AND ad_zipcode = '.' AND ad_city = '.' AND ad_country = 'DE'");
  if ($adIdInsurance == "") {
    insertStmt("address", array("ad_street", "Warenwert " . $jb_value_of_goods . " Euro", "ad_zipcode", ".", "ad_city", ".", "ad_country", "DE"));
    $adIdInsurance = getLastInsertId();
  }
  insertStmt("tour", array("jb_id", $jbIdInsurance, "ad_id", $adIdInsurance, "tr_sort", "1", "tr_comp", "Transportzusatzversicherung", "tr_hsno", ".", "tr_person", "", "csc_id", $csc_id_payer,
    "tr_remark", "", "tr_status", 0, "tr_ware_from_to", 0, "tr_mediationarea_id", 0));
  insertStmt("tourservice", array("jb_id", $jbIdInsurance, "csc_id", $csc_id_payer, "tr_sort", "0", "srv_id", "0", "trs_srv_name", "Fixpreis", "srvt_id", "0", "trs_srvt_name", "",
    "trs_price", $jb_fixpriceInsurance, "trs_discount", 0));
  mk_jb_invtext_full($jbIdInsurance);

// Verschiedene Sätze und Höchstgrenzen einbauen
// Versicherungsdebitoren klären
// Versicherungauftrag muss auch gelöscht / upgedatet werden können
  return $jbIdInsurance;
}

function getMediationarea_id($hq_id, $ad_zipcode, $ad_street, $tr_hsno) {
  global $db;
  
  $srvp_id = $db->getOne("SELECT srvpxa.srvp_id, srvpxa.srvpxa_mode FROM address AS ad, serviceplzaddress AS srvpxa"
             . " WHERE srvpxa.hq_id = '$hq_id' AND ad.ad_id = srvpxa.ad_id AND"
             . "       ad.ad_zipcode = '$ad_zipcode' AND ad.ad_street = '$ad_street'");
  if ($srvp_id == "")
    $srvp_id = $db->getOne("SELECT srvp_id FROM serviceplz WHERE srvp_plz = '$ad_zipcode'");
  return $srvp_id;
}

function getCustomerCouriers($db, $cs_id) {
  global $phpVersion;

  $cr_id_order_list_customer = "var cr_id_order_list_customer=[";
  $sqlquery = "SELECT cr.cr_sid FROM customercourier AS cc, courier AS cr WHERE cc.cs_id = $cs_id AND cc.cscr_relation = 1 AND cc.cr_id = cr.cr_id";
  $res = $db->query($sqlquery);
  if (DB::isError($res)) reportDie ("$PHP_SELF: '$sqlquery': " . $res->getMessage());
  $i = 0;
  while ($row = ($phpVersion >= "8.0" ? $res->fetch_assoc() : $res->fetchRow())):
    if ($i++ > 0) $cr_id_order_list_customer .= ",\n";
      $cr_id_order_list_customer .= "\"" . $row["cr_sid"] . "\"";
  endwhile;
  $res->free();
  $cr_id_order_list_customer .= "];\n";
  return ($cr_id_order_list_customer);
}

function getCustomerFilters($db, $cs_id) {

  $cs_filter_list_customer = "var cs_filter_list_customer=[";
  $cs_filter_jbedit = $db->getOne("SELECT cs_filter_jbedit FROM customer WHERE cs_id = $cs_id");
  if (trim($cs_filter_jbedit) != ""):
    $cs_filter_jbeditArr = explode(",", $cs_filter_jbedit);
    $i = 0;
    foreach ($cs_filter_jbeditArr as $cs_filter) {
      if (trim($cs_filter) != ""):
        if ($i++ > 0) $cs_filter_list_customer .= ",\n";
        $cs_filter_list_customer .= "\"" . $cs_filter . "\"";
      endif;
    }
  endif;
  $cs_filter_list_customer .= "];\n";
  return ($cs_filter_list_customer);
}

function getCustomerServices($db, $cs_id, $the_hq_id = 0) {
  global $hq_id, $phpVersion;
  
  // Matrix der Kunden mit speziellen Preisen
  $csSrvList = "cs_srv_list=[  ";
  $customerserviceList = array();
  $customer_specific = 1;
//die($the_hq_id);
  if ($the_hq_id == 0):
//echo "SELECT count(*) FROM service AS srv WHERE srv.cs_id = '$cs_id'";
//die($cs_id);
     // Prüfen, ob kundenspezifische Liste leer ist; wenn ja, dann globale Zentralenmatrix holen
      if ($db->getOne("SELECT count(*) FROM customerservice AS csv, service AS srv WHERE csv.cs_id = '$cs_id' AND csv.srv_id = srv.srv_id") >= 1 ||
        $db->getOne("SELECT count(*) FROM service AS srv WHERE srv.cs_id = '$cs_id'") >= 1):
          $sqlquery = "SELECT csv.cs_id, csv.srv_id, srv.srv_name FROM customerservice AS csv, service AS srv WHERE csv.cs_id = '$cs_id' AND csv.srv_id = srv.srv_id UNION" .
            " SELECT cs_id, srv_id, srv_name FROM service WHERE cs_id = '$cs_id' ORDER BY cs_id, srv_name";
    else:
      $sqlquery = "SELECT DISTINCT srv.srv_id, srv.srv_name FROM servicehistory AS srvh, service AS srv WHERE srvh.cs_id = '0' AND srvh.srv_id = srv.srv_id AND srvh.hq_id = '$hq_id' AND srv.srv_mode = 1 ORDER BY srv.srv_name";
      $customer_specific = 0;
    endif;
  else:
    $sqlquery = "SELECT csv.cs_id, csv.srv_id, srv.srv_name FROM customerservice AS csv, customer AS cs, service as srv, company as cmp WHERE csv.cs_id = cs.cs_id" . /* AND cs.hq_id = '$the_hq_id' */ " AND csv.srv_id = srv.srv_id AND srv.srv_name != 'DELETE' AND cs.cmp_id = cmp.cmp_id AND cmp_visible = 1 AND cmp_archived = 0 UNION" .
      " SELECT srv.cs_id, srv_id, srv_name FROM service AS srv, customer AS cs, company AS cmp WHERE cs.cs_id = srv.cs_id" . /* AND srv.hq_id = '$the_hq_id' */ " AND srv.srv_name != 'DELETE' AND cs.cmp_id = cmp.cmp_id AND cmp_visible = 1 AND cmp_archived = 0 ORDER BY cs_id, srv_name";
//    $sqlquery = "SELECT cs_id, srv_id, cssrv_sort FROM customerservice ORDER BY cs_id, cssrv_sort";
  endif;
  $res = $db->query($sqlquery);
  if (DB::isError($res)) reportDie ("$PHP_SELF: '$sqlquery': " . $res->getMessage());
  $prev_cs_id = 0;
  while ($row = ($phpVersion >= "8.0" ? $res->fetch_assoc() : $res->fetchRow())):
    if ($customer_specific == 0)
      $row["cs_id"] = $cs_id;
    if ($prev_cs_id != $row["cs_id"]):
      $customerserviceList[$row["cs_id"]] = array();
      $prev_cs_id = $row["cs_id"];
    endif;
//    $srv_name = getFieldValueFromId("service", "srv_id", $row["srv_id"], "srv_name");
    array_push ($customerserviceList[$row["cs_id"]], array($row["srv_id"], trim($row["srv_name"])));
    $csSrvList .= "[\"" . $row["cs_id"] . "\", \"" . trim($row["srv_name"]) . "\"],\n";
  endwhile;
  $res->free();
  $csSrvList = substr($csSrvList, 0, -2) . "];\n";
  if ($csSrvList == "cs_srv_list=[];\n"):
    $csSrvtList = "cs_srvt_list=[];\n";
    $csPriceList = "cs_price_list=[];\n";
    $csCalcMandList = "cs_calc_mand_list=[];\n";
    $setCalcButtonClassName =
      "if (typeof(parent.job_options.document.tourOptions.calcButton) != 'undefined')\n" .
      "  parent.job_options.document.tourOptions.calcButton.className = 'commission_no_disabled';\n";  
  else:
    $csSrvtList = "cs_srvt_list=[  ";
    $customerservicetypeList = array();
    if ($the_hq_id == 0):
      if ($customer_specific == 1):
          $sqlquery = "SELECT csvt.cs_id, csvt.srvt_id, srvt.srvt_name FROM customerservicetype AS csvt, servicetype AS srvt WHERE csvt.cs_id = '$cs_id' AND csvt.srvt_id = srvt.srvt_id UNION ALL " .
            "SELECT cs_id, srvt_id, srvt_name FROM servicetype WHERE cs_id = '$cs_id' ORDER BY cs_id, srvt_name";
      else:
        $sqlquery = "SELECT DISTINCT srvt.srvt_id, srvt.srvt_name FROM servicehistory AS srvh, servicetype AS srvt WHERE srvh.cs_id = '0' AND srvh.srvt_id = srvt.srvt_id AND srvh.hq_id = '$hq_id ' AND srvt.srvt_mode = '1' ORDER BY srvt.srvt_name";
      endif;
    else:
      $sqlquery = "SELECT csvt.cs_id, csvt.srvt_id, srvt.srvt_name FROM customerservicetype AS csvt, customer AS cs, servicetype AS srvt, company AS cmp WHERE csvt.cs_id = cs.cs_id" . /* AND cs.hq_id = '$the_hq_id' */ " AND csvt.srvt_id = srvt.srvt_id AND srvt.srvt_name != 'DELETE' AND cs.cmp_id = cmp.cmp_id AND cmp_visible = 1 AND cmp_archived = 0 UNION" .
        " SELECT srvt.cs_id, srvt_id, srvt_name FROM servicetype AS srvt, customer AS cs, company AS cmp WHERE cs.cs_id = srvt.cs_id" . /* AND srvt.hq_id = '$the_hq_id' */ " AND srvt.srvt_name != 'DELETE' AND cs.cmp_id = cmp.cmp_id AND cmp_visible = 1 AND cmp_archived = 0 ORDER BY cs_id, srvt_name";
//      $sqlquery = "SELECT cs_id, srvt_id, cssrvt_sort FROM customerservicetype ORDER BY cs_id, cssrvt_sort";
    endif;
    $res = $db->query($sqlquery);
    if (DB::isError($res)) reportDie ("$PHP_SELF: '$sqlquery': " . $res->getMessage());
    $prev_cs_id = 0;
    while ($row = ($phpVersion >= "8.0" ? $res->fetch_assoc() : $res->fetchRow())):
      if ($customer_specific == 0)
        $row["cs_id"] = $cs_id;
      if ($prev_cs_id != $row["cs_id"]):
        $customerservicetypeList[$row["cs_id"]] = array();
        $prev_cs_id = $row["cs_id"];
      endif;
//      $srvt_name = getFieldValueFromId("servicetype", "srvt_id", $row["srvt_id"], "srvt_name");
      array_push ($customerservicetypeList[$row["cs_id"]], array($row["srvt_id"], trim($row["srvt_name"])));
      $csSrvtList .= "[\"" . $row["cs_id"] . "\", \"" . trim($row["srvt_name"]) . "\"],\n";
    endwhile;
    $res->free();
    $csSrvtList = substr($csSrvtList, 0, -2) . "];\n";
    if ($the_hq_id == 0):
      $currentHqId = $hq_id;
      $constHqId = getParameterValue("0", "MANDATOR_SERVICE2_ENABLED", $hq_id);
    else:
      $currentHqId = $the_hq_id;
      $constHqId = getParameterValue("0", "MANDATOR_SERVICE2_ENABLED", $the_hq_id);
    endif;
    if ($constHqId == "" || $constHqId == "0") : $currentHqId = "0"; endif;
    $csPriceList = "cs_price_list=[  ";
    $i = 0;
    $today = getdate();
    $nowtime = $today['year'] . "-" . $today['mon'] . "-" . $today['mday'] . " " .
      $today['hours'] . ":" . $today['minutes'] . ":" . $today['seconds'];
    $csCalcMandList = "cs_calc_mand_list=[  ";

//echo "customerserviceList:\n" . var_export($customerserviceList, true) . "\n";
//echo "customerservicetypeList:\n" .  var_export($customerservicetypeList, true) . "\n";
    foreach($customerserviceList as $key_cs_id => $val_srv_id_arr) {
      foreach($val_srv_id_arr as $val_srv_id) {
//echo "customerservicetypeList[$key_cs_id]:\n" .  var_export($customerservicetypeList[$key_cs_id], true) . "\n";
//        if (isset($customerservicetypeList[$key_cs_id])):
          foreach($customerservicetypeList[$key_cs_id] as $val_srvt_id) {
            $currentHqId = $db->getOne("SELECT hq_id FROM customer WHERE cs_id = " . $key_cs_id);
            if ($customer_specific == 1)
              $tmpPriceArr = getServiceValues($val_srv_id[0], $val_srvt_id[0], $key_cs_id, $currentHqId, $nowtime, 3);
            else
              $tmpPriceArr = getServiceValues($val_srv_id[0], $val_srvt_id[0], 0, $currentHqId, $nowtime, 3);
            $tmpPrice = $tmpPriceArr[0];
            $tmpCrPrice = $tmpPriceArr[1];
            $tmpPrice = sprintf("%01.2f", $tmpPrice);
//            if (!($customer_specific == 0 && $tmpPrice != "0.00"))
              $csPriceList .= "[\"" . $key_cs_id . "\", \"" . $val_srv_id[1] . "\", \"" . $val_srvt_id[1] . "\", \"" . $tmpPrice . "\", \"" . $tmpCrPrice ."\"],\n";
          }
//        endif;
      }
      $csCalcMandList .= "[\"" . $key_cs_id . "\", \"" . getParameterValue("0", "CUSTOMER_MASK_CALCULATOR_USAGE_ONLY_" . $key_cs_id, "0") . "\"],\n";
//$csCalcMandList .= "\n// " . $db->getOne("SELECT par_value FROM parameter WHERE par_key = 'CUSTOMER_MASK_CALCULATOR_USAGE_ONLY_" . $key_cs_id . "'");
    }
    $csPriceList = substr($csPriceList, 0, -2) . "];\n";
    $csCalcMandList = substr($csCalcMandList, 0, -2) . "];\n";
    // Wenn Sondervereinbarungen vorhanden, dann rot anmalen!
    $setCalcButtonClassName =
      "if (typeof(parent.job_options.document.tourOptions.calcButton) != 'undefined')\n" .
      "  parent.job_options.document.tourOptions.calcButton.className = 'commission_no_enabled';\n";
  endif;
  if ($the_hq_id == 0):
//    return ("parent.job_options." . $csSrvList . "parent.job_options." . $csSrvtList . "parent.job_options." . $csPriceList . $setCalcButtonClassName);
    return ("parent.job_options." . $csSrvList . "parent.job_options." . $csSrvtList . "parent.job_options." . $csPriceList . "parent.job_options." . $csCalcMandList . $setCalcButtonClassName . "if (parent.job_options.jb_markup_overwrite == 1) parent.job_options.checkFixprice(0);\n");
  else:
    return ("var " . $csSrvList . "var " . $csSrvtList . "var " . $csPriceList . "var " . $csCalcMandList);
  endif;
}

function setJavascriptOpenerFormVals($frameIdx, $formIdx, $elemList, $opener = "opener.")
{
  $retStr = "";
  foreach($elemList as $key => $val)
    $retStr .=
      "if (typeof($opener" . "parent.$frameIdx.document.$formIdx.$key) != 'undefined')\n" .
      "  " . $opener . "parent.$frameIdx.document.$formIdx.$key.value = \"$val\";\n";
  return $retStr;
}  

function setJavascriptOpenerDisabled($frameIdx, $formIdx, $elemIdx, $falseOrTrue, $opener = "opener.")
{
  return (
    "if (typeof($opener" . "parent.$frameIdx.document.$formIdx.$elemIdx) != 'undefined')\n" .
    "  " . $opener . "parent.$frameIdx.document.$formIdx.$elemIdx.disabled" .
      " = $falseOrTrue;\n"
    );
}  

function setJavascriptOpenerChecked($frameIdx, $formIdx, $elemIdx, $falseOrTrue, $opener = "opener.")
{
  return (
    "if (typeof($opener" . "parent.$frameIdx.document.$formIdx.$elemIdx) != 'undefined')\n" .
    "  " . $opener . "parent.$frameIdx.document.$formIdx.$elemIdx.checked" .
      " = $falseOrTrue;\n"
    );
}  

function setJavascriptOpenerJobList($tourNo, $jobList)
{
  $retStr = "";
  foreach($jobList as $key => $val)
    $retStr .= "opener.setJobList($tourNo, $key, \"$val\");\n";
  return $retStr;
}      

function javascriptOpenerRefreshAndClose($noCurTourNo = 0)
{
/* Nicht Hansetrans
  return(
    "opener.setCurTourNo(curTourNo);\n" .
    "opener.parent.frames[" . JOB_TOUR . "].document.forms[" . TOURFORM .
    "].elements[" . VON_CSC_ID . "].focus();\n" .
    "opener.parent.frames[" . JOB_OPTIONS . "].isCurrentlySubmitting = false;\n" .
    "opener.checkSendTour();\n" .
    "self.close();\n"
    );
*/
  return(
    (($noCurTourNo == 0) ? "opener.setCurTourNo(curTourNo);\n" : "") .
    "opener.parent.job_tour.document.tourForm.vonFirmaButton.focus();\n" .
    "opener.parent.job_options.isCurrentlySubmitting = false;\n" .
    (($noCurTourNo == 0) ? "opener.checkSendTour();\n" : "").
    "self.close();\n"
    );
}

function javascriptAdd_cs_eid($csc_id, $prefix = "")
{
  global $db;

  if ($csc_id == "")
    return "";
  // die cs_eid ist wichtig zur Festellung, ob eine Kostenstelle als Bezahler gewählt werden kann!
  $cs_eid = $db->getOne(
    "SELECT cs.cs_eid from customer AS cs, costcenter AS csc" .
    " WHERE cs.cs_id = csc.cs_id AND csc.csc_id = '$csc_id'");
  $csc_is_extern = $db->getOne("SELECT csc_is_extern from costcenter WHERE csc_id = '$csc_id'");
  // Kommissionsnummer ja/nein wird gleich mitgespeichert!
  if ((trim($cs_eid) != "" && $cs_eid != "0") /* && $csc_is_extern != 1 */):
//die ("löpt");
    if (!(strpos(strtoupper($db->getOne("SELECT csc_path from costcenter WHERE csc_id = $csc_id")), "//EXTERN//") === FALSE))
      $cs_eid = "";
    $cs_id = getFieldValueFromId("costcenter", "csc_id", $csc_id, "cs_id");
    return $prefix . "add_cs_eid($csc_id, '$cs_eid', " .
      my_str_check($db->getOne("SELECT cs_commission_no from customer WHERE cs_id = " . $cs_id)) .
      ", '" . 
      my_str_check($db->getOne(
         "SELECT cmp.cmp_comp FROM company AS cmp, customer AS cs, costcenter AS csc" .
         " WHERE cmp.cmp_id = cs.cmp_id AND cs.cs_id = csc.cs_id AND csc.csc_id = '$csc_id'")) .
      "', " . 
      my_str_check($db->getOne(
        "SELECT cmp.cmp_authenticated FROM company AS cmp, customer AS cs, costcenter AS csc" .
        " WHERE cmp.cmp_id = cs.cmp_id AND cs.cs_id = csc.cs_id AND csc.csc_id = '$csc_id'")) .
      ", '" . 
      my_str_check($db->getOne(
        "SELECT cmp.cmp_remark FROM company AS cmp, customer AS cs, costcenter AS csc" .
        " WHERE cmp.cmp_id = cs.cmp_id AND cs.cs_id = csc.cs_id AND csc.csc_id = '$csc_id'")) .
      "', " . 
      $db->getOne("SELECT cs_jobbatch from customer WHERE cs_id = " . $cs_id) .
      ", " . 
      $db->getOne("SELECT cs_discount from customer WHERE cs_id = " . $cs_id) .
      ", '" . 
      $db->getOne("SELECT cs_filter from customer WHERE cs_id = " . $cs_id) .
      "', " . 
      my_str_check($db->getOne(
        "SELECT cmp.tx_id FROM company AS cmp, customer AS cs, costcenter AS csc" .
        " WHERE cmp.cmp_id = cs.cmp_id AND cs.cs_id = csc.cs_id AND csc.csc_id = '$csc_id'")) .    
      ", '" . 
      my_str_check($db->getOne("SELECT csc_name from costcenter WHERE csc_id = $csc_id")) .
      "', " . 
        $csc_is_extern .
      ", " . 
        $cs_id .
      ", " . 
      $db->getOne("SELECT cs_fixprice_discount from customer WHERE cs_id = " . $cs_id) .
      ", " . 
      $db->getOne("SELECT cs_prov from customer WHERE cs_id = " . $cs_id) .
      ", '" . 
      my_str_check($db->getOne(
        "SELECT cmp.cmp_stax_idno FROM company AS cmp, customer AS cs, costcenter AS csc" .
        " WHERE cmp.cmp_id = cs.cmp_id AND cs.cs_id = csc.cs_id AND csc.csc_id = '$csc_id'")) .
      "', '" . 
      $db->getOne("SELECT par_value FROM parameter WHERE par_key = 'MASK_COMM_PREFIX_" . $cs_id . "'") .
      "', " . 
      $db->getOne("SELECT cs_jb_jam_waittime from customer WHERE cs_id = " . $cs_id) .
      ", " . 
      $db->getOne("SELECT cs_tracking from customer WHERE cs_id = " . $cs_id) .
      ", '" . 
      $db->getOne("SELECT usr_inv_email from customer, employee, user WHERE cs_id = " . $cs_id . " AND customer.cs_admin = employee.emp_id AND employee.usr_id = user.usr_id") .
      "', '" . 
      $db->getOne("SELECT par_value FROM parameter WHERE par_key = 'CUSTOMER_MASK_JB_INCOMPLETE_" . $cs_id . "'") .
      "', " . 
      $db->getOne("SELECT cs_invmode from customer WHERE cs_id = " . $cs_id) .
      ");\n";
  endif;
//die ("löpt nich: $cs_eid, $csc_is_extern");
  return "";
}

function javascriptImpressumWindow()
{
  return "function mkImpressumPopupWin()\n" .
    "{\n" .
    "  var widthPopupWin = 250;\n" .
    "  var heightPopupWin = 310;\n" .
    "  var leftPopupWin = (screen.width / 2) - (widthPopupWin / 2) - 12;\n" .
    "  var topPopupWin = (screen.height / 2) - (heightPopupWin / 2) - 50;\n" .
    "  var popupWin;\n" .
    "\n" .
    "  popupWin=window.open(\"../admin/impressum.html\", \"\",\n" .
    "    \"dependent=yes,width=\" + widthPopupWin + \",height=\" + heightPopupWin +\n" .
    "    \",left=\" + leftPopupWin + \",top=\" + topPopupWin);\n" .
    "}\n";
}

function getValsFromDate($dateVal)
{
// "2003-01-16 18:40:23"
  return(array(
    (is_numeric(substr($dateVal, 0, 4)) ? substr($dateVal, 0, 4) : 0),
    (is_numeric(substr($dateVal, 5, 2)) ? substr($dateVal, 5, 2) : 0),
    (is_numeric(substr($dateVal, 8, 2)) ? substr($dateVal, 8, 2) : 0),
    (is_numeric(substr($dateVal, 11, 2)) ? substr($dateVal, 11, 2) : 0),
    (is_numeric(substr($dateVal, 14, 2)) ? substr($dateVal, 14, 2) : 0),
    (is_numeric(substr($dateVal, 17, 2)) ? substr($dateVal, 17, 2) : 0)
  ));  
}

//function my_datum_zeit_format_timestamp($var_date)
//{
//  return substr($var_date, 6, 2) . "." . substr($var_date, 4, 2) . "." . substr($var_date, 0, 4) .
//    "&nbsp;" . substr($var_date, 8, 2) . ":" . substr($var_date, 10, 2);
//}

function my_datum_zeit_format_datetime($var_date, $nbsp = "&nbsp;")
{
  return substr($var_date, 8, 2) . "." . substr($var_date, 5, 2) . "." . substr($var_date, 0, 4) .
    $nbsp . substr($var_date, 11, 2) . ":" . substr($var_date, 14, 2);
}

function mkLineBreaks($text, $colsMax, $linesMax, $is_http = false)
{
  global $hq_id;

  $text = trim($text);
  $text = str_replace("\r", '', $text);
  // Leerzeilen entfernen
  while (!(strpos($text, "\n\n") === false))
    $text = str_replace("\n\n", "\n", $text);
  $text = str_replace("\n", '; ', $text);
  $formattedLines = "";
  $formattedLine = "";
  $nextWord = "";
  for ($i = 0; $i < $linesMax; $i++):
    $formattedLine = $nextWord . ($nextWord == " " || $formattedLine == "" ? "" : " ");
    for ($j = 0; $j < $colsMax; $j++):
      if (!(strpos($text, " ") === false)):
        if (substr($text, 0, 1) == " "):
          $nextWord = " ";
          $text = substr($text, 1);
        else:
          $nextWord = substr($text, 0, strpos($text, " "));
          $text = substr(stristr($text, " "), 1);
        endif;
      else:
        $nextWord = $text;
        $text = "";
      endif;
      if ($nextWord == "" && $text == "")
        break;
      if (strlen($formattedLine . $nextWord) <= $colsMax):
        $formattedLine .= $nextWord;
        if (strlen($formattedLine . " ") <= $colsMax & $nextWord != " "):
          $formattedLine .= " ";
        endif;
      else:
        break;
      endif;
    endfor;
    while (strlen($formattedLine) < getParameterValue("0", "INV_MAXCOLS_EXPORT", $hq_id)):
      $formattedLine .= " ";
    endwhile;
    $formattedLines .= (($formattedLines != "" && $formattedLine != "") ? "\n" : "") . $formattedLine;
    if ($nextWord == "" && $text == "")
      break;
  endfor;
  if (!($nextWord == "" && $text == ""))
    writeLog_("../log/caglobal_", " Text in `mkLineBreaks` truncated: \$nextWord = '$nextWord', \$text == '$text' (THIS SHOULD NOT BE POSSIBLE!!!)");
  if (!$is_http)
    $formattedLines = str_replace('\'', '\\\'', $formattedLines);
  return $formattedLines;
}

function mkLineBreaksWithBreaks($text, $colsMax, $linesMax, $is_http = false, $do_log = false)
{
  global $hq_id;

  $lines = explode("\n", $text);
  $formattedText = "";  
  foreach ($lines as $line) {
    // Leerzeilen auslassen, wenn Bemerkungstext gedruckt wird (z. Zt. nur in Bremen)
    if (getParameterValue("0", "INV_PRINT_REMARK", $hq_id) == "0" || (getParameterValue("0", "INV_PRINT_REMARK", $hq_id) == "1" && trim($line) != ""))
      $formattedText .= mkLineBreaks($line, $colsMax, $linesMax, $is_http) . "\n";
  }
  $lines = explode("\n", $formattedText);
  $formattedText = "";  
  for ($i = 0; $i < $linesMax; $i++) {
    $formattedText .= (isset($lines[$i]) ? $lines[$i] : "") . "\n";
  }
  if (count($lines) > $linesMax):
//    writeLog_("../log/caglobal_", " Text in `mkLineBreaksWithBreaks` truncated:");
//    for ($i = $linesMax - 1; $i < count($lines); $i++) {
//      writeLog_("../log/caglobal_", "--- " . $lines[$i]);
//    }
    if ($do_log == true)
      writeLog_("../log/caglobal_", "*** In order to preserve information, newlines have been replaced by semicolons!");
    $formattedText = mkLineBreaks($text, $colsMax, $linesMax, $is_http) . "\n";
  endif;
  return $formattedText;
}

function padRight($aString, $len)
{
  while (strlen($aString) < $len)
    $aString .= " ";
  return $aString;
}

function padLeft($aString, $len)
{
  while (strlen($aString) < $len)
    $aString = " " . $aString;
  return $aString;
}

function mk_jb_invtext($jb_id, $do_log = false, $tmp_add_srvs = "", $tmp_add_srvts = "", $tmp_add_mult = "", $tmp_add_mult_price = "", $tmp_add_sids = "", $tmp_add_prices = "")
{
  global $PHP_SELF, $db, $hq_id, $jb_toll, $jb_hiddenFreetext_1, $phpVersion;
//  if ($jb_id = "killMe")
//    return;

  // Einbeziehung der Einträge aus dem Calculator
  $real_jb_freetext_2 = $tmp_add_srvs . "²" . $tmp_add_srvts . "²" . $tmp_add_mult . "²" . $tmp_add_mult_price;
  $tmp_special_jb_invtext = "";
  $tmp_add_srvsArr = explode("¹", $tmp_add_srvs);
  $tmp_add_srvtsArr = explode("¹", $tmp_add_srvts);
  $tmp_add_multArr = explode("¹", $tmp_add_mult);
//print_r($tmp_add_srvsArr); echo "<br>\n";
//print_r($tmp_add_srvtsArr); echo "<br>\n";
//print_r($tmp_add_multArr); echo "<br>\n";
  $maxLenMult = 0;
  for ($i = 0; $i < count($tmp_add_multArr); $i++)
    if (strlen($tmp_add_multArr[$i]) > $maxLenMult)
      $maxLenMult = strlen($tmp_add_multArr[$i]);
  $tmp_add_mult_priceArr = explode("¹", $tmp_add_mult_price);
//print_r($tmp_add_mult_priceArr); echo "<br>\n";
  $maxLenPrice = 0;
  for ($i = 0; $i < count($tmp_add_mult_priceArr); $i++)
    if (strlen($tmp_add_mult_priceArr[$i]) > $maxLenPrice)
      $maxLenPrice = strlen($tmp_add_mult_priceArr[$i]);
  deleteStmt("jobcalculator", "jb_id = '$jb_id'");
  $db->query("DELETE FROM jobprice WHERE jb_id = " . $jb_id . " AND mt_sort = 11 AND jbprc_remark = 'c'");
  for ($i = 0; $i < count($tmp_add_srvsArr); $i++)
    if (trim($tmp_add_mult_priceArr[$i]) != "")
    {
// echo $tmp_add_mult_priceArr[$i] . " / " . str_replace(",", ".", $tmp_add_multArr[$i]) . " = " . ($tmp_add_mult_priceArr[$i] / str_replace(",", ".", $tmp_add_multArr[$i])) . "<br>\n";
      $tmp_special_jb_invtext .=
        padRight($tmp_add_multArr[$i] . "x", $maxLenMult + 2) .
        padRight(
          trim($tmp_add_srvsArr[$i]) . (trim($tmp_add_srvtsArr[$i]) != "" ? " " . $tmp_add_srvtsArr[$i] : "") .
          str_replace(".", ",", " (" . sprintf("%01.2f", ((float) str_replace(",", ".", $tmp_add_mult_priceArr[$i]) / (float) str_replace(",", ".", $tmp_add_multArr[$i]))) . ")")
          , getParameterValue("0", "INV_MAXCOLS", $hq_id) - ($maxLenMult + 2) - ($maxLenPrice + 4) - 2) . ": " .
        padLeft($tmp_add_mult_priceArr[$i], $maxLenPrice) . " EUR\n";
      insertStmt("jobcalculator", 
        array("jb_id", $jb_id, "jbc_amount", $tmp_add_multArr[$i] ,"srv_name", $tmp_add_srvsArr[$i], "srvt_name", trim($tmp_add_srvtsArr[$i]), "jbc_price",
        sprintf("%01.2f", ((float) str_replace(",", ".", $tmp_add_mult_priceArr[$i]) / (float) str_replace(",", ".", $tmp_add_multArr[$i]))), "jbc_totalprice", str_replace(",", ".", $tmp_add_mult_priceArr[$i])));
//print_r (        array("jb_id", $jb_id, "jbc_amount", $tmp_add_multArr[$i] ,"srv_name", $tmp_add_srvsArr[$i], "srvt_name", $tmp_add_srvtsArr[$i], "jbc_price",
//        sprintf("%01.2f", (str_replace(",", ".", $tmp_add_mult_priceArr[$i]) / str_replace(",", ".", $tmp_add_multArr[$i]))), "jbc_totalprice", str_replace(",", ".", $tmp_add_mult_priceArr[$i])));
      if (trim($tmp_add_srvtsArr[$i]) == "Kilometer") {
        $db->query("DELETE FROM jobprice WHERE jb_id = " . $jb_id . " AND mt_sort = 11");
        writeLog_("../log/caglobal_", "[INSERT INTO jobprice (jb_id, mt_sort, jbprc_price, jbprc_remark) VALUES (" . $jb_id . ", 11, " . $tmp_add_multArr[$i] . ", 'c')]");
        $db->query("INSERT INTO jobprice (jb_id, mt_sort, jbprc_price, jbprc_remark) VALUES (" . $jb_id . ", 11, " . $tmp_add_multArr[$i] . ", 'c')");
      }
    }

  // 2018-05-28: STB912838 und STB974019
  // 2025-06-18: PZM ($cs_invmode == 0)
  $cs_id = getFieldValueFromId("costcenter", "csc_id", getFieldValueFromId("job", "jb_id", $jb_id, "csc_id_payer"), "cs_id");
  $cs_invmode = getFieldValueFromId("customer", "cs_id", $cs_id, "cs_invmode");
  if (getParameterValue("0", "MASK_INVOICE_SHOW_SERVICES_" . $cs_id, "0") == "1" || $cs_invmode == 0):
    $dbh_jb = "job";
    $dbh_trs = "tourservice";
    $costArr = getJobCosts(array("jb_id" => $jb_id, "cnt_costsplit" => 1));
    writeLog_("../log/caglobal_", "\$jb_id = " . $jb_id);
    writeLog_("../log/caglobal_", "\$costArr = " . json_encode($costArr));
    $is_minimum = false;
    for ($i = 0; $i < count($costArr) - 1; $i++) {
      if ($cs_invmode == 0) {
        if (!(strpos($costArr[$i][0], "*") === false)) {
          $tmp_cost = explode("*", $costArr[$i][0]);
          $pos = strpos($tmp_cost[0], "km");
          $km = (float) trim(str_replace(",", ".", substr($tmp_cost[0], 0, $pos)));
          $tmp_cost[1] = str_replace("&nbsp;", "", $tmp_cost[1]);
          $pos = strpos($tmp_cost[1], chr(128));
          $eur = (float) trim(str_replace(",", ".", substr($tmp_cost[1], 0, $pos)));
          $costArr[$i][1] = round($km * $eur, 2);
        } else {
          if (!(strpos($costArr[$i][0], "pro") === false)) {
            $tmp_cost = explode("pro", $costArr[$i][0]);
            $pos = strpos($tmp_cost[0], chr(128));
            $eur = (float) trim(str_replace(",", ".", substr($tmp_cost[0], 0, $pos)));
            $tmp_cost[1] = str_replace("&nbsp;", "", $tmp_cost[1]);
            $pos = strpos($tmp_cost[1], "weitere");
            $cnt = (int) trim(str_replace(",", ".", substr($tmp_cost[1], 0, $pos)));
            $costArr[$i][1] = $cnt * $eur;
          } else {
            if (!(strpos($costArr[$i][0], "Aufschlag") === false)) {
              $tmp_cost = explode("&nbsp;", $costArr[$i][0]);
              $pos = strpos($tmp_cost[count($tmp_cost) - 2], chr(128));
              $eur = (float) trim(str_replace(",", ".", substr($tmp_cost[count($tmp_cost) - 2], 0, $pos)));
              $costArr[$i][1] = $eur;
            } else {
              if (substr($costArr[$i][0], 0 , strlen("Fixpreis&nbsp;")) != "Fixpreis&nbsp;" && substr($costArr[$i][0], 0, strlen("Servicepreis&nbsp;")) != "Servicepreis&nbsp;") {
                $pos = strpos($costArr[$i][0], chr(128));
                $eur = (float) trim(str_replace(",", ".", substr($costArr[$i][0], 0, $pos)));
                $costArr[$i][1] = $eur;
              } else {
                if (substr($costArr[$i][0], 0, strlen("Fixpreis&nbsp;[M]")) == "Fixpreis&nbsp;[M]") {
                  $costArr[$i][0] = substr($costArr[$i][0], strlen("Fixpreis&nbsp;[M]" . "&nbsp;"));
                  $costArr[$i][1] = $db->getOne("SELECT jb_fixprice FROM job WHERE jb_id = " . $jb_id);
                  $is_minimum = true;
                }
              }
            }
          }
        }
        $costArr[$i][0] = str_replace("Bus", "Transporter", str_replace("km", " km", str_replace(chr(128), " EUR", str_replace("&nbsp;" . chr(128), " EUR", str_replace("&nbsp;z", "", $costArr[$i][0])))));
      }
      if (!($cs_invmode == 0 && (substr($costArr[$i][0], 0 , strlen("Fixpreis&nbsp;")) == "Fixpreis&nbsp;" || substr($costArr[$i][0], 0, strlen("Servicepreis&nbsp;")) == "Servicepreis&nbsp;"))) {
        if (getParameterValue("0", "MASK_INVOICE_SHOW_SERVICES_" . $cs_id, "0") == "1" || ($cs_invmode == 0 && (!$is_minimum || substr($costArr[$i][0], 0, strlen("Mindestpreis")) == "Mindestpreis"))) {
          $tmp_special_jb_invtext .= trim(str_replace("&nbsp;", " ", $costArr[$i][0])) . ": " .
          padLeft(str_replace(".", ",", sprintf("%01.2f", trim($costArr[$i][1]))) . " EUR", getParameterValue("0", "INV_MAXCOLS", $hq_id) - strlen(trim(str_replace("&nbsp;", " ", $costArr[$i][0])). ": ")) .
          "\n";
        }
      }
    }
    writeLog_("../log/caglobal_", "\$costArr = " . json_encode($costArr));
  endif;

  $tmp_special_sids_jb_invtext = "";
  if (getParameterValue("0", "MASK_INVOICE_SHOW_SIDS", $hq_id) == 1):
//   Einbeziehung der Unternehmerverrechnung aus dem Calculator
//    $tmp_add_jb_idsArr = explode("¹", $tmp_add_jb_ids);
//    $maxcount = count($tmp_add_jb_idsArr);
    $tmp_add_sidsArr = explode("¹", $tmp_add_sids);
//  if (count($tmp_add_sidsArr) > $maxcount)
      $maxcount = count($tmp_add_sidsArr);
//    $tmp_add_pricesArr = explode("¹", $tmp_add_prices);
//    if (count($tmp_add_pricesArr) > $maxcount)
//      $maxcount = count($tmp_add_pricesArr);
    if ($maxcount > 0 && $tmp_add_sidsArr[0] != ""):
      if ($maxcount == 1):  
        $tmp_special_sids_jb_invtext = "Ausführendes Fahrzeug: ";
      else:
        $tmp_special_sids_jb_invtext = "Ausführende Fahrzeuge: ";
      endif;
      $ltrim_mask = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
      $tmp_special_sids_jb_invtext .= substr(ltrim($tmp_add_sidsArr[0], $ltrim_mask), 1);
      for ($i = 1; $i < $maxcount; $i++):
        $tmp_special_sids_jb_invtext .= ", " . substr(ltrim($tmp_add_sidsArr[$i], $ltrim_mask), 1);
      endfor;
      $tmp_special_sids_jb_invtext .= "\n";
    endif;
  endif;
//echo "$tmp_special_sids_jb_invtext<br>";

  $sqlquery = "SELECT DISTINCT job.jb_id, job.jb_freetext_1, job.vht_id, job.emp_id, tour.csc_id, tour.tr_sort, tour.tr_comp, tour.tr_person, tour.tr_remark, " .
      "tour.ad_id, tour.tr_hsno, tour.tr_ware_from_to, tour.tr_commission_no FROM job, tour " .
      "WHERE job.jb_id = tour.jb_id AND job.hq_id = '$hq_id' AND job.jb_id = $jb_id AND ((job.jb_storno != 3 AND job.jb_storno != 4) OR jb_storno IS NULL) " .
      "ORDER BY job.jb_id, tour.tr_sort";      
  $res = $db->query($sqlquery);
  if (DB::isError($res))
    reportDie ("$PHP_SELF: '$sqlquery' : " . $res->getMessage());

  // Bei Listenkunden besteht der Rechnungste nur aus freetext_1 und Kommissionsnummern und Calculatoreinträgen!!!
  // Dies gilt ab 12.12.05 auch für alle Aufträge, die über die Auftragslistenerfassung eingegeben wurden (d.h. auch wenn Kunde eigentlich kein Listenkunde ist)
  // Erweiterung am 24.05.2006: Wenn die Kostenstelle in INV_CSC_ID_NOAUTO als erste Etappenstelle eingestellt
  // Erweiterung am 19.10.2006: Wenn der Kunde in cs_invtext_mode Häkchen hat
  $csc_id_payer = getFieldValueFromId("job", "jb_id", $jb_id, "csc_id_payer");
  $cs_id = getFieldValueFromId("costcenter", "csc_id", $csc_id_payer, "cs_id");  
  // Erweiterung am 26.01.2007: INV_CSC_ID_NOAUTO kann jetzt mehr als nur eine Kostenstelle enthalten
  $inv_csc_id_noauto_arr = explode("|", getParameterValue("0", "INV_CSC_ID_NOAUTO", $hq_id));
  if ($inv_csc_id_noauto_arr === false)
    $inv_csc_id_noauto_arr = array();
  $csc_id_first = $db->getOne("SELECT csc_id from tour WHERE jb_id = $jb_id AND tr_sort = 1");
  $noauto_text = false;
  foreach ($inv_csc_id_noauto_arr as $val)
    if ($csc_id_first == $val)
      $noauto_text = true;
writeLog_("../log/caglobal_", "\$csc_id_payer: $csc_id_payer, \$cs_id: $cs_id, \$jb_id: $jb_id");
writeLog_("../log/caglobal_", " \$db->getOne(\"SELECT cs_jobbatch from customer WHERE cs_id = $cs_id\"): ");
writeLog_("../log/caglobal_", $db->getOne("SELECT cs_jobbatch from customer WHERE cs_id = $cs_id"));
writeLog_("../log/caglobal_", ", \$db->getOne(\"SELECT jb_id from jobbatchlist WHERE jb_id = $jb_id\"): ");
writeLog_("../log/caglobal_", $db->getOne("SELECT jb_id from jobbatchlist WHERE jb_id = $jb_id"));

  if ($db->getOne("SELECT cs_jobbatch from customer WHERE cs_id = $cs_id") == 1 || $db->getOne("SELECT jb_id from jobbatchlist WHERE jb_id = $jb_id") == $jb_id ||
    $noauto_text || $db->getOne("SELECT cs_invtext_mode from customer WHERE cs_id = $cs_id") == 1):
    while ($row = ($phpVersion >= "8.0" ? $res->fetch_assoc() : $res->fetchRow())):
      if ($row["tr_sort"] == 1):  
        $jb_freetext_1 = $row["jb_freetext_1"];
        if (trim($jb_freetext_1) != "" && substr($jb_freetext_1, -1) != "\n")
          $jb_freetext_1 .= "\n";
        $jb_invtext = $jb_freetext_1;
        if (trim($jb_toll) != "")
          $jb_invtext .= "Maut: " . str_replace(".", ",", $jb_toll) . " EUR\n";
      endif;
      if (trim($row["tr_commission_no"]) != "")
        $jb_invtext .= "# " . $row["tr_commission_no"] . "\n";
    endwhile;
    $jb_invtext_cr = $jb_invtext;
    if (trim($jb_hiddenFreetext_1) != "" && substr($jb_hiddenFreetext_1, -1) != "\n")
      $jb_hiddenFreetext_1 .= "\n";
    $jb_invtext .= $jb_hiddenFreetext_1 . trim($tmp_special_jb_invtext);
    $jb_markup = $db->getOne("SELECT jb_markup FROM job WHERE jb_id = '$jb_id'");
    $jb_fixprice = $db->getOne("SELECT jb_fixprice FROM job WHERE jb_id = '$jb_id'");
    $jb_serviceprice = $db->getOne("SELECT jb_serviceprice FROM job WHERE jb_id = '$jb_id'");
    $jb_invtext .= checkDiscountStr($jb_id, $jb_markup, $jb_fixprice, $jb_serviceprice);
    if (getParameterValue("0", "INV_SHOW_MARKUP_BATCH", $hq_id) == "1"):
      if ((getParameterValue("0", "INV_PRINT_SRVPRICE", $hq_id) == "1" || getParameterValue("0", "INV_PRINT_SRVPRICE_" . $cs_id, "0") == "1") && $jb_serviceprice <> 0):
        $euro_sign = "EUR";
        if (getParameterValue("0", "INV_USE_EURO_SIGN", $hq_id) == "1")
          $euro_sign = chr(128);
        $jb_invtext .= "\nServicepreis " . str_replace(".", ",", sprintf("%01.2f", $jb_serviceprice)) . " " . $euro_sign;
      endif;    
//      $jb_invtext .= mkMarkupStr($jb_markup, $jb_id);
    endif;
    $jb_invtext = mkLineBreaksWithBreaks($jb_invtext, getParameterValue("0", "INV_MAXCOLS", $hq_id), getParameterValue("0", "INV_MAXLINES", $hq_id), false, $do_log);
writeLog_("../log/caglobal_", "\$jb_invtext: $jb_invtext, \$jb_id: $jb_id");
    $db->query("UPDATE job SET jb_invtext = '$jb_invtext' WHERE jb_id = '" . $jb_id . "'");
    if (getParameterValue("0", "INV_JB_INVOICE_CR", $hq_id) == "1"):
      $jb_invtext_cr = mkLineBreaksWithBreaks($jb_invtext_cr, getParameterValue("0", "INV_MAXCOLS", $hq_id), getParameterValue("0", "INV_MAXLINES", $hq_id), false, $do_log);
      $db->query("UPDATE job SET jb_invtext_cr = '$jb_invtext_cr' WHERE jb_id = '" . $jb_id . "'");
    endif;
    $db->query("UPDATE job SET jb_freetext_2 = '$real_jb_freetext_2' WHERE jb_id = '" . $jb_id . "'");
  else:
    $i = 0;
    $prev_job_id = 0;
    $prev_tr_remark = "";
    $prev_emp_id = "";
    $prev_vht_id = "";
    $prev_jb_freetext_1 = "";
    $csc_name = "";
    $jb_orderer = $db->getOne("SELECT jb_orderer FROM job WHERE jb_id = " . $jb_id);
    $jb_invtext = "";
    if (trim($jb_orderer) != "")
      $jb_invtext = "Besteller/in: " . $jb_orderer . "\n";
    while ($row = ($phpVersion >= "8.0" ? $res->fetch_assoc() : $res->fetchRow())):
//      $prev_csc_name = $csc_name;
      $prev_emp_id = $row["emp_id"];
      $prev_vht_id = $row["vht_id"];
      $prev_jb_freetext_1 = $row["jb_freetext_1"];
      // current costcenter is payer?
//      if ($row["csc_id"] == $row["csc_id_payer"]):
//        $csc_name = "Ihnen";
//      else:
//        $csc_name = $row["csc_name"];
        $csc_name = $row["tr_comp"];
        if (trim($csc_name) == ".")
          $csc_name = "";
        if (trim($row["tr_person"]) != "" && trim($row["tr_person"]) != ".")
          $csc_name .= ($csc_name != "" ? ", " : "") . $row["tr_person"];
        // Die Adressen der Empfänger werden jetzt auch angezeigt
        list($ad_street, $ad_zipcode, $ad_city) =
          getFieldsValueFromId("address", "ad_id", $row["ad_id"],
            array("ad_street", "ad_zipcode", "ad_city"));
        if (trim($ad_street) == ".")
          $ad_street = "";
        if (trim($ad_zipcode) == ".")
          $ad_zipcode = "";
        if (trim($ad_city) == ".")
          $ad_city = "";
        $tr_hsno = $row["tr_hsno"];
        if (trim($tr_hsno) == ".")
          $tr_hsno = "";
        // Kommissionsnummer
        if (trim($row["tr_commission_no"]) != "")
          $csc_name .= ", (Kom. " . $row["tr_commission_no"] . ")";
//      endif;
      if ($row["tr_sort"] == 1):
        // end of previous job?
        if ($prev_job_id <> 0):
//          echo "<br>$prev_job_id:<br>" . nl2br($jb_invtext) . "\n<br>" . nl2br($prev_tr_remark) . "\n<br>";
//          echo nl2br($jb_invtext) . "\n<br>";
          save_jb_invtext($prev_job_id, $jb_invtext, $prev_emp_id, $prev_vht_id, $prev_tr_remark, $prev_jb_freetext_1, $do_log, $real_jb_freetext_2, $tmp_special_jb_invtext);
        endif;
        $prev_job_id = $row["jb_id"];
        $prev_tr_remark = $row["tr_remark"];
        if (getParameterValue("0", "INV_PRINT_REMARK", $hq_id) == "1"): // z. Zt. nur in Bremen
          $jb_invtext .= $tmp_special_sids_jb_invtext . "Abs.: $csc_name" . ($csc_name != "" ? ", " : "") . "$ad_street $tr_hsno" . ($ad_street . $tr_hsno != "" ? ", " : "") . "$ad_zipcode $ad_city";
        else:
          $jb_invtext .= $tmp_special_sids_jb_invtext . get_tr_ware_from_to_text($row["tr_ware_from_to"], 1)
            . ": $csc_name" . ($csc_name != "" ? ", " : "") . "$ad_street $tr_hsno" . ($ad_street . $tr_hsno != "" ? ", " : "") . "$ad_zipcode $ad_city";
        endif;
      elseif ($row["tr_sort"] == 2):    
        if ((($csc_name != "" || $ad_street != "" || $tr_hsno != "" || $ad_zipcode != "" || $ad_city != "") || getParameterValue("0", "INV_PRINT_REMARK", $hq_id) != "1") && trim($row["tr_comp"]) != ""):
          if (getParameterValue("0", "INV_PRINT_REMARK", $hq_id) == "1"): // z. Zt. nur in Bremen            
            $jb_invtext .= ", Empf.: $csc_name" . ($csc_name != "" ? ", " : "") . "$ad_street $tr_hsno" . ($ad_street . $tr_hsno != "" ? ", " : "") . "$ad_zipcode $ad_city";
          else:
            $jb_invtext .= "\n" . get_tr_ware_from_to_text($row["tr_ware_from_to"], 2)
              . ": $csc_name" . ($csc_name != "" ? ", " : "") . "$ad_street $tr_hsno" . ($ad_street . $tr_hsno != "" ? ", " : "") . "$ad_zipcode $ad_city";
          endif;
        endif;
      else:  
        if ((($csc_name != "" || $ad_street != "" || $tr_hsno != "" || $ad_zipcode != "" || $ad_city != "") || getParameterValue("0", "INV_PRINT_REMARK", $hq_id) != "1") && trim($row["tr_comp"]) != ""):
          if (getParameterValue("0", "INV_PRINT_REMARK", $hq_id) == "1"): // z. Zt. nur in Bremen
            $jb_invtext .= ", Empf.: $csc_name in $ad_zipcode $ad_city";
          else:
            $jb_invtext .= "\n" . get_tr_ware_from_to_text($row["tr_ware_from_to"], 2)
              . ": $csc_name" . ($csc_name != "" ? ", " : "") . "$ad_street $tr_hsno" . ($ad_street . $tr_hsno != "" ? ", " : "") . "$ad_zipcode $ad_city";
          endif;
        endif;
//        $jb_invtext .= ", Abs. $prev_csc_name, Empf. $csc_name";
      endif;
    endwhile;
    if ($prev_job_id <> 0):
//      echo "<br>$prev_job_id:<br>" . nl2br($jb_invtext) . "\n<br>" . nl2br($prev_tr_remark) . "\n<br>";
      save_jb_invtext($prev_job_id, $jb_invtext, $prev_emp_id, $prev_vht_id, $prev_tr_remark, $prev_jb_freetext_1, $do_log, $real_jb_freetext_2, $tmp_special_jb_invtext);
    endif;
  endif;
  $res->free();
}

function mk_jb_invtext_full($jb_id) {
  global $db, $hq_id, $jb_toll, $jb_hiddenFreetext_1, $phpVersion;

  $sqlquery = "SELECT DISTINCT job.jb_id, job.hq_id, job.jb_finishtime, job.jb_freetext_2, job.jb_cr_price FROM job WHERE jb_id = " . $jb_id;
  //writeLog_("../log/check_cr_agio_", "Querying for finished jobs to rebuild `jb_invtext` [$sqlquery]");
  $res = $db->query($sqlquery);
  if (DB::isError($res))
    reportDie ("$PHP_SELF: '$sqlquery' : " . $res->getMessage());
  while ($row = ($phpVersion >= "8.0" ? $res->fetch_assoc() : $res->fetchRow())):
    $hq_id = $row["hq_id"];
  //  writeLog_("../log/check_cr_agio_", "Writing new invoice text in job " . $row["jb_id"] . " (jb_cr_price: '" . $row["jb_cr_price"] . "', jb_finishtime: '". $row["jb_finishtime"] . "', \$jb_finishtime_start: '$jb_finishtime_start', \$jb_finishtime_today = '$jb_finishtime_today', memory_get_usage() = " . memory_get_usage() . ")");
    $jb_cr_price_total = $row["jb_cr_price"];
    $jb_hiddenFreetext_1 = $db->getOne("SELECT gdc_content FROM genericdatacontainer WHERE gdc_obj_type = 'jb' AND gdc_obj_id = " . $row["jb_id"] . " AND gdc_gen_fieldname = 'jb_hiddenFreetext_1'");
    $jb_cr_serviceprice = $db->getOne("SELECT gdc_content FROM genericdatacontainer WHERE gdc_obj_type = 'jb' AND gdc_obj_id = " . $row["jb_id"] . " AND gdc_gen_fieldname = 'jb_cr_serviceprice'");
    // Sondervereinbarungen holen!!!
    $tmp_freetext_2Arr = explode("²", $row["jb_freetext_2"]);
    // Unteraufträge holen!
    list ($tmp_add_jb_ids, $tmp_add_sids, $tmp_add_prices) = getJobChildren($row["jb_id"], "job", "false");
    $jb_toll = $db->getOne("SELECT gdc_content FROM genericdatacontainer WHERE gdc_obj_type = 'jb' AND gdc_obj_id = " . $row["jb_id"] . " AND gdc_gen_fieldname = 'jb_toll'");
    mk_jb_invtext($row["jb_id"], true, $tmp_freetext_2Arr[0], $tmp_freetext_2Arr[1], $tmp_freetext_2Arr[2], $tmp_freetext_2Arr[3], $tmp_add_sids, $tmp_add_prices);
  endwhile;
  $res->free();
}

function get_tr_ware_from_to_text($tr_ware_from_to, $position)
{
  if ($tr_ware_from_to == 1 || ($tr_ware_from_to == 0 && $position == 1))
    return "Abholung";
  if ($tr_ware_from_to == 2 || ($tr_ware_from_to == 0 && $position == 2))
    return "Anlieferung";
  if ($tr_ware_from_to == 3)
    return "Anlieferung und Abholung";
}

function save_jb_invtext($prev_job_id, $jb_invtext, $prev_emp_id, $prev_vht_id, $prev_tr_remark, $prev_jb_freetext_1, $do_log = false, $real_jb_freetext_2 = "", $tmp_special_jb_invtext = "")
{
  global $db, $hq_id, $jb_toll, $jb_hiddenFreetext_1, $jb_cr_price_total, $jb_cr_serviceprice;

  // Bemerkung übernehmen (nur ween getParameterValue("0", "INV_PRINT_REMARK", $hq_id) == 1)
  if (getParameterValue("0", "INV_PRINT_REMARK", $hq_id) == "1"): // z. Zt. nur in Bremen
    if (trim($prev_tr_remark) != "")
      $jb_invtext = $jb_invtext . "\n" . $prev_tr_remark;
  endif;
  // freien Rechnungstext samt Fahrzeugangabe und Mitarbeiter-Kürzel übernehmen
  $ma_name = "";
  if ($prev_emp_id != "" && $prev_emp_id != 0)
    $ma_name = substr(getFieldValueFromId("user", "usr_id", $prev_emp_id, "usr_firstname"), 0, 1)
             . substr(getFieldValueFromId("user", "usr_id", $prev_emp_id, "usr_name"), 0, 1);
  if (trim($prev_jb_freetext_1) != "" && substr($prev_jb_freetext_1, -1) != "\n")
    $prev_jb_freetext_1 .= "\n";
  // "(mit Service)" ausblenden
  
  $metatype_string = "";
  $metatype_string_cont = "";
  if (!($prev_vht_id == 999 && (getParameterValue("0", "INV_PRINT_METATYPE_SERVICE", $hq_id) == "1"))):
    $metatype_string = "(" . $db->getOne("SELECT mt_value FROM metatype WHERE mt_sort = '" . $prev_vht_id . "' AND mt_type = 'vehicletype'") . ")";
    $metatype_string = str_replace("Bus", "Transporter", $metatype_string);
    $metatype_string_cont = ", ";
  endif;
  
  if (trim($jb_hiddenFreetext_1) != "" && substr($jb_hiddenFreetext_1, -1) != "\n")
    $jb_hiddenFreetext_1 .= "\n";
  $jb_freetext_2 = $prev_jb_freetext_1 . $jb_hiddenFreetext_1 .
    $tmp_special_jb_invtext . $metatype_string .
    ($ma_name != "" ? $metatype_string_cont . "MA: " . $ma_name : "");
  $jb_freetext_2_cr = $jb_freetext_2;
  $euro_sign = "EUR";
  if (getParameterValue("0", "INV_USE_EURO_SIGN", $hq_id) == "1")
    $euro_sign = chr(128);
  if (getParameterValue("0", "INV_JB_INVOICE_CR", $hq_id) == "1"):
    $jb_freetext_2_cr = $prev_jb_freetext_1 .
      (getParameterValue("0", "MASK_CR_PRICE_MODE", $hq_id) == "1" && strtotime(getParameterValue("0", "MASK_CR_PRICE_MODE_DATE", $hq_id)) <= strtotime(getFieldValueFromId("job", "jb_id", $prev_job_id, "jb_ordertime"))
      ? // "Frachtvergütung: " . str_replace(".", ",", sprintf("%01.2f", $jb_cr_price_total - $jb_cr_serviceprice)) . " " . $euro_sign . "\n" .
        ($jb_cr_serviceprice > 0 ? "Servicevergütung: " . str_replace(".", ",", sprintf("%01.2f", $jb_cr_serviceprice)) . " " . $euro_sign . "\n" : "")
      : "") .
      $metatype_string .
      ($ma_name != "" && getParameterValue("0", "MASK_CR_PRICE_MODE", $hq_id) != "1" ? $metatype_string_cont . "MA: " . $ma_name : "");
  endif;
  $jb_markup = $db->getOne("SELECT jb_markup FROM job WHERE jb_id = '$prev_job_id'");
  $jb_fixprice = $db->getOne("SELECT jb_fixprice FROM job WHERE jb_id = '$prev_job_id'");
  $jb_serviceprice = $db->getOne("SELECT jb_serviceprice FROM job WHERE jb_id = '$prev_job_id'");
  $jb_freetext_2 .= checkDiscountStr($prev_job_id, $jb_markup, $jb_fixprice, $jb_serviceprice);
  if (getParameterValue("0", "INV_JB_INVOICE_CR", $hq_id) != "1"):
    $jb_freetext_2_cr = $jb_freetext_2;
  endif;
  if ((getParameterValue("0", "INV_PRINT_SRVPRICE", $hq_id) == "1" || getParameterValue("0", "INV_PRINT_SRVPRICE_" . getFieldValueFromId("costcenter", "csc_id", getFieldValueFromId("job", "jb_id", $prev_job_id, "csc_id_payer"), "cs_id"), "0") == "1") && $jb_serviceprice <> 0):
    $jb_freetext_2 .= "\nServicepreis " . str_replace(".", ",", sprintf("%01.2f", $jb_serviceprice)) . " " . $euro_sign;
  endif;  

  $toll_text = "";
  if (trim($jb_toll) != "")
    $toll_text = "\nMaut: " . str_replace(".", ",", $jb_toll) . " EUR";

//  if (getParameterValue("0", "MASK_MARKUP_MODE", $hq_id) == "1" || getParameterValue("0", "MASK_ADD_TO_REMARK", $hq_id) == "1"):
//    $markup_text = "";
//    if ($jb_markup <> 0):
//      $markup_text = mkMarkupStr($jb_markup, $prev_job_id);
//    endif;
//    if (getParameterValue("0", "MASK_ADD_TO_REMARK", $hq_id) == "1"): // 23.02.2026: MASK_ADD_TO_REMARK gibt es nicht mehr! Code wird also niemals ausgeführt
//      // Name und Telefonnummer des Erfassers für Bemerkung
//      $usr_name_remark = getFieldValueFromId("user", "usr_id", $prev_emp_id, "usr_firstname") . " " .
//        getFieldValueFromId("user", "usr_id", $prev_emp_id, "usr_name") . " (" .
//        getFieldValueFromId("user", "usr_id", $prev_emp_id, "usr_phone") . ")";
//      $tr_remark = $db->getOne("SELECT tr_remark from tour WHERE jb_id = '$prev_job_id' AND tr_sort = 1");
//      // Wenn Name und Telefonnummer des Erfassers noch nicht oder
//      // nicht mehr vorhanden, dann hier ergänzen
//      // Aber erst einmal entfernen, falls vorhanden
//      $tr_remark = str_replace("|$usr_name_remark|", "", $tr_remark);
//      // Ebenso 
//      if (!(strpos($tr_remark, "|Treibstoffzuschlag") === false)):
//        $tr_remark = substr($tr_remark, strpos($tr_remark, "|") + 1);
//        $tr_remark = substr($tr_remark, strpos($tr_remark, "|") + 2);
//      endif;
//      $tr_remark = trim($tr_remark);
//      // jetzt ist die Bemerkung wieder clean und die Angaben können ergänzt werden
//      $tr_remark = "|" . $usr_name_remark  . "|\n|" . substr($markup_text, 1) . "|\n" . $tr_remark;
//      updateStmt("tour", "jb_id", $prev_job_id, array("tr_remark", $tr_remark) ,"tr_sort = 1");
//    endif;
//    if (getParameterValue("0", "MASK_MARKUP_MODE", $hq_id) == "1"):
//      $jb_freetext_2 .= $markup_text;
//      if (getParameterValue("0", "INV_JB_INVOICE_CR", $hq_id) != "1"):
//        $jb_freetext_2_cr = $jb_freetext_2;
//      endif;
//    endif;
//  endif;

//echo nl2br($jb_freetext_2) . "\n<br>\n<br>";
  $jb_invtext_cr = $jb_invtext . "\n" . $jb_freetext_2_cr;
  $jb_invtext = $jb_invtext . "\n" . $jb_freetext_2 . (isset($cost_text) ? $cost_text : "") . $toll_text;
  $co2e = $db->getOne("SELECT jbprc_price FROM jobprice WHERE jb_id = " . $prev_job_id . " AND mt_sort = 12");
  if ($co2e != "" && $co2e > 0)
    $jb_invtext .= "\nDie CO2E-Emission nach Well-to-Wheel-Methode für diesen Transport beträgt " . str_replace(".", ",", sprintf("%01.2f", $co2e)) . " kg";
    // Prüfen, ob Kommissionsnummer für Rechnung übernommen werden muss
//echo "*** vorher: ****<br>" . nl2br($jb_invtext) . "\n<br>\n<br>";
  $jb_invtext = mkLineBreaksWithBreaks($jb_invtext, getParameterValue("0", "INV_MAXCOLS", $hq_id), getParameterValue("0", "INV_MAXLINES", $hq_id), false, $do_log);
  $jb_invtext_cr = mkLineBreaksWithBreaks($jb_invtext_cr, getParameterValue("0", "INV_MAXCOLS", $hq_id), getParameterValue("0", "INV_MAXLINES", $hq_id), false, $do_log);
//echo "*** nachher: ****<br>" . nl2br($jb_invtext) . "\n<br>\n<br>";
  $db->query("UPDATE job SET jb_invtext = '$jb_invtext' WHERE jb_id = '" . $prev_job_id . "'");
  if (getParameterValue("0", "INV_JB_INVOICE_CR", $hq_id) == "1"):
    $db->query("UPDATE job SET jb_invtext_cr = '$jb_invtext_cr' WHERE jb_id = '" . $prev_job_id . "'");
  endif;
  $db->query("UPDATE job SET jb_freetext_2 = '$real_jb_freetext_2' WHERE jb_id = '" . $prev_job_id . "'");
}

function checkDiscountStr($jb_id, $jb_markup, $jb_fixprice, $jb_serviceprice)
{
  global $db, $hq_id, $phpVersion;

  $euro_sign = "EUR";
// https://www.gerd-riesselmann.net/webentwicklung/utf-8-latin1-aka-iso-8859-1-und-das-euro-zeichen/
  if (getParameterValue("0", "INV_USE_EURO_SIGN", $hq_id) == "1")
    $euro_sign = chr(128);
  $discount_text = "";
//  $full_price = 0;
  $full_price_without_service = 0;
  $full_price_without_markup_and_service = 0;
  $full_price_without_service_with_self_service_discount = 0;
  $discount_price = 0;
  $the_discount = 0;
  $serviceprice_discount = 0;

  $self_service_discount = $db->getOne("SELECT jbprc_price FROM jobprice WHERE jb_id = " . $jb_id . " AND mt_sort = 13");
  $self_service_discount = (float) $self_service_discount;
  $sqlquery = "SELECT trs_discount, trs_price, trs_srv_name FROM tourservice WHERE jb_id = '$jb_id'";
  $res = $db->query($sqlquery);
  if (DB::isError($res)) reportDie ("$PHP_SELF: '$sqlquery': " . $res->getMessage());
  while ($row = ($phpVersion >= "8.0" ? $res->fetch_assoc() : $res->fetchRow())):
    if ($row["trs_discount"] != 0):
      if ($discount_text == "" && getParameterValue("0", "INV_PRINT_DISCOUNT", $hq_id) == "1"):
        $discount_text = "\nRabatt " . str_replace(".", ",", sprintf("%01.2f", $row["trs_discount"])) . "%";
        $the_discount = $row["trs_discount"];
      endif;
      $the_markup = $jb_markup;
      if ($row["trs_srv_name"] == 'Servicepreis'):
        $the_markup = 0;
        $serviceprice_discount = 1;
      endif;
      $discount_price += round($row['trs_price'] * ((100 + $row["trs_discount"]) / 100), 2);
    endif;
    if ($row["trs_srv_name"] != 'Servicepreis') {
      $full_price_without_markup_and_service += round(round($row['trs_price'] / ((100 - $self_service_discount) / 100), 2) / (1 + ($jb_markup / 100)), 2);
      $full_price_without_service += round($row['trs_price'] / ((100 - $self_service_discount) / 100), 2);
      $full_price_without_service_with_self_service_discount += $row['trs_price'];
    }
//    $full_price += $row['trs_price'];
  endwhile;
  $res->free();

  if ($self_service_discount > 0) {
    $full_price_without_service = $db->getOne("SELECT jbprc_remark FROM jobprice WHERE jb_id = " . $jb_id . " AND mt_sort = 13");
    $full_price_without_markup_and_service = round($full_price_without_service / (1 + ($jb_markup / 100)), 2);
    $discount_text = "\nSelbsterfasserrabatt " . str_replace(".", ",", sprintf("%01.2f", $self_service_discount)) . "% auf " . str_replace(".", ",", sprintf("%01.2f", $full_price_without_service)) . " " . $euro_sign . " = " . str_replace(".", ",", sprintf("%01.2f", $full_price_without_service_with_self_service_discount - $full_price_without_service, 2)) . " " . $euro_sign .
    $discount_text;
  }
//echo $self_service_discount . "<br>\n";
//echo $jb_markup . "<br>\n";
//echo $full_price_without_markup_and_service . "<br>\n";
//echo $full_price_without_service . "<br>\n";
//echo $full_price_without_service_with_self_service_discount . "<br>\n";
//die();

  if ($the_discount != 0 && getParameterValue("0", "INV_PRINT_DISCOUNT", $hq_id) == "1") {
    $discount_text .= " auf " . str_replace(".", ",", sprintf("%01.2f", $full_price_without_service_with_self_service_discount)) . " " . $euro_sign . " = " . str_replace(".", ",", sprintf("%01.2f", $full_price_without_service_with_self_service_discount - $discount_price)) . " " . $euro_sign;
  }

  if ($jb_markup <> 0 && getParameterValue("0", "MASK_MARKUP_MODE", $hq_id) == "1"):
//    $markup_price = $db->getOne("SELECT jb_subtotalprice - jb_serviceprice FROM job WHERE jb_id = " . $jb_id);
//    $totalprice = $db->getOne("SELECT jb_totalprice - jb_serviceprice FROM job WHERE jb_id = " . $jb_id);
    $discount_text = "\nTreibstoffzuschlag " . str_replace(".", ",", sprintf("%01.2f", $jb_markup)) . "%" .
      " auf " . str_replace(".", ",", sprintf("%01.2f", $full_price_without_markup_and_service)) . " " . $euro_sign . " = " . str_replace(".", ",", sprintf("%01.2f", $full_price_without_service - $full_price_without_markup_and_service)) . " " . $euro_sign . 
      $discount_text;
  endif;

//    if ($discount_text != ""):
//      // wenn Festpreis vorhanden, dann wg. Rundungs-Dramen lieber den nehmen, anstatt zurückzurechnen;
//      // nur im Fall der PLZ-, Bereichspreise etc. wird zurückgerechnet
//      if ($jb_fixprice <> 0):
//        $full_price = $jb_fixprice + ($serviceprice_discount * $jb_serviceprice);
////        $discount_price = $full_price * (1 - ($the_discount / 100));
//      endif;
//      return ($discount_text . " auf " . str_replace(".", ",", sprintf("%01.2f", $full_price)) . " " . $euro_sign . " = " . str_replace(".", ",", sprintf("%01.2f", $full_price - round($full_price * (1 - $the_discount / 100), 2))) . " " . $euro_sign . $self_service_discount_text);
//    endif;
//    return $self_service_discount_text;
//  return "";
  return $discount_text;
}

//function mkMarkupStr($jb_markup, $jb_id)
//{
//  global $db;
//
//  $markup_text = ""; 
//  if ($jb_markup <> 0):
//    $markup_price = $db->getOne("SELECT jb_subtotalprice - jb_serviceprice FROM job WHERE jb_id = " . $jb_id);
//    $totalprice = $db->getOne("SELECT jb_totalprice - jb_serviceprice FROM job WHERE jb_id = " . $jb_id);
//    $markup_text = "\nTreibstoffzuschlag " . str_replace(".", ",", sprintf("%01.2f", $jb_markup)) . "%" .
//      " auf " . str_replace(".", ",", sprintf("%01.2f", $markup_price)) . " EUR = " . str_replace(".", ",", sprintf("%01.2f", $totalprice - $markup_price)) . " EUR";
//  endif;
//  return $markup_text;
//}

// this function is needed for import only
// Sericeprice and full Addresses (Berlin) are not considered
function mk_jb_price_old($jb_id)
{
  global $db, $phpVersion;

  $fullPrice = 0;
  $jb_subtotal = 0;
  $sqlquery = "SELECT hq_id, vht_id, jb_ordertime, csc_id_payer, csc_id_payer_cash FROM job WHERE jb_id = $jb_id";
  $res = $db->query($sqlquery);
  if (DB::isError($res)) reportDie ("$PHP_SELF: '$sqlquery': " . $res->getMessage());
  $row = ($phpVersion >= "8.0" ? $res->fetch_assoc() : $res->fetchRow());
  $res->free();
  $csc_id_payer = $row['csc_id_payer'];
  $jb_cash = false;
  if ($csc_id_payer == CSC_ID_PAYER_CASH):
    $csc_id_payer = $csc_id_payer_cash;
    $jb_cash = true;
  endif;
  $cs_id = getFieldValueFromId("costcenter", "csc_id", "$csc_id_payer", "cs_id");
  $srvt_name = $db->getOne("SELECT mt_value FROM metatype WHERE mt_sort = '" . $row["vht_id"] . "' AND mt_type = 'vehicletype'");
  $jb_markup = getFuelMarkup($srvt_name, $cs_id, $row['hq_id'], $row['jb_ordertime']);
  list ($fp, $fd, $fpm, $customer_specific, $special_address) =
    saveServiceCosts("Grundpreis", $srvt_name, $row['hq_id'], $cs_id, $jb_id, 0, $jb_ordertime, 0, 1, 0, $jb_cash, $csc_id_payer, 0, false, false, false, $jb_markup, $row["vht_id"]);
  $fullPrice += round($fp * ((100-$fd)/100), 2);
  $jb_subtotal += round($fpm * ((100-$fd)/100), 2);

  $ad_id1 = "";
  $ad_id2 = "";
  $jb_tourdata1 = "";
  $jb_tourdata2 = "";
  $jb_tourdata3 = "";
  $sqlquery = "SELECT address.ad_id, ad_zipcode, ad_city, tr_sort FROM address, tour WHERE jb_id = $jb_id AND address.ad_id = tour.ad_id";
  $res1 = $db->query($sqlquery);
  if (DB::isError($res1)) reportDie ("$PHP_SELF: '$sqlquery': " . $res1->getMessage());
  while ($row1 = ($phpVersion >= "8.0" ? $res1->fetch_assoc() : $res1->fetchRow())):
    $ad_id1 = $ad_id2;
    $ad_id2 = $row1['ad_id'];
    if ($row1['tr_sort'] > 1):
      list ($fp, $fd, $fpm, $customer_specific, $special_address) =
        saveServiceCosts($ad_id1, $ad_id2, $row['hq_id'], $cs_id, $jb_id, $row['tr_sort'], $jb_ordertime, 0, 1, 0, $jb_cash, $csc_id_payer, 0, false, false, false, $jb_markup, $row["vht_id"]);
      $fullPrice += round($fp * ((100-$fd)/100), 2);
      $jb_subtotal += round($fpm * ((100-$fd)/100), 2);
    endif;
    $jb_tourdata1 .= ($jb_tourdata1 == "" ? "" : ";") . $row1['ad_zipcode'];
    $jb_tourdata2 .= ($jb_tourdata2 == "" ? "" : ";") . $row1['ad_city'];
//    $jb_tourdata3 .= ($jb_tourdata3 == "" ? "" : ";") . (trim($jobList[$i][JL_AD_COUNTRY]) == "" ? "DE" : $jobList[$i][JL_AD_COUNTRY]);    
  endwhile;
  $res1->free();

  updateStmt("job", "jb_id", $jb_id, array(
    "jb_totalprice", $fullPrice, "jb_subtotalprice", $jb_subtotal, "jb_markup", $jb_markup, "jb_tourdata", $jb_tourdata1 . "|" . $jb_tourdata2 . "|" . $jb_tourdata3));
}

if (!defined("MASK_CR_PRICE_MODE")) {
  define("MASK_CR_PRICE_MODE",    "1");
}
define("JB_CR_MARKUP",          "1");
define("JB_CR_FIXPRICE",        "2");
define("JB_CR_FIXSERVICEPRICE", "3");
define("JB_CR_SERVICEPRICE",    "4");
define("JB_CR_PROV",            "5");
define("JB_CR_SERVICE_PROV",    "6");
define("JB_CR_AGIO",            "7");
define("JB_MARKUP_MAN",         "8");
define("JB_CR_MARKUP_MAN",      "9");
define("JB_CR_SUBTOTAL",        "10");

// $mode = 0 -> normaler Modus (Schnittstellenaufträge), sonst Neuberechnung von nach dem alten Schema gespeicherten Aufträgen
function mk_jb_price($jb_id, $mode = 0) {
  global $db, $hq_id, $phpVersion; // getServiceVehicleTypeMappingId() needs global hq_id

  $csc_id_payer_cashArr = array();
  $sqlquery = "SELECT hq_id, par_value FROM parameter WHERE par_key = 'CSC_ID_PAYER_CASH' ORDER BY hq_id";
  $res = $db->query($sqlquery);
  if (DB::isError($res)) reportDie ("$PHP_SELF: '$sqlquery': " . $res->getMessage());
  while ($row = ($phpVersion >= "8.0" ? $res->fetch_assoc() : $res->fetchRow())):
    $csc_id_payer_cashArr[] = $row['par_value'];
  endwhile;
  $res->free();

  writeLog_("../log/caglobal_", "mk_jb_price: \$jb_id = " . $jb_id . ", \$mode = " . $mode);
  $fullPrice = 0.00;
  $jb_subtotal = 0.00;
  $jb_totalprice = 0.00;
//  $fullCrPrice = 0.00;
  $jb_cr_subtotal = 0.00;
  $getPriceOnly = 1;
  $jb_cr_price = 0.00;
  $tmp_discount_rate = 0.00;
//  $grundpreis = 0.00;
//  $cr_grundpreis = 0.00;

  $jb_cr_markup = 0.00;
  $jb_cr_fixprice = 0.00;
  $jb_cr_fixserviceprice = 0.00;
  $jb_cr_serviceprice = 0.00;
  $jb_cr_price_rate = 0.00;
  $jb_cr_serviceprice_rate = 0.00;
  $jb_cr_agio = 0.00;

  $sqlquery = "SELECT hq_id, vht_id, jb_ordertime, csc_id_payer, csc_id_payer_cash, jb_markup, jb_cr_price, jb_fixprice, jb_cr_subprice, jb_serviceprice, cr_id, jb_createtime, jb_subtotalprice, jb_totalprice FROM job WHERE jb_id = " . $jb_id;
  $res = $db->query($sqlquery);
  if (DB::isError($res1)) reportDie ("$PHP_SELF: '$sqlquery': " . $res1->getMessage());
  if (!($row = ($phpVersion >= "8.0" ? $res->fetch_assoc() : $res->fetchRow())))
    return;
  $res->free;
  // getServiceVehicleTypeMappingId() needs global hq_id
  $hq_id = $row["hq_id"];
//  $_CSC_ID_PAYER_CASH_ = getParameterValue("0", "CSC_ID_PAYER_CASH", $row['hq_id']);
//echo $row['hq_id'] . ", " . $_CSC_ID_PAYER_CASH_ . "\n";
//  $_MASK_CASH_PAYER_SELECT_ = getParameterValue("0", "MASK_CASH_PAYER_SELECT", $row['hq_id']);
  $csc_id_payer = $row['csc_id_payer'];
  $jb_cash = false;
//  if ($csc_id_payer == $_CSC_ID_PAYER_CASH_):
  if (in_array($csc_id_payer, $csc_id_payer_cashArr)):
    if ($row["csc_id_payer_cash"] != 0)
      $csc_id_payer = $row["csc_id_payer_cash"];
    $jb_cash = true;
//  else:
//    return;
  endif;
  $cs_id = getFieldValueFromId("costcenter", "csc_id", $csc_id_payer, "cs_id");
  // Listenkunden werden nicht bearbeitet
  if ($db->getOne("SELECT cs_jobbatch from customer WHERE cs_id = " . $cs_id) == 1) {
//    myWriteLog("*** Listenkundenauftrag wurde ignoriert *** " . "\$jb_id = " . $jb_id . ", \$row[\"hq_id\"] = " . $row["hq_id"] . ", \$row[\"jb_ordertime\"] = " . $row["jb_ordertime"]);
    return;
  }
  $srvt_name = $db->getOne("SELECT mt_value FROM metatype WHERE mt_sort = '" . $row['vht_id'] . "' AND mt_type = 'vehicletype'");
  if (MASK_CR_PRICE_MODE == "1") {
    // TSZ für Frachtvergütung über Schnittstelle ist immer der Default (über die Schnittstelle ist jb_cr_markup in jobprice nicht definiert), ansonsten kann er in der jobprice hinterlegt sein
    $jb_cr_markup = $db->getOne("SELECT jbprc_price FROM jobprice WHERE jb_id = " . $jb_id . " AND mt_sort IN (" . JB_CR_MARKUP . ", " . JB_CR_MARKUP_MAN . ")");
    if ($jb_cr_markup == "") { // kein Eintrag für $jb_cr_markup = nehme Default
      $jb_cr_markup = getFuelMarkupCr($srvt_name, $cs_id, $row['hq_id'], $row['jb_ordertime']);
    }
    if ($mode == 0) {
	  // TSZ für Auftragspreis ist Default, manueller Kurier-TSZ, manuelle Frachtvergütung und manuelle Servicevergütung sind über Schnittstelle nicht vorgesehen
      $jb_markup = getFuelMarkup($srvt_name, $cs_id, $row['hq_id'], $row['jb_ordertime']);
      // $jb_cr_fixprice
      // Für den Fall, dass folgende Werte zukünftig über die Schnittstelle kommen
//      $jb_cr_markup = $db->getOne("SELECT jbprc_price FROM jobprice WHERE mt_sort IN (1,9)");
//      $jb_cr_fixprice = $db->getOne("SELECT jbprc_price FROM jobprice WHERE mt_sort = 2");
//      $jb_cr_fixserviceprice = $db->getOne("SELECT jbprc_price FROM jobprice WHERE mt_sort = 3");
    } else {
	  // TSZ für Auftragspreis, Manuelle Frachtvergütung und manuelle Servicevergütung sind im Auftrag hinterlegt
      $jb_markup = $row['jb_markup'];
      $jb_cr_fixprice = $row['jb_cr_subprice'];
      $jb_cr_fixserviceprice = $db->getOne("SELECT gdc_content FROM genericdatacontainer WHERE gdc_obj_type = 'jb' AND gdc_obj_id = " . $jb_id . " AND gdc_gen_fieldname = 'jb_cr_serviceprice'");
    }
  }
  $real_jb_cr_price = $row["jb_cr_price"];
//echo $srvt_name. ", " .$row['hq_id']. ", " .$cs_id. ", " .$jb_id. ", " ."0". ", " .$row['jb_ordertime']. ", " ."0". ", " ."1". ", " .$getPriceOnly. ", " .$jb_cash. ", " .$csc_id_payer. ", " ."0". ", " ."false". ", " ."false". ", " ."false". ", " . $jb_markup. ", " .$row['vht_id'] . "\n";
  list ($fp, $fd, $fpm, $final_cr_price, $final_cr_discount, $final_cr_price_markup, $customer_specific, $special_address, $validfrom) =
    saveServiceCosts("Grundpreis", $srvt_name, $row['hq_id'], $cs_id, $jb_id, 0, $row['jb_ordertime'], 0, 1, $getPriceOnly, $jb_cash, $csc_id_payer, 0, false, false, false, $jb_markup, $jb_cr_markup, $row['vht_id']);
//echo "$fp, $fd, $fpm, $final_cr_price, $final_cr_discount, $final_cr_price_markup, $customer_specific, $special_address, $validfrom\n";
  $fullPrice += round($fp * ((100-$fd)/100), 2);
  $jb_subtotal += round($fpm * ((100-$fd)/100), 2);
  $jb_cr_subtotal += round($final_cr_price_markup * ((100-$fd)/100), 2);
  $fullCrPrice += round($final_cr_price * ((100-$fd)/100), 2);

  $ad_id1 = "";
  $ad_id2 = "";
  $zipcode1 = false;
  $zipcode2 = false;
  $jb_tourdata1 = "";
  $jb_tourdata2 = "";
  $jb_tourdata3 = "";
  $sqlquery = "SELECT address.ad_id, ad_country, ad_zipcode, ad_city, tr_sort, tr_hsno, tr_mediationarea_id FROM address, tour WHERE jb_id = " . $jb_id . " AND address.ad_id = tour.ad_id";
  $res1 = $db->query($sqlquery);
  if (DB::isError($res1)) reportDie ("$PHP_SELF: '$sqlquery': " . $res1->getMessage());
  while ($row1 = ($phpVersion >= "8.0" ? $res1->fetch_assoc() : $res1->fetchRow())):
    $ad_id1 = $ad_id2;
    $zipcode1 = $zipcode2;
    $ad_id2 = $row1['ad_id'] . "³" . $row1["tr_hsno"];
    $zipcode2 = false;
    if ($row1["tr_mediationarea_id"] != 0):
      $ad_id2 = $row1["tr_mediationarea_id"];
      $zipcode2 = true;
    endif;        
    if ($row1['tr_sort'] > 1):
//echo $jb_id . ", " . $ad_id1 . ", " . $ad_id2 . ", " . $srvt_name. ", " .$row['hq_id']. ", " .$cs_id. ", " .$jb_id. ", " ."0". ", " .$row['jb_ordertime']. ", " ."0". ", " ."1". ", " .$getPriceOnly. ", " .$jb_cash. ", " .$csc_id_payer. ", " ."0". ", " ."false". ", " ."false". ", " ."false". ", " . $jb_markup. ", " .$row['vht_id'] . "\n";
//myWriteLog("$ad_id1, $ad_id2, " . $row['hq_id'] . ", $cs_id, $jb_id, " . $row1['tr_sort'] . ", " . $row['jb_ordertime'] . ", 0, 1, $getPriceOnly, $jb_cash, $csc_id_payer, 0, $zipcode1, $zipcode2, false, $jb_markup, " . $row['vht_id']);
      list ($fp, $fd, $fpm, $final_cr_price, $final_cr_discount, $final_cr_price_markup, $customer_specific, $special_address, $validfrom) =
        saveServiceCosts($ad_id1, $ad_id2, $row['hq_id'], $cs_id, $jb_id, $row1['tr_sort'], $row['jb_ordertime'], 0, 1, $getPriceOnly, $jb_cash, $csc_id_payer, 0, $zipcode1, $zipcode2, false, $jb_markup, $jb_cr_markup, $row['vht_id']);
//myWriteLog("$fp, $fd, $fpm, $final_cr_price, $final_cr_discount, $final_cr_price_markup, $customer_specific, $special_address, $validfrom");
      $fullPrice += round($fp * ((100-$fd)/100), 2);
      $jb_subtotal += round($fpm * ((100-$fd)/100), 2);
//myWriteLog("\$fullPrice = " . $fullPrice);
      $jb_cr_subtotal += round($final_cr_price_markup * ((100-$fd)/100), 2);
      $fullCrPrice += round($final_cr_price * ((100-$fd)/100), 2);
//      $jb_cr_price_rate = round((1 - ($final_cr_price / $fp)) * 100, 2);
//myWriteLog("\$jb_cr_price_rate = " . $jb_cr_price_rate . ", \$final_cr_price = " . $final_cr_price . ", \$fp = " . $fp);
//      if (round($jb_cr_price_rate) - round($jb_cr_price_rate, 2) < 0.07)
//        $jb_cr_price_rate = round($jb_cr_price_rate);
//myWriteLog("\$jb_cr_price_rate = " . $jb_cr_price_rate);
//myWriteLog("Station " . $row1['tr_sort'] . ": " . round($fp * ((100-$fd)/100), 2) . " (ohne TSZ: " . round($fpm * ((100-$fd)/100), 2) . "), " . $fd);
//myWriteLog("Station " . $row1['tr_sort'] . " Cr: " . round($final_cr_price * ((100-$fd)/100), 2) . " (ohne TSZ: " . round($final_cr_price_markup * ((100-$fd)/100), 2) . "), " . $fd);
    endif;
    $jb_tourdata1 .= ($jb_tourdata1 == "" ? "" : ";") . $row1['ad_zipcode'];
    $jb_tourdata2 .= ($jb_tourdata2 == "" ? "" : ";") . $row1['ad_city'];
    $jb_tourdata3 .= ($jb_tourdata3 == "" ? "" : ";") . $row1['ad_country'];
  endwhile;
  $res1->free();

  $jb_cr_price = $jb_cr_fixprice;
//echo $jb_cr_price . "\n";
  if ($row['jb_fixprice'] == 0):
    $jb_totalprice = $fullPrice;
    if ($jb_cr_price == 0 && MASK_CR_PRICE_MODE == "1"):
      $jb_cr_price = $jb_cr_subtotal;
      $jb_cr_price_total = $fullCrPrice;
      $jb_cr_price_rate = get_cr_price_rate($row['hq_id'], $cs_id, $row['jb_ordertime'], $vhtSrvt_name, $row['vht_id']);
    endif;
  else:
    // Festpreis-Discount wird bei Schnittstellenaufträgen nicht berücksichtigt
    if ($mode != 0)
      $tmp_discount_rate = $db->getOne("SELECT trs_discount FROM tourservice WHERE jb_id = " . $jb_id . " AND trs_srv_name = 'Fixpreis'");
    $jb_subtotal = round($row['jb_fixprice'] * (1 - ($tmp_discount_rate / 100)), 2);
    $jb_totalprice = round($jb_subtotal * (1 + ($jb_markup / 100)), 2);
    if (MASK_CR_PRICE_MODE == "1") {
      if ($jb_cr_price == 0) {
        if ($real_jb_cr_price == $row["jb_totalprice"]) { // Stuttgart hatte anfangs keinen Kurierabschlag definiert
          $jb_cr_price_rate = 0;
          $jb_cr_price = $jb_subtotal;
		} else {
          list($jb_cr_price, $jb_cr_price_rate) =
            getCr_price_global($jb_subtotal, $row['hq_id'], $cs_id, $row['jb_ordertime'], $vhtSrvt_name, $row['vht_id']);
        }
//echo $jb_subtotal . ", " . $jb_cr_price . ", " . $jb_cr_price_rate . "\n";
      }
      $jb_cr_price_total = round($jb_cr_price * (1 + ($jb_cr_markup / 100)), 2);
    }
  endif;
  $jb_subtotalprice += $row['jb_serviceprice'];
  $jb_totalprice += $row['jb_serviceprice'];

  if (MASK_CR_PRICE_MODE == "1") {
    if ($jb_cr_fixserviceprice == 0 && $row["jb_serviceprice"] > 0)
      list($jb_cr_serviceprice, $jb_cr_serviceprice_rate) =
        getCr_price_global($row["jb_serviceprice"], $row['hq_id'], $cs_id, $row['jb_ordertime'], $vhtSrvt_name, $row['vht_id']);
  }
  if (MASK_CR_PRICE_MODE == "1" && strtotime(MASK_CR_PRICE_MODE_DATE) <= strtotime($row['jb_ordertime'])) {
    if ($cs_id != "" && $cs_id != 0) {
      if ($row['cr_id'] != "" && $row['cr_id'] != 0) {
        $jb_cr_agio = $db->getOne("SELECT cscr_prov FROM customercourier WHERE cs_id = " . $cs_id . " AND cr_id = " . $row['cr_id']);
        if ($jb_cr_agio == "")
          $jb_cr_agio = 0;
      }
    } else {
      myWriteLog("");
      writeLog_("../log/caglobal_", "mk_jb_price: *** ERROR: \$cs_id not defined ***");
    }
    $jb_cr_price += ($jb_cr_serviceprice + $jb_cr_fixserviceprice);
    $jb_cr_price_total = round($jb_cr_price_total * (1 + ($jb_cr_agio / 100)), 2) + $jb_cr_serviceprice + $jb_cr_fixserviceprice;
  }
  if ($mode == 0) {
    writeLog_("../log/caglobal_", "mk_jb_price: " . 
      json_encode(array(
        "jb_totalprice", $jb_totalprice, "jb_subtotalprice", $jb_subtotal, "jb_cr_price", $jb_cr_price_total, "jb_markup", $jb_markup, "jb_tourdata", $jb_tourdata1 . "|" . $jb_tourdata2 . "|" . $jb_tourdata3)));
    updateStmt("job", "jb_id", $jb_id, array(
      "jb_totalprice", $jb_totalprice, "jb_subtotalprice", $jb_subtotal, "jb_cr_price", $jb_cr_price_total, "jb_markup", $jb_markup, "jb_tourdata", $jb_tourdata1 . "|" . $jb_tourdata2 . "|" . $jb_tourdata3));
    $insert_clause = 
      /*($jb_cr_markup > 0 ?*/ "(" . $jb_id . ", " . JB_CR_MARKUP . ", " . $jb_cr_markup . "), " /*: "")*/ .
//      ($jb_cr_fixprice > 0 ? "(" . $jb_id . ", " . JB_CR_FIXPRICE . ", " . $jb_cr_fixprice . "), " : "") .
//      ($jb_cr_fixserviceprice > 0 ? "(" . $jb_id . ", " . JB_CR_FIXSERVICEPRICE . ", " . $jb_cr_fixserviceprice  . "), " : "") .
//      ($jb_cr_serviceprice > 0 ? "(" . $jb_id . ", " . JB_CR_SERVICEPRICE . ", " . $jb_cr_serviceprice . "), " : "") .
      ($jb_cr_price_rate > 0 ? "(" . $jb_id . ", " . JB_CR_PROV . ", " . $jb_cr_price_rate . "), " : "") .
//      ($jb_cr_serviceprice_rate > 0 ? "(" . $jb_id . "," .  JB_CR_SERVICE_PROV . ", " . $jb_cr_serviceprice_rate . "), " : "") .
//      ($jb_cr_agio > 0 ? "(" . $jb_id . "," .  JB_CR_AGIO . ", " . $jb_cr_agio . "), " : "") .
      ($jb_cr_price > 0 ? "(" . $jb_id . ", " . JB_CR_SUBTOTAL . ", " . $jb_cr_price . "), " : "");
    $sqlquery = "DELETE FROM jobprice WHERE jb_id = " . $jb_id;
    writeLog_("../log/caglobal_", "mk_jb_price: [" . $sqlquery . "]");
    $db->query($sqlquery);
    $sqlquery = "INSERT INTO jobprice (jb_id, mt_sort, jbprc_price) VALUES " . substr($insert_clause, 0, strlen($insert_clause) - 2);
    writeLog_("../log/caglobal_", "mk_jb_price: [" . $sqlquery . "]");
    $db->query($sqlquery);
  } else {
    echo "\$jb_id = " . $jb_id . "\n";
    if (round($row['jb_subtotalprice'], 2) != round($jb_subtotal, 2) || round($row['jb_totalprice'], 2) != round($jb_totalprice, 2) ||
      round($db->getOne("SELECT jbprc_price FROM jobprice WHERE jb_id = " . $jb_id . " AND mt_sort = " . JB_CR_SUBTOTAL), 2) != round($jb_cr_price, 2) || round($row['jb_cr_price'], 2) != round($jb_cr_price_total, 2)) {
      echo "\$row['hq_id'] = " . $row['hq_id'] . ", \$row['jb_ordertime'] = " . $row['jb_ordertime'] . "\n";
//      echo "\$row['vht_id'] = " . $row['vht_id'] . "\n";
//      echo "\$row['csc_id_payer'] = " . $row['csc_id_payer'] . "\n";
//      echo "\$row['csc_id_payer_cash'] = " . $row['csc_id_payer_cash'] . "\n";
//      echo "\$row['jb_createtime'] = " . $row['jb_createtime'] . "\n";
      if ($row['jb_markup'] != 0)
        echo "\$row['jb_markup'] = " . $row['jb_markup'] . "\n";
      if ($row['jb_fixprice'] != 0)
        echo "\$row['jb_fixprice'] = " . $row['jb_fixprice'] . "\n";
      if ($row['jb_cr_subprice'] != 0)
        echo "\$row['jb_cr_subprice'] = " . $row['jb_cr_subprice'] . " ( = \$jb_cr_fixprice)\n";
      if ($row['jb_serviceprice'] != 0)
        echo "\$row['jb_serviceprice'] = " . $row['jb_serviceprice'] . "\n";
      $jbprc_jb_cr_markup = $db->getOne("SELECT jbprc_price FROM jobprice WHERE jb_id = " . $jb_id . " AND mt_sort = " . JB_CR_MARKUP);
      if ($jbprc_jb_cr_markup != "" && $jbprc_jb_cr_markup != 0)
        echo "JB_CR_MARKUP = " . $jbprc_jb_cr_markup . "\n";
      $jbprc_jb_cr_fixprice = $db->getOne("SELECT jbprc_price FROM jobprice WHERE jb_id = " . $jb_id . " AND mt_sort = " . JB_CR_FIXPRICE);
      if ($jbprc_jb_cr_fixprice != "" && $jbprc_jb_cr_fixprice != 0)
        echo "JB_CR_FIXPRICE = " . $jbprc_jb_cr_fixprice . "\n";
      $jbprc_jb_cr_fixserviceprice = $db->getOne("SELECT jbprc_price FROM jobprice WHERE jb_id = " . $jb_id . " AND mt_sort = " . JB_CR_FIXSERVICEPRICE);
      if ($jbprc_jb_cr_fixserviceprice != "" && $jbprc_jb_cr_fixserviceprice != 0)
        echo "JB_CR_FIXSERVICEPRICE = " . $jbprc_jb_cr_fixserviceprice . "\n";
      $jbprc_jb_cr_serviceprice = $db->getOne("SELECT jbprc_price FROM jobprice WHERE jb_id = " . $jb_id . " AND mt_sort = " . JB_CR_SERVICEPRICE);
      if ($jbprc_jb_cr_serviceprice != "" && $jbprc_jb_cr_serviceprice != 0)
        echo "JB_CR_SERVICEPRICE = " . $jbprc_jb_cr_serviceprice . "\n";
      $jbprc_jb_cr_prov = $db->getOne("SELECT jbprc_price FROM jobprice WHERE jb_id = " . $jb_id . " AND mt_sort = " . JB_CR_PROV);
      if ($jbprc_jb_cr_prov != "" && $jbprc_jb_cr_prov != 0)
        echo "JB_CR_PROV = " . $jbprc_jb_cr_prov . "\n";
//      echo "\$jb_cr_price_rate = " . $jb_cr_price_rate . "\n";
      $jbprc_jb_cr_service_prov = $db->getOne("SELECT jbprc_price FROM jobprice WHERE jb_id = " . $jb_id . " AND mt_sort = " . JB_CR_SERVICE_PROV);
      if ($jbprc_jb_cr_service_prov != "" && $jbprc_jb_cr_service_prov != 0)
        echo "JB_CR_SERVICE_PROV = " . $jbprc_jb_cr_service_prov . "\n";
//      echo "\$jb_cr_serviceprice_rate = " . $jb_cr_serviceprice_rate . "\n";
      $jbprc_jb_cr_agio = $db->getOne("SELECT jbprc_price FROM jobprice WHERE jb_id = " . $jb_id . " AND mt_sort = " . JB_CR_AGIO);
      if ($jbprc_jb_cr_agio != "" && $jbprc_jb_cr_agio != 0)
        echo "JB_CR_AGIO = " . $jbprc_jb_cr_agio . "\n";
//      echo "\$jb_cr_agio = " . $jb_cr_agio . "\n";
      $jbprc_jb_markup_man = $db->getOne("SELECT jbprc_price FROM jobprice WHERE jb_id = " . $jb_id . " AND mt_sort = " . JB_MARKUP_MAN);
      if ($jbprc_jb_markup_man != "" && $jbprc_jb_markup_man != 0)
        echo "JB_MARKUP_MAN = " . $jbprc_jb_markup_man . "\n";
      $jbprc_jb_cr_markup_man = $db->getOne("SELECT jbprc_price FROM jobprice WHERE jb_id = " . $jb_id . " AND mt_sort = " . JB_CR_MARKUP_MAN);
      if ($jbprc_jb_cr_markup_man != "" && $jbprc_jb_cr_markup_man != 0)
        echo "JB_CR_MARKUP_MAN = " . $jbprc_jb_cr_markup_man . "\n";
      $jbprc_jb_cr_subtotal = $db->getOne("SELECT jbprc_price FROM jobprice WHERE jb_id = " . $jb_id . " AND mt_sort = " . JB_CR_SUBTOTAL);
      if ($jbprc_jb_cr_subtotal != "" && $jbprc_jb_cr_subtotal != 0)
        echo "JB_CR_SUBTOTAL = " . $jbprc_jb_cr_subtotal . "\n";
      if (round($jbprc_jb_cr_subtotal, 2) != round($jb_cr_price, 2)) // repairing a previous bug
        echo ($jbprc_jb_cr_subtotal != "" ? "UPDATE jobprice SET jbprc_price = " . $jb_cr_price . " WHERE jb_id = " . $jb_id . " AND mt_sort = " . JB_CR_SUBTOTAL . " AND jbprc_price = " . $jbprc_jb_cr_subtotal
          : "INSERT INTO jobprice (jb_id, mt_sort, jbprc_price) VALUES " . "(" . $jb_id . ", " . JB_CR_SUBTOTAL . ", " . $jb_cr_price . ")") . ";\n";
      echo "\$row['jb_subtotalprice'] = " . $row['jb_subtotalprice'] . ", \$jb_subtotal = " . $jb_subtotal . "\n";
      echo "\$row['jb_totalprice'] = " . $row['jb_totalprice'] . ", \$jb_totalprice = " . $jb_totalprice . "\n";
      echo "jb_cr_subtotal (mt_sort = " . JB_CR_SUBTOTAL . ") = " . $jbprc_jb_cr_subtotal . ", \$jb_cr_subtotal = " . $jb_cr_price . "\n";
      echo "\$row['jb_cr_price'] = " . $row['jb_cr_price'] . ", \$jb_cr_price_total = " . $jb_cr_price_total . "\n";
    }
  }
}

function mk_jb_cr_price_text($jb_cr_price_tmpArr, $f_jb_id, $jb_cr_price_tmp_time, $jb_km_unrounded) {
  global $db;

  $tsz_string = " (inkl. " . str_replace(".", ",", sprintf("%01.2f", $jb_cr_price_tmpArr["\$cr_fuel_markup"])) . "% TSZ)";

  return
    "Stand: " . substr($jb_cr_price_tmp_time, 8, 2) . "." . substr($jb_cr_price_tmp_time, 5, 2) . "." . substr($jb_cr_price_tmp_time, 0, 4) . " " . substr($jb_cr_price_tmp_time, 10, 9) . " Uhr\n" .
    "Fahrer: " . $jb_cr_price_tmpArr["\$cr_sid"] . "\n" .
    "Fahrzeug: " . $jb_cr_price_tmpArr["\$cr_vehicle"] . "\n" .
    "Standort: " . $jb_cr_price_tmpArr["\$current_location"] . " (" . $jb_cr_price_tmpArr["\$cr_gps_lat"] . ", " . $jb_cr_price_tmpArr["\$cr_gps_long"] . ")" . "\n" .
    ($jb_cr_price_tmpArr["\$cr_is_occupied"] != 1 ? "Anfahrt min.: " . $jb_cr_price_tmpArr["\$starting_min"] : "Aktueller Auftrag: " . $jb_cr_price_tmpArr["\$jb_id_occupied"]) . "\n" .
    ($jb_cr_price_tmpArr["\$cr_is_occupied"] != 1 ? "KM zur Start-PLZ: " . $jb_cr_price_tmpArr["\$starting_km"] : "Ziel-PLZ: " . $jb_cr_price_tmpArr["\$cur_zipcode_occupied"]) . "\n" .
    ($jb_cr_price_tmpArr["\$is_desiredzipcode"] != 1 ? "Heimat-PLZ: " : "Wunsch-PLZ: ") . $jb_cr_price_tmpArr["\$cr_homezipcode"] . " (" . $jb_cr_price_tmpArr["\$home_gps_lat"] . ", " . $jb_cr_price_tmpArr["\$home_gps_long"] . ")" . "\n" .
    (isset($jb_cr_price_tmpArr["\$ending_km"]) ? "KM zur " . ($jb_cr_price_tmpArr["\$is_desiredzipcode"] != 1 ? "Heimat-PLZ" : "Wunsch-PLZ") . ": " . $jb_cr_price_tmpArr["\$ending_km"] . "\n" : "").
    "Frachtvergütung: " . str_replace(".", ",", sprintf("%01.2f", $jb_cr_price_tmpArr["\$jb_cr_price"])) . " " . chr(128) . $tsz_string . "\n\n" .
    (getParameterValue("0", "BWV_CR_PRICE_RETOUR", "0") == "1"
      ? "Vergütung nur Hinfahrt:\n  Grundpreis " . str_replace(".", ",", sprintf("%01.2f", $jb_cr_price_tmpArr["\$basic_cr_price"])) . " " . chr(128) . " und " . round($jb_cr_price_tmpArr["\$starting_m"] / 1000 + $jb_km_unrounded)  . " Km zu " . str_replace(".", ",", sprintf("%01.2f", $jb_cr_price_tmpArr["\$cr_price_per_km_rund"])) . " " . chr(128) . " = " . str_replace(".", ",", sprintf("%01.2f", $jb_cr_price_tmpArr["\$jb_cr_price_one_way"])) . " " . chr(128) . $tsz_string . "\n"
      : "") .
    "Vergütung nach Rundkilometern:\n  Grundpreis " . str_replace(".", ",", sprintf("%01.2f", $jb_cr_price_tmpArr["\$basic_cr_price"])) . " " . chr(128) . " und "  . $jb_cr_price_tmpArr["\$round_km"] . " Km zu " . $jb_cr_price_tmpArr["\$cr_price_per_km_rund"] . " " . chr(128) . " = " . str_replace(".", ",", sprintf("%01.2f", $jb_cr_price_tmpArr["\$cr_price_longhaul_rund"])) . " " . chr(128) . $tsz_string . "\n" .
    "Vergütung nach Lastkilometern (PZM):\n  " /* . str_replace(".", ",", sprintf("%01.2f", round($db->getOne("SELECT jbprc_price FROM jobprice WHERE jb_id = " . $f_jb_id . " AND mt_sort = 11"), 2))) . " Km zu " . str_replace(".", ",", sprintf("%01.2f", $jb_cr_price_tmpArr["\$cr_price_per_km_last"])) . " " . chr(128) . " = " */ . str_replace(".", ",", sprintf("%01.2f", $jb_cr_price_tmpArr["\$cr_price_longhaul_last"])) . " " . chr(128) . $tsz_string . "\n";
}

// Prüfen, ob das jb_incomplete-Flag gesetzt werden muss
// $default = 1 erzwingt das Setzen des jb_incomplete-Flags
function check_jb_incomplete($jb_id, $default = 0)
{
  global $PHP_SELF, $db, $usr_id, $phpVersion;

  // 1. Kriterium: Plz-Preis/Fixpreis fehlt bzw ist Null
  $sqlquery = "SELECT trs_srv_name, trs_price, trs_discount FROM tourservice WHERE jb_id = '$jb_id' AND trs_srvt_name != 'z'";
//  writeLog_("../log/caglobal_", "\$sqlquery = " . $sqlquery);
  $res = $db->query($sqlquery);
  if (DB::isError($res)) reportDie ("$PHP_SELF: '$sqlquery': " . $res->getMessage());
  $significant_price = 0;
  while ($row = ($phpVersion >= "8.0" ? $res->fetch_assoc() : $res->fetchRow())):
//    writeLog_("../log/caglobal_", "\$row = " . json_encode($row));
    if (strpos($row['trs_srv_name'], "Grundpreis") === false):
      // Grundpreis wird ignoriert
      if ($row['trs_price'] < 0.02 && $row['trs_price'] > -0.02): // 29.06.2018: Ein einziger 0-Preis (oder 0,01 € ab 01.11.2018) muss jb_incomplete setzen; 
        $significant_price = 0;
        writeLog_("../log/caglobal_", "\$significant_price = " . $significant_price);
        break;
      endif;
      $significant_price += ($row['trs_price'] * ((100 - $row['trs_discount']) / 100));
    endif;
  endwhile;
  $res->free();
 
  // 2. Kriterium: Kommissionsnummer erforderlich, aber keine gesetzt
  $cs_commission_no_ok = true;
  $csc_id_payer = getFieldValueFromId("job", "jb_id", $jb_id, "csc_id_payer");
  $cs_commission_no = $db->getOne("SELECT cs_commission_no from customer WHERE cs_id = " .
    getFieldValueFromId("costcenter", "csc_id", $csc_id_payer, "cs_id"));
  if ($cs_commission_no == 1 &&
    // Neu ab 31.01.2020: Fehlende Kommissionsnummer führt nicht mehr zu jb_incomplete, wenn vom Kunden eingegeben
    getFieldValueFromId("user", "usr_id", $usr_id, "usr_type") != 2):
    $cs_commission_no_ok = false;
// Ab 01.12.2025: jb_commission_no statt tr_commission_no
//    if ($db->getOne("SELECT COUNT(tr_commission_no) FROM tour WHERE jb_id = '$jb_id' AND (TRIM(tr_commission_no) != '' AND tr_commission_no IS NOT NULL)") > 0):
    if ($db->getOne("SELECT TRIM(jb_commission_no) FROM job WHERE jb_id = '$jb_id'") != ""):
      $cs_commission_no_ok = true;
    endif;
  endif;
//echo "|$cs_commission_no_ok|<br>\n";

  // 3. Kriterium: 18.03.2024: co2e ist erforderlich (cmp_sustainability_email ist gesetzt), aber nicht vorhanden
  $cmp_sustainability_email_ok = true;
  $cs_id = getFieldValueFromId("costcenter", "csc_id", $csc_id_payer, "cs_id");
//echo "|\$cs_id=$cs_id|<br>\n";
  $cmp_sustainability_email = $db->getOne("SELECT cmp_sustainability_email from company WHERE cmp_id = " . $db->getOne("SELECT cmp_id from customer WHERE cs_id = " . $cs_id));
  writeLog_("../log/caglobal_", "\$jb_id = $jb_id, \$cs_id = $cs_id, \$cmp_sustainability_email = |$cmp_sustainability_email|");
  if ($cmp_sustainability_email == ""):
    $cs_id_parent = getFieldValueFromId("customer", "cs_id", $cs_id, "cs_id_parent");
//echo "|\$cs_id_parent=$cs_id_parent|<br>\n";
    if ($cs_id_parent != 0):
      $cmp_sustainability_email = $db->getOne("SELECT cmp_sustainability_email from company WHERE cmp_id = " . $db->getOne("SELECT cmp_id from customer WHERE cs_id = " . $cs_id_parent));
      writeLog_("../log/caglobal_", "\$jb_id = $jb_id, \$cs_id_parent = $cs_id_parent, \$cmp_sustainability_email = |$cmp_sustainability_email|");
    endif;
  endif;
  if ($cmp_sustainability_email != ""):
    $jb_status = $db->getOne("SELECT jb_status FROM job WHERE jb_id = " . $jb_id);
    if ($jb_status == 2):
      $cmp_sustainability_email_ok = false;
      $co2e = $db->getOne("SELECT jbprc_price FROM jobprice WHERE jb_id = " . $jb_id . " AND mt_sort = 12");
      if ($co2e != "" && $co2e > 0):
        $cmp_sustainability_email_ok = true;
      endif;
      writeLog_("../log/caglobal_", "\$jb_id = $jb_id, \$jb_status = $jb_status, \$co2e = $co2e, \$cmp_sustainability_email_ok = |$cmp_sustainability_email_ok|");
    endif;
  endif;
//echo "|$cmp_sustainability_email_ok|<br>\n";
  // Nun schaun mer mal, ob das jb_incomplete-Flag gesetzt oder gelöscht werden muss
  if ($significant_price == 0 || $cs_commission_no_ok == false || $cmp_sustainability_email_ok == false || $default == 1):
    $tmpArr = array("jb_incomplete", 1);
  else:
    $tmpArr = array("jb_incomplete", 0);
  endif;
  // Neu ab 23.01.2013: Grundpreis nullen wenn usr_type = 2 und entfernungsabhängige Preiskomponente fehlt
  if ($significant_price == 0 && getFieldValueFromId("user", "usr_id", $usr_id, "usr_type") == 2):
    updateStmt("tourservice", "jb_id", $jb_id, array("trs_price", 0), "trs_srv_name = 'Grundpreis'");
    array_push ($tmpArr, "jb_totalprice", 0, "jb_subtotalprice", 0);
  endif;
  writeLog_("../log/caglobal_", "\$jb_id = $jb_id, \$tmpArr = " . json_encode($tmpArr));
  updateStmt("job", "jb_id", $jb_id, $tmpArr);

  // Unteraufträge beachten!!!
  list ($tmp_add_jb_ids, $tmp_add_sids, $tmp_add_prices) = getJobChildren($jb_id, "job", false);
  $tmp_add_jb_idsArr = explode("¹", $tmp_add_jb_ids);
  for ($i = 0; $i < count($tmp_add_jb_idsArr); $i++):
    // jb_id für Beleg und Gegenbeleg extrahieren
    $tmp_add_jb_idsSubArr = explode("²", $tmp_add_jb_idsArr[$i]);
    // incomplete-flag schreiben
    if ($tmp_add_jb_idsArr[$i] != ""):
//      echo $tmp_add_jb_idsSubArr[0] . "<br>";
      updateStmt("job", "jb_id", $tmp_add_jb_idsSubArr[0], $tmpArr);
//      echo $tmp_add_jb_idsSubArr[1] . "<br>";
      updateStmt("job", "jb_id", $tmp_add_jb_idsSubArr[1], $tmpArr);
    endif;
  endfor;

//  die();
}

function check_jb_serviceprice($jb_id, $hq_id, $jb_ordertime) {
  global $db;

  if (getParameterValue("0", "MASK_SERVICE_PRICE_STREET", $hq_id) != "") {
    $maskServicePriceStreetArr = explode(",", getParameterValue("0", "MASK_SERVICE_PRICE_STREET", $hq_id));
    $msps_ad_zipcode = $maskServicePriceStreetArr[0];
    $msps_ad_street = $maskServicePriceStreetArr[1];
    $msps_ad_street_no_oddArr = explode("-", $maskServicePriceStreetArr[2]);
    $msps_ad_street_no_odd_from = $msps_ad_street_no_oddArr[0];
    $msps_ad_street_no_odd_to = $msps_ad_street_no_oddArr[1];
    $msps_ad_street_no_evenArr = explode("-", $maskServicePriceStreetArr[3]);
    $msps_ad_street_no_even_from = $msps_ad_street_no_evenArr[0];
    $msps_ad_street_no_even_to =  $msps_ad_street_no_evenArr[1];
    $msps_ad_street_no_valid_from = $maskServicePriceStreetArr[4];
    $msps_ad_street_no_valid_to = $maskServicePriceStreetArr[5];
    $msps_ad_street_no_price =  $maskServicePriceStreetArr[6];

    if (strtotime(substr($jb_ordertime, 0, 10)) >= strtotime($msps_ad_street_no_valid_from) && strtotime(substr($jb_ordertime, 0, 10)) <= strtotime($msps_ad_street_no_valid_to)) {
      $i = 1;
      do {
        // gespeicherte Tour-Daten holen
        if (existsEntry("tour", array("jb_id", $jb_id, "tr_sort", $i))){
          $tourFound = 1;
          list($csc_id, $tr_comp, $tr_person, $ad_street, $tr_hsno,
            $ad_zipcode, $ad_city, $ad_country, $tr_remark, $tr_status, $tr_ware_from_to, $tr_commission_no, $tr_mediationarea_id, $tr_status, $tr_sign, $tr_signname, $tr_finishtime, $tr_id) =
            getTourData($jb_id, $i);
          $tr_hsno_ori = $tr_hsno;
          $tr_hsno = ereg_replace("[^[:digit:]+]","-", str_replace(" ", "", trim($tr_hsno)));
          if (!(strpos($tr_hsno, "-") === FALSE)) :
             $tr_hsno = substr($tr_hsno, 0, strpos($tr_hsno, "-"));
          endif;
//if ($msps_ad_zipcode == $ad_zipcode && $msps_ad_street == substr($ad_street, 0, strlen($msps_ad_street)))
//  echo $msps_ad_zipcode . " " . $ad_zipcode . " " . $msps_ad_street . " " . substr($ad_street, 0, strlen($msps_ad_street)) . " " . $tr_hsno_ori . "\n" .
//  $msps_ad_street_no_even_from  . " " . $tr_hsno . " " . $msps_ad_street_no_even_to . " " . $tr_hsno  . "\n" .
//  $msps_ad_street_no_odd_from  . " " .  $tr_hsno . " " . $msps_ad_street_no_odd_to . " " . $tr_hsno  . "\n";
          if ($msps_ad_zipcode == $ad_zipcode && $msps_ad_street == substr($ad_street, 0, strlen($msps_ad_street)) &&
             (($msps_ad_street_no_even_from <= $tr_hsno && $msps_ad_street_no_even_to >= $tr_hsno) || ($msps_ad_street_no_odd_from <= $tr_hsno && $msps_ad_street_no_odd_to >= $tr_hsno))) {
            $jb_serviceprice = $db->getOne("SELECT jb_serviceprice FROM job WHERE jb_id = " . $jb_id);
            $jb_totalprice = $db->getOne("SELECT jb_totalprice FROM job WHERE jb_id = " . $jb_id);
            $jb_subtotalprice = $db->getOne("SELECT jb_subtotalprice FROM job WHERE jb_id = " . $jb_id);
            $jb_serviceprice += $msps_ad_street_no_price;
            $jb_totalprice += $msps_ad_street_no_price;
            $jb_subtotalprice += $msps_ad_street_no_price;
//echo $jb_serviceprice . " " . $jb_totalprice  . " " . $jb_subtotalprice . "\n";
            writeLog_("../log/caglobal_", "Automatic servicetime added: \$jb_id = $jb_id, \$jb_ordertime = $jb_ordertime, \$jb_serviceprice = $jb_serviceprice");
            updateStmt("job", "jb_id", $jb_id, array("jb_serviceprice", $jb_serviceprice, "jb_totalprice", $jb_totalprice, "jb_subtotalprice", $jb_subtotalprice));
            deleteStmt("tourservice", "jb_id = " . $jb_id . " AND trs_srv_name = 'Servicepreis'");
            $csc_id_payer = $db->getOne("SELECT csc_id_payer FROM job WHERE jb_id = " . $jb_id);
            $tmpArr = array("jb_id", $jb_id, "tr_sort", 0, "srv_id", 0, "trs_srv_name", "Servicepreis", "srvt_id", 0, "trs_srvt_name", "",
              "trs_price", $jb_serviceprice, "trs_discount", 0, "csc_id", $csc_id_payer);
            insertStmt("tourservice", $tmpArr);
          }
        } else {
          $tourFound = 0;
        }
        $i++;
      } while ($tourFound == 1);
    }
  }
}

function mkCsc_id_start($csc_id_start)
{
  global $db, $hq_id, $phpVersion;

  if (trim($csc_id_start) == "" || $csc_id_start == 0)
    return "";

  $sqlquery = "SELECT csc2.csc_id, csc2.csc_name, cs.cs_id, cs.cs_eid, cs.csc_id_payer, cs.cs_commission_no," .
    "  cmp.cmp_id, cmp.cmp_comp, cmp.cmp_comp2, cmp.cmp_authenticated, cmp.cmp_remark, cmp.cmp_match, cmp.tx_id, " .
    "  cscad.ad_id, cscad.cscad_comp, cscad.cscad_comp2, cscad.cscad_hsno," .
    "  cscad.cscad_remark, cscad.cscad_person, cscad.cscad_phone," .
    "  ad.ad_street, ad.ad_zipcode, ad.ad_city, ad.ad_country " .
    "  FROM company AS cmp, customer AS cs, costcenter AS csc, costcenter AS csc2, costcenteraddress AS cscad, address AS ad " .
    "  WHERE csc.csc_id = $csc_id_start AND cs.hq_id = '$hq_id' AND cmp.cmp_id = cs.cmp_id AND cs.cs_id = csc.cs_id " .
    "  AND csc2.csc_id = csc.csc_id AND csc2.csc_is_extern = '0' AND csc2.csc_id = cscad.csc_id AND cscad.adt_id = '4' AND cscad.ad_id = ad.ad_id";
  $result = $db->query($sqlquery);
  if (DB::isError($result)) reportDie ("$PHP_SELF: " . $result->getMessage());
  while ($row = ($phpVersion >= "8.0" ? $res->fetch_assoc() : $res->fetchRow())):
    $csc_id_payer_comp = "";
      if ($row["csc_id_payer"] != "" && $row["csc_id_payer"] != 0)
        $csc_id_payer_comp = $db->getOne("SELECT cmp_comp FROM company, customer, costcenter WHERE company.cmp_id = customer.cmp_id AND customer.cs_id = costcenter.cs_id AND costcenter.csc_id = " . $row["csc_id_payer"]);
    $csc_id_start_js_code =
      "  setJobList(0, jl_csc_id, " . $row["csc_id"] . ");\n" .
      "  setJobList(0, jl_tr_comp, '" . my_str_check($row["cscad_comp"]) . "');\n" .
      "  setJobList(0, jl_tr_person, '" . my_str_check($row["cscad_person"]) . "');\n" .
      "  setJobList(0, jl_ad_street, '" . my_str_check($row["ad_street"]) . "');\n" .
      "  setJobList(0, jl_tr_hsno, '" . my_str_check($row["cscad_hsno"]) . "');\n" .
      "  setJobList(0, jl_ad_zipcode, '" . $row["ad_zipcode"] . "');\n" .
      "  setJobList(0, jl_ad_city, '" . my_str_check($row["ad_city"]) . "');\n" .
      "  setJobList(0, jl_ad_country, '" . my_str_check($row["ad_country"]) . "');\n" .
      "  setJobList(0, jl_tr_remark, '" . my_str_check($row["cscad_remark"]) . "');\n" .
      "  setJobList(0, jl_csc_id_payer, \"false\");\n" .
      "  setJobList(0, jl_hide_tr_remark, \"true\");\n" .
      "  if ('" . my_str_check($row["csc_id_payer"]) . "' != '')\n" .
      "  {\n" .
      "      setCsc_id_payer('" . my_str_check($row["csc_id_payer"]) . "', '" . my_str_check($csc_id_payer_comp) . "');\n" .
      "      parent.job_options.document.tourOptions.payer_is_default.value = \"true\";\n" .
      "  }\n" .
      "  if (" . $row["tx_id"] . " != \"\" && " . $row["tx_id"] . " != 0)\n" .
      "  {\n" .
      "    checkJb_sales_tax_rate_sign(" . $row["tx_id"] . ");\n" .
      "  }\n" .
      "  if ('" . $row["cs_eid"] . "' != \"\" && '" . $row["cs_eid"] . "' != 0)\n" .
      "  {\n" .
      javascriptAdd_cs_eid($row['csc_id'], "") .
      "  }\n" .
      "  parent.job_tour.document.tourForm.elements[nach_fields[jl_tr_comp]].focus();\n" .
      "  self.setTimeout(\"refreshFormFields()\", 100);\n" .
      "  self.setTimeout(\"resetSignificantPriceValues()\", 150);\n" .
      "  self.setTimeout(\"checkSendTour()\", 200);\n";
    if (DB::isError($result)) reportDie ("$PHP_SELF: " . $result->getMessage());
  endwhile;
  $result->free();
  return $csc_id_start_js_code;
}

function getAreaName($zipcode, $type = 0)
{
  global $db, $hq_id;

  $strStart = "";
  $strMid = "&nbsp;(";
  $strEnd = ")";
  if ($type == 1):
    $strStart = "(";
    $strMid = "&nbsp;";
    $strEnd = ")";
  endif;
  
  if (strlen($zipcode) == 5 && is_numeric($zipcode)):
    return (
      $strStart .
      $db->getOne(
        "SELECT srvpa.srvpa_name " .
        "FROM serviceplz AS srvp, serviceplzareamapping AS srvpam, serviceplzarea AS srvpa " .
        "WHERE srvp.srvp_plz = $zipcode AND srvp.srvp_id = srvpam.srvp_id AND srvpa.hq_id = '$hq_id' AND srvpam.srvpa_id = srvpa.srvpa_id") .
      $strMid .
      $db->getOne(
        "SELECT srvpa.srvpa_longname " .
        "FROM serviceplz AS srvp, serviceplzareamapping AS srvpam, serviceplzarea AS srvpa " .
        "WHERE srvp.srvp_plz = $zipcode AND srvp.srvp_id = srvpam.srvp_id AND srvpa.hq_id = '$hq_id' AND srvpam.srvpa_id = srvpa.srvpa_id") .
      $strEnd);
  else:
    return "";
  endif;
}

// Feststellen, ob ein Auftrag ursprünglich als Nacherfassung eingegeben wurde
function job_was_afterwards($jb_id)
{
  global $db;

  if ($db->getOne(
    "SELECT COUNT(*) FROM phoenix_log.log AS lg WHERE lg.jb_id = $jb_id AND (lg.logo_id = 1 OR lg.logo_id = 25) AND LEFT(lg.logo_description, 13) = 'Nacherfassung'") >= 1)
    return true;
// Jobs aus Listenerfassung berücksichtigen!
  if ($db->getOne(
    "SELECT COUNT(*) FROM jobbatchlist AS jbl WHERE jbl.jb_id = $jb_id") >= 1)
    return true;
  return false;
}

/*
// Kommissionsnummer für den Export in jb_invtext kopieren
function copy_commission_no($jb_id)
{
  global $PHP_SELF, $db, $phpVersion;

  // Kommissionsnummer finden
  $commission_no_all = "";
*/
/*  $csc_id_payer = getFieldValueFromId("job", "jb_id", $jb_id, "csc_id_payer"); */
  // Kommissionsnummer nur dann suchen und exportieren, wenn das entsprechende Flag beim Payer gesetzt ist
  // --> macht irgendwie keinen Sinn; wenn schon da, dann auch ausgeben... egal, wie dahin gekommen...
/*  $cs_commission_no = $db->getOne("SELECT cs_commission_no from customer WHERE cs_id = " .
    getFieldValueFromId("costcenter", "csc_id", $csc_id_payer, "cs_id")); 
  if ($cs_commission_no == 1): */
/*
    $sqlquery = "SELECT tr_commission_no FROM tour WHERE jb_id = '$jb_id' AND (tr_commission_no != '' AND tr_commission_no IS NOT NULL)";
    $res = $db->query($sqlquery);
    if (DB::isError($res)) reportDie ("$PHP_SELF: '$sqlquery': " . $res->getMessage());
    $commission_no_all = "";
    while ($row = ($phpVersion >= "8.0" ? $res->fetch_assoc() : $res->fetchRow())):
      if ($row['tr_commission_no'] != ""):
        $commission_no_all = $commission_no_all .
        ($commission_no_all != "" ? ", " : "Kommission: ") . $row['tr_commission_no'] . "\n";
      endif;
    endwhile;
    $res->free();
    if ($commission_no_all != ""):    
//      $jb_invtext = $db->getOne("SELECT jb_invtext from job WHERE jb_id = '" . $jb_id . "'");
//      $jb_invtext .= $commission_no_all;
//      $tmpArr = array("jb_invtext", $jb_invtext);
//      updateStmt("job", "jb_id", $jb_id, $tmpArr);
      return ("\n" . $commission_no_all);
    endif;
*/
/*  endif; */
/*
  return "";
}
*/

function getNextOrderDate($jahr, $monat, $tag, $jb_permanent, $jb_permanent2, $doLog = false, $endejahr = 2038, $endemonat = 1, $endetag = 1)
{
//  include_once("../include/calendar.inc.php");

  $tempDate = array($jahr, sprintf("%d", $monat), sprintf("%d", $tag));
  $tempDateMonth = array($jahr, sprintf("%d", $monat));

  switch ($jb_permanent)
  {
    // die ersten drei Fälle werden gleich behandelt, da es hier nur auf den Wert in jb_permanent2 ankommt
    case 1: // werktags
    case 2: // werktags mit Samstag
    case 3: // täglich
    case 9: // feiertags
      if ($jb_permanent2 != "0000000" || $jb_permanent != 9) {
        do {
          $tempDate = addDaysComplete($tempDate[0], $tempDate[1], $tempDate[2], 1);
          // Nummer des nächgsten Wochentages ermitteln
          $dayNo = date("w", mktime(0, 0, 0, $tempDate[1], $tempDate[2], $tempDate[0]));
          // Nummer umrechnen, damit mit dem Wert in jb_permanent2 verglichen werden kann
          // date()       : Montag = 1, Dienstag = 2, ..., Samstag = 6, Sonntag = 0
          // jb_permanent2: Montag = 0, Dienstag = 1, ..., Samstag = 5, Sonntag = 6
          if ($dayNo == 0):
            $dayNo = 6;
          else:
            $dayNo -= 1;
          endif;
          if ($doLog)
            writeLog_("../log/check_jb_permanent_standing_", "  next date: " . $tempDate[0] . "-" . $tempDate[1] . "-" . $tempDate[2] . ", dayNo: $dayNo");
          // Überprüfen, ob der nächste Wochentag in jb_permanent2 vorhanden ist
          $jb_permanent_ok = false;
          if (substr($jb_permanent2, $dayNo, 1) == "1")
            $jb_permanent_ok = true;
        } while ((isPublicHoliday($tempDate[0], $tempDate[1], $tempDate[2], $doLog) != "" || !$jb_permanent_ok)
        /* && (mktime(0, 0, 0, $tempDate[1], $tempDate[2], $tempDate[0]) <= mktime(0, 0, 0, $endemonat, $endetag, $endejahr))*/);
      }
      if ($jb_permanent == 9) {
        $jb_permanent2_tempDate = $tempDate;
        $tempDate = array($jahr, sprintf("%d", $monat), sprintf("%d", $tag));
        do {
          $tempDate = addDaysComplete($tempDate[0], $tempDate[1], $tempDate[2], 1);
        } while (!(isPublicHoliday($tempDate[0], $tempDate[1], $tempDate[2], $doLog) != "") && mktime(0, 0, 0, $tempDate[1], $tempDate[2], $tempDate[0]) <= mktime(0, 0, 0, $endemonat, $endetag, $endejahr));
        if ($doLog)
          writeLog_("../log/check_jb_permanent_standing_", "  next date from \$jb_permanent == 9: " . $tempDate[0] . "-" . $tempDate[1] . "-" . $tempDate[2]);
//print_r($jb_permanent2_tempDate);
//echo mktime(0, 0, 0, $jb_permanent2_tempDate[1], $jb_permanent2_tempDate[2], $jb_permanent2_tempDate[0]) . "\n";
//print_r($tempDate);
//echo mktime(0, 0, 0, $tempDate[1], $tempDate[2], $tempDate[0]) . "\n";
        if ($jb_permanent2 != "0000000" && mktime(0, 0, 0, $jb_permanent2_tempDate[1], $jb_permanent2_tempDate[2], $jb_permanent2_tempDate[0]) < mktime(0, 0, 0, $tempDate[1], $tempDate[2], $tempDate[0])) {
          $tempDate = $jb_permanent2_tempDate;
        }
        if ($doLog)
          writeLog_("../log/check_jb_permanent_standing_", "  resulting date with \$jb_permanent == 9: " . $tempDate[0] . "-" . $tempDate[1] . "-" . $tempDate[2]);
      }
      break;
    case 4: // wöchentlich
      $tempDate = addDaysComplete($tempDate[0], $tempDate[1], $tempDate[2], 7);
      while (isPublicHoliday($tempDate[0], $tempDate[1], $tempDate[2], $doLog) != "")
        $tempDate = addDaysComplete($tempDate[0], $tempDate[1], $tempDate[2], 1);
      break;
    case 5: // vierzehntägig
      $tempDate = addDaysComplete($tempDate[0], $tempDate[1], $tempDate[2], 14);
      while (isPublicHoliday($tempDate[0], $tempDate[1], $tempDate[2], $doLog) != "")
        $tempDate = addDaysComplete($tempDate[0], $tempDate[1], $tempDate[2], 1);
      break;
    case 6: // monatlich
      $tempDateMonth = addMonths($tempDateMonth[0], $tempDateMonth[1], 1);
      $tempDate[0] = $tempDateMonth[0];
      $tempDate[1] = $tempDateMonth[1];
      if ($tempDate[2] > daysPerMonth($tempDateMonth[0], $tempDateMonth[1]))
        $tempDate[2] = daysPerMonth($tempDateMonth[0], $tempDateMonth[1]);
      while (isPublicHoliday($tempDate[0], $tempDate[1], $tempDate[2], $doLog) != "")
        $tempDate = addDaysComplete($tempDate[0], $tempDate[1], $tempDate[2], 1);
      break;
    case 7: // monatlich zum Monatsende
      $tempDateMonth = addMonths($tempDateMonth[0], $tempDateMonth[1], 1);
      $tempDate[0] = $tempDateMonth[0];
      $tempDate[1] = $tempDateMonth[1];
      $tempDate[2] = daysPerMonth($tempDateMonth[0], $tempDateMonth[1]);
      while (isPublicHoliday($tempDate[0], $tempDate[1], $tempDate[2], $doLog) != "")
        $tempDate = addDaysComplete($tempDate[0], $tempDate[1], $tempDate[2], -1);
      break;
    case 8: // vierzehntätig zum Monatsende (15. und 31.)
      if ($tempDate[2] < 20):
        // nächster Termin ist Monatsende desselben Monats
        // wie monatlich zum Monatsende
        $tempDate[0] = $tempDateMonth[0];
        $tempDate[1] = $tempDateMonth[1];
        $tempDate[2] = daysPerMonth($tempDateMonth[0], $tempDateMonth[1]);
        while (isPublicHoliday($tempDate[0], $tempDate[1], $tempDate[2], $doLog) != "")
          $tempDate = addDaysComplete($tempDate[0], $tempDate[1], $tempDate[2], -1);
        break;
      else:
        // nächster Termin ist der 15. des nächsten Monats
        $tempDateMonth = addMonths($tempDateMonth[0], $tempDateMonth[1], 1);
        $tempDate[0] = $tempDateMonth[0];
        $tempDate[1] = $tempDateMonth[1];
        $tempDate[2] = 15;
        while (isPublicHoliday($tempDate[0], $tempDate[1], $tempDate[2], $doLog) != "")
          $tempDate = addDaysComplete($tempDate[0], $tempDate[1], $tempDate[2], -1);
        break;
      endif;
    case 10: // vierzehntätig zum Monatsanfang (16. und 1.)
      if ($tempDate[2] < 16):
        // nächster Termin ist der 16. desselben Monats
        $tempDate[0] = $tempDateMonth[0];
        $tempDate[1] = $tempDateMonth[1];
        $tempDate[2] = 16;
        while (isPublicHoliday($tempDate[0], $tempDate[1], $tempDate[2], $doLog) != "")
          $tempDate = addDaysComplete($tempDate[0], $tempDate[1], $tempDate[2], 1);
        break;
      else:
        // nächster Termin ist der 1. des nächsten Monats
        $tempDateMonth = addMonths($tempDateMonth[0], $tempDateMonth[1], 1);
        $tempDate[0] = $tempDateMonth[0];
        $tempDate[1] = $tempDateMonth[1];
        $tempDate[2] = 1;
        while (isPublicHoliday($tempDate[0], $tempDate[1], $tempDate[2], $doLog) != "")
          $tempDate = addDaysComplete($tempDate[0], $tempDate[1], $tempDate[2], 1);
        break;
      endif;
    case 11: // vierwöchentlich
      $tempDate = addDaysComplete($tempDate[0], $tempDate[1], $tempDate[2], 28);
      while (isPublicHoliday($tempDate[0], $tempDate[1], $tempDate[2], $doLog) != "")
        $tempDate = addDaysComplete($tempDate[0], $tempDate[1], $tempDate[2], 1);
      break;
//    case 9: // quartalsweise
//      do
//        $tempDateMonth = addMonths($tempDateMonth[0], $tempDateMonth[1], 3);
//      while (isPublicHoliday($tempDateMonth[0], $tempDateMonth[1], $tempDate[2], $doLog) != "");
//      $tempDate[0] = $tempDateMonth[0];
//      $tempDate[1] = $tempDateMonth[1];
//      break;
//    case 10: // halbjährlich
//      do
//        $tempDateMonth = addMonths($tempDateMonth[0], $tempDateMonth[1], 6);
//      while (isPublicHoliday($tempDateMonth[0], $tempDateMonth[1], $tempDate[2], $doLog) != "");
//      $tempDate[0] = $tempDateMonth[0];
//      $tempDate[1] = $tempDateMonth[1];
//      break;
//    case 11: // jährlich
//      do
//        $tempDateMonth = addMonths($tempDateMonth[0], $tempDateMonth[1], 12);
//      while (isPublicHoliday($tempDateMonth[0], $tempDateMonth[1], $tempDate[2], $doLog) != "");
//      $tempDate[0] = $tempDateMonth[0];
//      $tempDate[1] = $tempDateMonth[1];
  }
  return $tempDate;
}

function isPublicHoliday($year, $month, $day, $doLog = false)
{
  global $ph;

  for ($i = 0; $i < count($ph); $i++):
    if ($ph[$i][0] == $year && $ph[$i][1] == $month && $ph[$i][2] == $day):
if ($doLog)
  writeLog_("../log/check_jb_permanent_standing_", "  isPublicHoliday($year, $month, $day) = true");
      return true;
    endif;
  endfor;
if ($doLog)
  writeLog_("../log/check_jb_permanent_standing_", "  isPublicHoliday($year, $month, $day) = false");
  return false;
}

$timeofday1 = array();
function trace_execution_time_start()
{
  global $timeofday1;
  
  $timeofday1[] = gettimeofday();
//echo $timeofday1["sec"] . "." . sprintf("%06d", $timeofday1["usec"]) . "<br>";  
}

function trace_execution_time_stop($msg = "")
{
  global $timeofday1;
  
  $tod1 = $timeofday1; 
  $timeofday2 = gettimeofday();
  $tod1_pop = array_pop($tod1);
//echo $timeofday2["sec"] . "." . sprintf("%06d", $timeofday2["usec"]) . "<br>";  
  return $msg . "[" .
  (($timeofday2["usec"] >= $tod1_pop["usec"]) ?
  ($timeofday2["sec"] - $tod1_pop["sec"]) :
  ($timeofday2["sec"] - $tod1_pop["sec"] - 1))
  . "." .
  (($timeofday2["usec"] >= $tod1_pop["usec"]) ?
  (sprintf("%03d", floor(($timeofday2["usec"] - $tod1_pop["usec"]) / 1000))) :
  (sprintf("%03d", floor((1000000 + $timeofday2["usec"] - $tod1_pop["usec"]) / 1000)))) .
  " sec]";
}

function writeLog_($logfilename, $log_text) {
//  echo "[" . date("Y-m-d H:i:s O") . "] " . $log_text .  "\n";
  $today = getdate();
  $fileHandle = @fopen($logfilename . $today['year'] . sprintf("%02d", $today['mon']) . ".log", 'a');
  if (!$fileHandle) {
    $fileHandle = @fopen($logfilename . $today['year'] . sprintf("%02d", $today['mon']) . ".web.log", 'a');
  }
  @fwrite($fileHandle, "[" . date("Y-m-d H:i:s") . "] " . $log_text .  "\n");
  @fclose($fileHandle);
  return;
}

?>
