<?php
/*=======================================================================
 *
 * order_status.php
 *
 * Autor: Carsten Annacker
 *
 =======================================================================*/

// Tobedone: Doppelte Scans herausfiltern!
// ältesten senden

// Skript soll unabhängig vom aktuellen Pfad per cron aufgerufen werden können
chdir('/srv/www/htm/tools/');

include_once("../include/glob_defs.inc.php");
include_once("../include/inc_scan_events.inc.php");
include_once("../include/inc_parseXML.inc.php");

//INSERT INTO parameter (par_key, md_id, hq_id, emp_id, par_value, par_text) VALUES ('ORDER_STATUS_AUTHENTICATIONTICKET', 0, 0, 0, '', 'ticket for authentication on status updates');
//INSERT INTO parameter (par_key, md_id, hq_id, emp_id, par_value, par_text) VALUES ('ORDER_STATUS_AUTHENTICATIONTIME', 0, 0, 0, '', 'authentication ticket is valid for 4 hours only');
//INSERT INTO parameter (par_key, md_id, hq_id, emp_id, par_value, par_text) VALUES ('ORDER_STATUS_MESSAGEID', 0, 0, 0, '', 'unique message id for status updates (to be incremented after each single message)');

$log_file_name = "order_status";
$test_do_not_send = false;
$test_send = false;
$req_user_OS = "Hansetrans";
if ($test_do_not_send) {
  $req_host_LCD    = "";
  $req_port_LCD    = "";
  $req_service_LCD = "";
  $req_pass_LCD    = "";
  $req_user_LCD    = "";
  $req_host_OS     = "";
  $req_port_OS     = "";
  $req_service_OS  = "";
  $Locality        = "NA";
  $OrderNumberSource = "A03";
} elseif ($test_send) {
  $req_host_LCD    = "cdt-test.centiro.se";
  $req_port_LCD    = "80";
  $req_service_LCD = "/Universe.Services/NorthAmerica/Shipping/7/1/ShipmentProcess.svc";
  $req_pass_LCD    = "ikea123dk";
  $req_user_LCD    = "minitrans@dk.nordic.eu.ikea.com";
  $req_host_OS     = "testexternal-ikea.centiro.com";
  $req_port_OS     = "80";
  $req_service_OS  = "/Facades/Ikea/OtherServices/4/1/ServiceProvidersFacade.svc";
  $Locality        = "NA";
  $OrderNumberSource = "A03";
} else {
  $req_host_LCD    = "eu.centiro.ikea.com";
  $req_port_LCD    = "80";
  $req_service_LCD = "/Universe.Services/Shipping/7/1/ShipmentProcess.svc";
  $req_pass_LCD    = "H4ns3transCent!";
  $req_user_LCD    = "Hansetrans@de.ikea.com";
  $req_host_OS     = "eu.centiro.ikea.com";
  $req_port_OS     = "80";
  $req_service_OS  = "/Facades/Ikea/OtherServices/4/1/ServiceProvidersFacade.svc";
  $Locality        = "EU";
  $OrderNumberSource = "A01";
}

$eventMsgArrayLCD["102"] = "Handed over to TSP"; // Übernahme IKEA
$eventMsgArrayLCD["201"] = "Received at HUB"; // Einlagern LSC
$eventMsgArrayLCD["202"] = "Loaded on delivery truck"; // Auslagern LSC
$eventMsgArrayLCD["301"] = "Order delivered"; // Erledigt // Lieferung
$eventMsgArrayLCD["304"] = "Failed delivery"; // keine Anlieferung möglich
$eventMsgArrayLCD["351"] = "Picked up at customer"; // Abholung erfolgte
$eventMsgArrayLCD["354"] = "Failed Pick-up"; // keine Abholung möglich
$eventMsgArrayLCD["359"] = "Returned to Store Pick-Up"; // Übergabe an IKEA nach Abholung
$eventMsgArrayLCD["408"] = "Returned to Store"; // Übergabe an IKEA
$eventMsgArrayOS["501"] = "Planned"; // "Order is planned";
$eventMsgArrayOS["502"] = "LockedForChange"; // "Order is locked for Change";
$eventMsgArrayOS["301"] = "Completed"; // "Order completed" // Erledigt, Montage
//$eventMsgArray[1]["304"] = "Failed"; // "Failed" // Keine Montage möglich, Montage // Definiton hier nicht nötig, da es nicht gesendet wird

$mysql_db = mysql_connect($dbhost, $dblogin, $dbpassword) or die (mysql_error($mysql_db));
mysql_select_db("phoenix", $mysql_db) or die (mysql_error($mysql_db));
mysql_query('SET NAMES latin1', $mysql_db) or die ('SET NAMES latin1' . ": " . mysql_error($mysql_db));

$serviceMont  = pow(2, get_first("SELECT mt_sort FROM metatype WHERE mt_type = 'service' AND mt_mapped_value = 'MO'"));
$serviceAbhol = pow(2, get_first("SELECT mt_sort FROM metatype WHERE mt_type = 'service' AND mt_mapped_value = 'AB'"));

//$status = reqUploadOS(
//  array(
//    array($eventMsgArrayOS["501"], date("Y-m-d H:i:s"), "T82120395", "100"),
//  )
//);
//$status = reqUploadLCD(
//  array(
//    array($eventMsgArrayLCD["102"], "2015-02-27T16:46:51", "102", "DE", "Sindelfingen", "HA000000003", "", "110"),
//    array($eventMsgArrayLCD["201"], "2015-02-27T16:47:14", "201", "DE", "Sindelfingen", "HA000000003", "", "110"),
//    array($eventMsgArrayLCD["202"], "2015-02-27T20:08:42", "202", "DE", "Sindelfingen", "HA000000003", "", "110"),
//    array($eventMsgArrayLCD["301"], "2015-02-27T20:08:54", "301", "DE", "Sindelfingen", "HA000000003", "Eric", "110")
//  )
//);
//die();

/********************************************************************************/
// Vorbereitende Maßnahmen

writeLog_order_status("___________________________________________________________________________________");
// "Order delivered" und "Failed delivery" in "Picked up at customer" und "Failed Pick-up" umoperieren wenn Abholung
// Write time from the arrival-button in events '301', '304' and '351'
check_pickup_and_arr_tour();

// die aktuelle bo_id merken, damit später hinzugekommene Events beim Senden nicht berücksichtigt werden,
// da diese ja u.U. von dem nachfolgenden  Arbeitschritt noch umgewandelt werden müssen
//$max_bo_id = get_first("SELECT MAX(bo_id) FROM phoenix_log.b2b_objects WHERE bo_type = 300 AND bo_createtime <= SUBTIME(CONCAT(LEFT(NOW(), 14), FLOOR(MID(NOW(), 15, 1) / 3 ) * 3, '0:00'), '00:30:00')");
$max_bo_createtime = get_first("SELECT SUBTIME(CONCAT(LEFT(NOW(), 14), FLOOR(MID(NOW(), 15, 1) / 3 ) * 3, '0:00'), '00:30:00')");
writeLog_order_status("[" . date("Y-m-d H:i:s") . "] " . "\$max_bo_createtime = " . $max_bo_createtime);

writeLog_order_status("-----------------------------------------------------------------------------------");
writeLog_order_status("[" . date("Y-m-d H:i:s") . "] " . "*** set all 'Planned'-Events to pending ***");
// alle Planned-Events erstmal auf pending setzen, da sie die weitere Bearbeitung blockieren
// erst wenn "LockedForChange" stattfindet, dann auch "Planned" mitsenden
$sql_query = "SELECT bo_id FROM phoenix_log.b2b_objects WHERE bo_type = 300 AND bo_state IN (1) AND bo_obj_data LIKE '%|501%'";
$res = exec_query($sql_query, NULL, false);
while ($row = mysql_fetch_array($res, MYSQL_ASSOC)):
  // Planned erst einmal nicht mehr senden, da dies die weitere Bearbeitung blockiert
  exec_query("UPDATE phoenix_log.b2b_objects SET bo_state = -1 WHERE bo_id = " . $row["bo_id"]);
endwhile;

writeLog_order_status("-----------------------------------------------------------------------------------");
writeLog_order_status("[" . date("Y-m-d H:i:s") . "] " . "*** check for 'LockedForChange'-Events to be sent ***");
// Fällige LockedForChange-Events ermitteln
// dabei auch das "pending" Planned-Event mit senden
//$sql_query = "SELECT bo_id, bo_obj_data FROM phoenix_log.b2b_objects WHERE bo_type = 300 AND bo_state = -1 AND bo_obj_data LIKE '%|501%'";
$sql_query = "SELECT bo_id, bo_obj_data FROM phoenix_log.b2b_objects WHERE bo_type = 300 AND ((bo_state = -1 AND bo_obj_data LIKE '%|501%') OR bo_obj_data LIKE '%|502%') AND NOT (bo_obj_data LIKE 'HA%') ORDER BY bo_obj_data DESC";
$res = exec_query($sql_query, NULL, false);
$prev_sequence_no_502 = "";
$last_502_written = "";
while ($row = mysql_fetch_array($res, MYSQL_ASSOC)):
  list ($sequence_no, $tmp_event) = explode("|", $row["bo_obj_data"]);
  if ($tmp_event == "502") {
    $prev_sequence_no_502 = $sequence_no;
  } elseif ($prev_sequence_no_502 != $sequence_no) {
  	// Vorgängerevent (ist ja absteigend sortiert) ist kein "502" -> "502" fehlt also noch; prüfen, ob die Zeit gekommen ist, es zu schreiben...
    list($jb_ordertime, $jb_id) = get_first_row("SELECT jb_ordertime, job.jb_id FROM job, tour WHERE tr_commission_no = '" . $sequence_no . "' AND job.jb_id = tour.jb_id");
    if ($jb_ordertime != "") {
      $jb_o_t = strtotime($jb_ordertime);
      $LFC_time = mktime(date("H", $jb_o_t) - 54, date("i", $jb_o_t), date("s", $jb_o_t), date("m", $jb_o_t), date("d", $jb_o_t), date("Y", $jb_o_t));
      if (time() > $LFC_time
        /* && get_first("SELECT bo_id FROM phoenix_log.b2b_objects WHERE bo_type = 300 AND bo_obj_data = '" . $sequence_no . "|502'") == "" */)
      {
      	// die LFC_time kann natürlich nicht kleiner sein als Zeit des ersten Eingangs des Auftrags
        $jb_createtime_earliest = findEarliestJb_createtime($jb_id);
        if (strtotime($jb_createtime_earliest) > $LFC_time)
          $LFC_time = strtotime($jb_createtime_earliest);
        // LockedForChange schreiben (wenn nicht durch doppeltes 501-Event vorher schon geschrieben)
        if ($last_502_written != $sequence_no) {
          writeLog_order_status("[" . date("Y-m-d H:i:s") . "] " . "Barcode '" . $sequence_no . "': Auftragszeit = '" . $jb_ordertime . "', LFC-Zeit = '" . date("Y-m-d H:i:s", $LFC_time) . ", Einstellungszeit = '" . $jb_createtime_earliest . "'");
          exec_query("INSERT INTO phoenix_log.b2b_objects (bo_ver, bo_type, bo_state, bo_ext_id0, bo_ext_id1, bo_ext_id2, bo_obj_data, bo_createtime)" .
            " VALUES (0, 300, 1, 0, 0, 0, '" . $sequence_no . "|502', '" . date("Y-m-d H:i:s", $LFC_time) . "')");
          $last_502_written = $sequence_no;
//// Achtung: LockedForChange wird wegen $max_bo_id hier nicht mitgesendet, daher muss $max_bo_id angepasst werden
//// funktioniert natürlich nur nachts, wenn sonst nicht stattfindet
////        $max_bo_id = get_first("SELECT bo_id FROM phoenix_log.b2b_objects WHERE bo_type = 300 AND bo_obj_data = '" . $sequence_no . "|502'");
//          $max_bo_id = mysql_insert_id();
          // jetzt auch das pending "Planned" wegschreiben
          // bo_state muss hier auf '7' (nicht '1') gesetzt werden, da die neue bo_createtime kleiner ist als $max_bo_createtime;
          // das heißt, das das Event würde in diesem Lauf nicht gesendet und im nächsten Lauf wieder automatisch auf -1 gesetzt werden;
          exec_query("UPDATE phoenix_log.b2b_objects SET bo_state = 7, bo_createtime = '" . date("Y-m-d H:i:s", $LFC_time) . "' WHERE bo_id = " . $row["bo_id"] . " AND bo_state = -1");
//          exec_query("UPDATE phoenix_log.b2b_objects SET bo_state = 1 WHERE bo_obj_data = " . str_replace("|502", "|501", $row["bo_obj_data"]));
        } else {
          // das pending "Planned" ist doppelt
          exec_query("DELETE FROM phoenix_log.b2b_objects WHERE bo_id = " . $row["bo_id"] . " AND bo_state = -1");
        }
      }
    }
  }
endwhile;

//die();
writeLog_order_status("-----------------------------------------------------------------------------------");
writeLog_order_status("[" . date("Y-m-d H:i:s") . "] " . "*** find jb_ids for 'check_scan_events(...)' ***");
// Scan-Events vor dem Senden auf prozessuale Korrektheit überprüfen lassen
//$sql_query = "SELECT DISTINCT (job.jb_id) FROM phoenix_log.b2b_objects, job, tour WHERE bo_type = 300 AND bo_state IN (1,7) AND bo_createtime <= '" . $max_bo_createtime .
//  "' AND bo_obj_data LIKE CONCAT(BINARY tr_commission_no, '|%') AND tr_commission_no != '' AND job.jb_id = tour.jb_id AND tr_sort = 2";
$sql_query = "SELECT DISTINCT (bo_obj_data) FROM phoenix_log.b2b_objects WHERE bo_type = 300 AND bo_state IN (1,7) AND bo_createtime <= '" . $max_bo_createtime . "'";
$res = exec_query($sql_query, NULL, false);
$tr_commission_nos = "";
while ($row = mysql_fetch_array($res, MYSQL_ASSOC)):
  list ($sequence_no, $dummy) = explode("|", $row["bo_obj_data"]);
  if (trim($sequence_no) != "")
    $tr_commission_nos .= ",'" . $sequence_no . "'";
endwhile;
mysql_free_result($res);
$sql_query = "SELECT DISTINCT (jb_id) FROM tour WHERE tr_commission_no IN (" . substr($tr_commission_nos, 1) . ")";
$res = exec_query($sql_query, NULL, false);
writeLog_order_status("[" . date("Y-m-d H:i:s") . "] number of jb_ids to be checked before sending events: " . mysql_num_rows($res));
$jb_ids = "";
while ($row = mysql_fetch_array($res, MYSQL_ASSOC)):
  $jb_ids .= "," . $row["jb_id"];
endwhile;
mysql_free_result($res);

if ($jb_ids != "") {
  check_scan_events(substr($jb_ids, 1));
  // avoid sending of duplicate 'Order delivered' events (possible because events can come from both mobile device and manual editing)
  check_duplicate_deliveries(substr($jb_ids, 1));
}

/********************************************************************************/
writeLog_order_status("-----------------------------------------------------------------------------------");
writeLog_order_status("[" . date("Y-m-d H:i:s") . "] " . "*** send scan-events ***");
writeLog_order_status("[" . date("Y-m-d H:i:s") . "] sending scan-events for jb_ids = " . substr($jb_ids, 1));
// Status-Events senden
// Auch die bereits gesendeten (bo_state = 0) lesen, damit Dubletten pro Scan insgesamt ermittelt werden können
$sql_query = "SELECT bo_id, bo_ext_id1, bo_ext_id2, bo_obj_data, bo_createtime, bo_state FROM phoenix_log.b2b_objects, job, tour WHERE bo_type = 300 AND bo_state IN (0, 1, 7) AND bo_createtime <= '" . $max_bo_createtime .
  "' AND bo_obj_data LIKE CONCAT(BINARY tr_commission_no, '|%') AND tr_commission_no != '' AND job.jb_id = tour.jb_id AND tr_sort = 2 AND job.jb_id IN (" . substr($jb_ids, 1) . ") ORDER BY job.jb_id, bo_createtime";
$res = exec_query($sql_query, NULL, false);
$reqUploadArrLCD = array();
$reqUploadArrOS = array();
$bo_idsLCD = "";
$bo_idsOS = "";
$prev_event = "";
$prev_sequence_no = "";
while ($row = mysql_fetch_array($res, MYSQL_ASSOC)):
  list ($sequence_no, $event_no) = explode("|", $row["bo_obj_data"]);
  if ($prev_sequence_no != $sequence_no)
    $prev_event = "";
  // Kontextgebundene Scans werden vorerst noch als kontextfrei gescannt
  // daher die tr_id in $row["bo_ext_id1"] nachträglich eintragen
  if ($row["bo_ext_id1"] == 0 && in_array($event_no, array("301", "304", "351", "354"))) {
    $row["bo_ext_id1"] = get_first("SELECT tr_id FROM tour WHERE tr_commission_no = '" . $sequence_no . "'");
  }
  // tr_id nur holen, um nachzuschauen, ob der Auftrag über den order_request gekommen ist;
  // darf nicht den originalen Wert von $row["bo_ext_id1"] überschreiben, weil dieser darüber entscheidet, ob kontextfrei oder nicht;
  // bei kontextfreien Scans wird der der Standort nämlich vov der usr_id ($row["bo_ext_id2"]) geholt anstatt von der tr_id ($row["bo_ext_id1"])
  $tr_id_test = $row["bo_ext_id1"];
  if ($tr_id_test == 0) {
    $tr_id_test = get_first("SELECT tr_id FROM tour WHERE tr_commission_no = '" . $sequence_no . "'");
//    writeLog_order_status("[" . date("Y-m-d H:i:s") . "] " . "SELECT tr_id FROM tour WHERE tr_commission_no = '" . $sequence_no . "'");
  }
  // Nun schauen, ob der Auftrag auch über die Schnittstelle gekommen ist
  if ($tr_id_test != "" && get_first("SELECT gdc_content FROM genericdatacontainer, tour WHERE jb_id = gdc_obj_id AND gdc_gen_fieldname = 'acquisitiontime' AND tr_id = " . $tr_id_test) != "") {
//    writeLog_order_status("[" . date("Y-m-d H:i:s") . "] " . "SELECT gdc_content FROM genericdatacontainer, tour WHERE jb_id = gdc_obj_id AND gdc_gen_fieldname = 'acquisitiontime' AND tr_id = " . $tr_id_test);
    // Ist Schnittstellen Auftrag !!!!
    $EventTime = substr($row["bo_createtime"], 0, 10) . "T" . substr($row["bo_createtime"], -8);
    // Anhand der shipment-no bzw. orderno feststellen, ob Montage
    $row1 = get_first_row("SELECT job.jb_id, jb_service, hq_id, cr_sid FROM job, tour WHERE tr_commission_no = '" . $sequence_no . "' AND job.jb_id = tour.jb_id");  
//echo $sequence_no . ", " . $row1["jb_service"] . ", " . $event_no . "=>" . ((int) $row1["jb_service"] & (int) 2) . "\n";
//print_r($row1);
    if (($row1["jb_service"] & $serviceMont) != $serviceMont && $row1["jb_service"] != "" && in_array($event_no, array_keys($eventMsgArrayLCD)) && $prev_event != $event_no && $row["bo_state"] != 0) {
//echo "LCD\n";
      if ($row["bo_ext_id1"] == 0) {
//        // $tr_id nicht gegeben => Ortsangaben aus user_id ziehen
//        $cs_id_related = get_first("SELECT par_value FROM parameter AS par, employee as emp WHERE par_key = 'MASK_DISPOSITION_INIT_CS' AND emp.emp_id = par.emp_id AND usr_id = " . $row["bo_ext_id2"]);
//        if ($cs_id_related != "") {
//          $row1 = get_first_row("SELECT ad_country, ad_city FROM address AS ad, costcenteraddress AS cscad, customer AS cs WHERE ad.ad_id = cscad.ad_id AND cscad.csc_id = cs.csc_id AND adt_id = 4 AND cs.cs_id = " . $cs_id_related);
//        } else {
          // user keiner cs_id zugeordnet => Adresse aus tr_sort = 1 ziehen 
          // ... oder halt die Trottel wählen den falschen user, daher erst einmal hardcodiert nur aus dem auftrag ziehen..!
          $row1 = get_first_row("SELECT ad_country, ad_city, tr_signname FROM address AS ad, tour tr WHERE ad.ad_id = tr.ad_id AND tr_sort = 1 AND jb_id = " . $row1["jb_id"]);          
//       	}
        $SignedBy = "";
      } else {
        // $tr_id gegeben => Ortsangaben aus tr_id ziehen
        $row1 = get_first_row("SELECT ad_country, ad_city, tr_signname FROM address AS ad, tour tr WHERE ad.ad_id = tr.ad_id AND tr_id = " . $row["bo_ext_id1"]);
        $SignedBy = $row1["tr_signname"];
   	  }
      writeLog_order_status("[" . date("Y-m-d H:i:s") . "] " . "Barcode '$sequence_no': '$event_no' ('$EventTime') wird gesendet");
      $reqUploadArrLCD[] = array($eventMsgArrayLCD[$event_no], $EventTime, $event_no, $row1["ad_country"], $row1["ad_city"], $sequence_no, $SignedBy, "110");
      $bo_idsLCD .= ($bo_idsLCD == "" ? "" : ",") . $row["bo_id"];
    } elseif (($row1["jb_service"] & $serviceMont) == $serviceMont && in_array($event_no, array_keys($eventMsgArrayOS)) && $prev_event != $event_no && $row["bo_state"] != 0) {
//echo "OS\n";
      $sql_query = "SELECT DISTINCT trat_serialno FROM tourarticle WHERE jb_id = " . $row1["jb_id"];
      $res1 = exec_query($sql_query, NULL, false);
      while ($row2 = mysql_fetch_array($res1, MYSQL_ASSOC)) {
//        $reqUploadArrOS[] = array($eventMsgArrayOS[$event_no], $EventTime, $sequence_no, $row1["trat_serialno"]);
        $no_send_reason = "";
        if ($event_no == 301) {
          // "Completed" darf nur gesendet werden, wenn
          // ... Gesamtstatus des Auftrags "10" (OK) ist und ...
          $fin_state = get_first("SELECT gdc_content FROM genericdatacontainer WHERE gdc_obj_id = " . $row1["jb_id"] . " AND gdc_gen_fieldname = 'fin_state'");
          if ($fin_state != "10")
            $no_send_reason = "Statuscode '" . $fin_state . "'";
          // ... im Abnahmeportokoll "Fertiggestellt" angeklickt ist
          $bo_id_choice = get_first("SELECT bo_id FROM phoenix_log.b2b_objects WHERE bo_type = 501 AND bo_ext_id0 = " . $row1["jb_id"] . " AND LEFT(bo_obj_data, 10) = '9|choice|1'");
          if ($bo_id_choice == "") {
          	if ($no_send_reason != "")
          	  $no_send_reason .= ", ";
            $no_send_reason .= "'Fertiggestellt' nicht ausgewählt";
          }
          // 301 wird ab 20.10.2016 17:30 Uhr gar nicht mehr gesendet
          if ($no_send_reason == "") {
            $no_send_reason = "'Completed' is not to be sent after 2016-10-20";
          }
        }
        if ($no_send_reason != "") {
          writeLog_order_status("[" . date("Y-m-d H:i:s") . "] " . "Barcode '$sequence_no': '$event_no' ('$EventTime') für Artikelgruppe '" . $row2["trat_serialno"] . "' wird nicht gesendet ('" . $eventMsgArrayOS[$event_no] . "'): " . $no_send_reason);
          exec_query("UPDATE phoenix_log.b2b_objects SET bo_state = 5 WHERE bo_id = " . $row["bo_id"] . " AND bo_state != 0");
        } else {
          // Jedes Event muss einzeln gesendet werden!
          writeLog_order_status("[" . date("Y-m-d H:i:s") . "] " . "Barcode '$sequence_no': '$event_no' ('$EventTime') für Artikelgruppe '" . $row2["trat_serialno"] . "' wird gesendet ('" . $eventMsgArrayOS[$event_no] . "') " . $fin_state . " " . $bo_id_choice);
          $status = reqUploadOS(array(array($eventMsgArrayOS[$event_no], $EventTime, $sequence_no, $row2["trat_serialno"])));
          if (($status == "OK" || $status = "SO_MATRIX_NOT_SUPPORTED") && !$test_do_not_send && !$test_send) {
            writeLog_order_status("[" . date("Y-m-d H:i:s") . "] " . "-> Senden erfolgreich (Antwort: '$status')");
            exec_query("UPDATE phoenix_log.b2b_objects SET bo_state = 0 WHERE bo_id = " . $row["bo_id"] . " AND bo_state != 0");
          } elseif (!$test_do_not_send && !$test_send) {        	
            send_mail("Fehler beim Senden eines OS-Events", "\$status = " . $status);
          }
          // Wenn "Planned", dann auch gleich "LockedForChange" mit Status = -1 wegschreiben; das Event wird später mit Status = 1 aktiviert
//          if ($eventMsgArrayOS[$event_no] == "Planned" && !$test_do_not_send && !$test_send) {
//            // natürlich nur wenn nicht bereits eingetragen von vorheriger Aktion
//            $bo_id_test = get_first("SELECT bo_id FROM phoenix_log.b2b_objects WHERE bo_obj_data = '" . $sequence_no . "|502'");
//            if ($bo_id_test == "") {
//              exec_query("INSERT INTO phoenix_log.b2b_objects (bo_ver, bo_type, bo_state, bo_ext_id0, bo_ext_id1, bo_ext_id2, bo_obj_data, bo_createtime)" .
//                " VALUES (0, 300, -1, 0, 0, 0, '" . $sequence_no . "|502', '0000-00-00 00:00:00')");
//            }
//          }
        }
      }
      mysql_free_result($res1);
//      // wenn incomplete, dann den Auftrag auf unfertig setzen, damit er nicht abgerechnet wird
//      if ($event_no == 304)
//        exec_query("UPDATE phoenix.job SET jb_incomplete = 1 WHERE jb_id = " . $row1["jb_id"]);
//      $bo_idsOS .= ($bo_idsOS == "" ? "" : ",") . $row["bo_id"];
    } elseif ($prev_event == $event_no && $row["bo_state"] != 0) {
      // doppelte Events nicht senden (z.B. "Received at Hub"; könnte theoretisch richtig sein, weil zwei andere Scans dazwischen noch fehlen;
      // solange diese jedoch fehlen, soll "Received at Hub" nicht gesendet werden)
      // hier passiert ansonsten nichts mehr, status bleibt auf "zu senden"
      writeLog_order_status("[" . date("Y-m-d H:i:s") . "] " . "Barcode '$sequence_no': '$event_no' wurde nicht gesendet weil doppelt");
      exec_query("UPDATE phoenix_log.b2b_objects SET bo_state = 8 WHERE bo_id = " . $row["bo_id"]);
    } elseif (($row1["jb_service"] & $serviceMont) == $serviceMont && $event_no == 304 && $row["bo_state"] != 0) {
      // "Failed" ist als Status ok, wird aber nicht gesendet"
      writeLog_order_status("[" . date("Y-m-d H:i:s") . "] " . "Barcode '$sequence_no': '$event_no' wurde nicht gesendet weil es bei OS nicht zu senden ist (Auftrag " . $row1['jb_id'] . " wird auf die grüne Leiste verschoben)");
      exec_query("UPDATE phoenix_log.b2b_objects SET bo_state = 5 WHERE bo_id = " . $row["bo_id"]);
      // Ab 20.10.2016: Auftrag soll automatisch zurück auf die grüne Leiste, damit ein Update von IKEA durchkommt
      exec_query("UPDATE job SET jb_status = 9, cr_id = 0, cr_sid = '', cr_id_order = 0 WHERE jb_id = " . $row1["jb_id"]);
      exec_query("UPDATE vehicledisposition SET jb_id = 0 WHERE jb_id = " . $row1['jb_id']);
      exec_query("INSERT INTO phoenix_log.log (logo_id, hq_id, jb_id, usr_id, cr_sid, logo_description) VALUES (123, " . $row1['cr_sid'] . ", " . $row1['jb_id'] . ", 18086, '" . $row1['cr_sid'] . "', 'Reason: 'FAIL' (bo_id = " . $row["bo_id"] . ")'");
      writeLog_order_status("[" . date("Y-m-d H:i:s") . "] " . "Barcode '$sequence_no': ");
    } elseif ($row1["jb_id"] == "" && $row["bo_state"] != 0) {
      // Schnittstellenauftrag, aber Auftrag nicht vorhanden; bo_state = 4 setzen, damit er nicht immer wieder gefunden wird
      writeLog_order_status("[" . date("Y-m-d H:i:s") . "] " . "Barcode '$sequence_no': '$event_no' wurde nicht gesendet weil Autrag nicht vorhanden");
      exec_query("UPDATE phoenix_log.b2b_objects SET bo_state = 4 WHERE bo_id = " . $row["bo_id"]);
    } elseif ($row["bo_state"] == 0) {
      // bereits gesendetes Event soll nicht nochmal gesendet werden
      // diese sind hier nur vorhanden, um doppelte Events herauszufiltern
    } else {
      // Schnittstellenauftrag, aber code ungültig; bo_state = 2 setzen, damit er nicht immer wieder gefunden wird
      writeLog_order_status("[" . date("Y-m-d H:i:s") . "] " . "Barcode '$sequence_no': '$event_no' ist ungültig (Auftragstyp passt nicht)");
      exec_query("UPDATE phoenix_log.b2b_objects SET bo_state = 2 WHERE bo_id = " . $row["bo_id"]);
    }
  } else {
    // Kein Schnittstellenauftrag; bo_state = 3 setzen, damit er nicht immer wieder gefunden wird
    // Problem: Anfangs-Scan "Handed over to TSP" könnte auch vor Auftragseingang kommen
    // => Eine Woche lang behalten, dann verwerfen...
    $bc_ts = strtotime($row["bo_createtime"]);
    $expire_time = mktime(date("H", $bc_ts), date("i", $bc_ts), date("s", $bc_ts), date("m", $bc_ts), date("d", $bc_ts) + 7, date("Y", $bc_ts));
    if (time() > $expire_time) {
      writeLog_order_status("[" . date("Y-m-d H:i:s") . "] " . "Barcode '$sequence_no': '$event_no' ist ungültig (kein Schnittstellenauftrag)");
      exec_query("UPDATE phoenix_log.b2b_objects SET bo_state = 3 WHERE bo_id = " . $row["bo_id"]);
    }
  }
  $prev_sequence_no = $sequence_no;
  $prev_event = $event_no;
endwhile;
mysql_free_result($res);

if ($bo_idsLCD != "") {
  $status = reqUploadLCD($reqUploadArrLCD);
  if ($status == "Ok" && !$test_do_not_send) {
    writeLog_order_status("[" . date("Y-m-d H:i:s") . "] " . "-> Senden der LCD-Events erfolgreich (Antwort: '$status')");
    exec_query("UPDATE phoenix_log.b2b_objects SET bo_state = 0 WHERE bo_id IN (" . $bo_idsLCD . ")");
//    send_mail("Senden der LCD-Events erfolgreich", "\$status = " . $status);
  } else {
    if ($status == "AuthenticationFailed") {
      exec_query("UPDATE parameter SET par_value = '' WHERE par_key = 'ORDER_STATUS_AUTHENTICATIONTICKET'", NULL, false);
      exec_query("UPDATE parameter SET par_value = '' WHERE par_key = 'ORDER_STATUS_AUTHENTICATIONTIME'", NULL, false);
    }
    if (!$test_do_not_send)
  	  send_mail("Fehler beim Senden der LCD-Events", "\$status = " . $status);
  }
}

//// "ungültig" wieder auf "zu senden" setzen, denn beim nächsten Mal könnten sie ja passen...
//exec_query("UPDATE phoenix_log.b2b_objects SET bo_state = 1 WHERE bo_type = 300 AND bo_state = 6");

//if ($bo_idsOS != "") {
//  $status = reqUploadOS($reqUploadArrOS);
//  if ($status == "OK" && !$test_do_not_send && !$test_send) {
//    exec_query("UPDATE phoenix_log.b2b_objects SET bo_state = 0 WHERE bo_id IN (" . $bo_idsOS . ")");
//  }
//}

//echo $bo_ids . "\n";

function reqUploadLCD($events) {
  global $test_do_not_send, $req_host_LCD, $req_port_LCD, $req_service_LCD;

  $ShipmentEvents = "";
  foreach ($events as $event) {
  	$ShipmentEvents .= 
      "          <ns3:ShipmentEvent>\n" .
      "            <ns3:Description>" . $event[0] . "</ns3:Description>\n" .
      "            <ns3:EventTime>" . $event[1] . "</ns3:EventTime>\n" .
      "            <ns3:ExternalEventCode>" . $event[2] . "</ns3:ExternalEventCode>\n" .
      "            <ns3:ISOCountry>" . $event[3] . "</ns3:ISOCountry>\n" .
      "            <ns3:Location>" . $event[4] . "</ns3:Location>\n" .
      "            <ns3:SequenceNo>" . $event[5] . "</ns3:SequenceNo>\n" .
      ($event[6] != "" ?
      "            <ns3:SignedBy>" . $event[6] . "</ns3:SignedBy>\n" : "") .
      "            <ns3:TimeZone>" . $event[7] . "</ns3:TimeZone>\n" .
      "          </ns3:ShipmentEvent>\n";
  }
  
  if ($ShipmentEvents != "") {
    $AuthenticationTicket = reqAuthenticate();
    if ($AuthenticationTicket == "" && !$test_do_not_send) {
      return "Authentication failed";
    }
    $out =
      "<soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\"\n" .
      "xmlns:ns=\"http://www.centiro.com/Universe.Shipping.ServiceContracts/ShipmentProcess/7/1\"\n" .
      "xmlns:ns1=\"http://www.centiro.com/Universe.Common.ServiceContracts/7/1\"\n" .
      "xmlns:ns2=\"http://www.centiro.com/Universe.Shipping/ShipmentProcess/7/1\"\n" .
      "xmlns:ns3=\"http://www.centiro.com/Universe.Shipping.DataTypes/7/1\">\n" .
      "  <soapenv:Header/>\n" .
      "  <soapenv:Body>\n" .
      "    <ns:UploadMultipleShipmentEvents>\n" .
      "      <ns:AddMultipleEventsToShipmentRequestType>\n" .
      "        <ns1:AuthenticationTicket>" . $AuthenticationTicket . "</ns1:AuthenticationTicket>\n" .
      "        <ns1:MessageId>" . getMessageId() . "</ns1:MessageId>\n" .
      "        <ns2:CreateTrackingEventsWithoutShipment>false</ns2:CreateTrackingEventsWithoutShipment>\n" .
      "        <ns2:IdentifierKey>SequenceNo</ns2:IdentifierKey>\n" .
      "        <ns2:ShipmentEvents>\n" .
      $ShipmentEvents .
      "        </ns2:ShipmentEvents>\n" .
      "      </ns:AddMultipleEventsToShipmentRequestType>\n" .
      "    </ns:UploadMultipleShipmentEvents>\n" .
      "  </soapenv:Body>\n" .
      "</soapenv:Envelope>";
    
    $xmlArray = xmlRequest($out, $req_host_LCD, $req_port_LCD, $req_service_LCD, "http://www.centiro.com/Universe.Shipping.ServiceContracts/ShipmentProcess/7/1/ShipmentProcess/UploadMultipleShipmentEvents");
    return $xmlArray["s:Envelope"]["s:Body"]["UploadMultipleShipmentEventsResponse"]["UploadMultipleShipmentEventsResult"]["ProcessStatus"]["b:Status"];
  }
}

function reqAuthenticate() {
  global $test_do_not_send, $req_pass_LCD, $req_user_LCD, $req_host_LCD, $req_port_LCD, $req_service_LCD;

  $AuthenticationTicket = get_first("SELECT par_value FROM parameter WHERE par_key = 'ORDER_STATUS_AUTHENTICATIONTICKET'");
  $AuthenticationTime = get_first("SELECT par_value FROM parameter WHERE par_key = 'ORDER_STATUS_AUTHENTICATIONTIME'");

  if (!$test_do_not_send && ($AuthenticationTicket == "" || strtotime($AuthenticationTime) < mktime(date("H") - 4, date("i"), date("s"), date("m"), date("d"), date("Y")))) {
    $out =
      "<soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\"\n" .
      "xmlns:ns=\"http://www.centiro.com/Universe.Common.ServiceContracts/7/1\"\n" .
      "xmlns:ns1=\"http://www.centiro.com/Universe.Common.DataTypes/7/1\">\n" .
      "  <soapenv:Header/>\n" .
      "  <soapenv:Body>\n" .
      "    <ns:Authenticate>\n" .
      "      <ns:LoginRequest>\n" .
      "        <ns1:Password>" . $req_pass_LCD . "</ns1:Password>\n" .
      "        <ns1:UserName>" . $req_user_LCD . "</ns1:UserName>\n" .
      "      </ns:LoginRequest>\n" .
      "    </ns:Authenticate>\n" .
      "  </soapenv:Body>\n" .
      "</soapenv:Envelope>";
    $AuthenticationTicket = '';
    $AuthenticationTime = date("Y-m-d H:i:s");
    $xmlArray = xmlRequest($out, $req_host_LCD, $req_port_LCD, $req_service_LCD, "http://www.centiro.com/Universe.Common.ServiceContracts/7/1/CommonServices/Authenticate");
    if ($xmlArray["s:Envelope"]["s:Body"]["AuthenticateResponse"]["AuthenticateResult"]["a:ProcessStatus"]["a:Status"] == "Ok") {
      $AuthenticationTicket = $xmlArray["s:Envelope"]["s:Body"]["AuthenticateResponse"]["AuthenticateResult"]["a:AuthenticationTicket"];
      exec_query("UPDATE parameter SET par_value = '" . $AuthenticationTicket . "' WHERE par_key = 'ORDER_STATUS_AUTHENTICATIONTICKET'", NULL, false);
      exec_query("UPDATE parameter SET par_value = '" . $AuthenticationTime . "' WHERE par_key = 'ORDER_STATUS_AUTHENTICATIONTIME'", NULL, false);
    }
  }
  return $AuthenticationTicket;
}

function reqUploadOS($events) {
  global $req_user_OS, $req_host_OS, $req_port_OS, $req_service_OS, $Locality, $OrderNumberSource;

  $ShipmentEvents = "";
  foreach ($events as $event) {
    $gmdatetime = gmdate("Y-m-d H:i:s", strtotime($event[1]));

  	$ShipmentEvents .= 
      "    <ser:UpdateServiceStatusRequest>\n" .
      "      <dat:EventDateTime>\n" .
      "        <dat1:TimeZone>" . getTimezone($event[1]) . "</dat1:TimeZone>\n" .
      "        <dat1:UTCTime>" . substr($gmdatetime, 0, 10) . "T" . substr($gmdatetime, -8) . "</dat1:UTCTime>\n" .
      "      </dat:EventDateTime>\n" .
      "      <dat:OrderKey>\n" .
      "        <dat1:OrderNumber>" . $event[2] . "</dat1:OrderNumber>\n" .
      "        <dat1:OrderNumberSource>" . $OrderNumberSource . "</dat1:OrderNumberSource>\n" .
      "      </dat:OrderKey>\n" .
      "      <dat:SOServiceNo>" . $event[3] . "</dat:SOServiceNo>\n" .
      "      <dat:Status>" . $event[0] . "</dat:Status>\n" .
      "    </ser:UpdateServiceStatusRequest>\n";
  }

  if ($ShipmentEvents != "") {
    $out =
      "<soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\"\n" .
      "xmlns:ser=\"http://centiro.se/facade/serviceproviders/4/0/servicecontract\"\n" .
      "xmlns:dat=\"http://centiro.se/facade/serviceproviders/4/0/datacontract\"\n" .
      "xmlns:dat1=\"http://centiro.se/facade/otherservices/4/0/datacontract\">\n" .
      "  <soapenv:Header>\n" .
      "    <ser:UserId>" . $req_user_OS . "</ser:UserId>\n" .
      "    <ser:MessageId>" . getMessageId() . "</ser:MessageId>\n" .
      "    <ser:Locality>" . $Locality . "</ser:Locality>\n" .
      "  </soapenv:Header>\n" .
      "  <soapenv:Body>\n" .
      $ShipmentEvents .
      "  </soapenv:Body>\n" .
      "</soapenv:Envelope>";

    $xmlArray = xmlRequest($out, $req_host_OS, $req_port_OS, $req_service_OS, "http://centiro.se/facade/serviceproviders/4/0/servicecontract/IServiceProvidersFacade/UpdateServiceStatus");
    return $xmlArray["s:Envelope"]["s:Header"]["h:Result"]["ErrorCode"];
  }
}

function getMessageId() {
  global $test_do_not_send, $test_send;

  $MessageId = get_first("SELECT par_value FROM parameter WHERE par_key = 'ORDER_STATUS_MESSAGEID'") + 1;
  if (!$test_do_not_send && !$test_send)
    exec_query("UPDATE parameter SET par_value = '" . $MessageId . "' WHERE par_key = 'ORDER_STATUS_MESSAGEID'", NULL, false);
  return $MessageId;
}

function xmlRequest($xmlReq, $req_host, $req_port, $req_service, $soapAction)
{
  global $test_do_not_send;

  if (!$test_do_not_send) {
    $fp = fsockopen($req_host, $req_port, $errno, $errstr, 30);
  } else {
    $fp = 0;
  }
  if (!$fp && !$test_do_not_send) {
    echo "$errstr ($errno)<br />\n";
    return array();
  } else {
    while(!(strpos($xmlReq, "\n ") === false))
      $xmlReq = utf8_encode(str_replace("\n ", "\n", $xmlReq));
    if (!$test_do_not_send) {
      fputs ($fp, "POST " . $req_service . " HTTP/1.1\r\n");
      fputs ($fp, "Host: " . $req_host . "\r\n");
      fputs ($fp, "Content-type: text/xml; charset=utf-8\r\n");
      fputs ($fp, "Content-length: " . strlen($xmlReq) . "\r\n");
      fputs ($fp, "SOAPAction: \"" . $soapAction . "\"\r\n");
      fputs ($fp, "Connection: close\r\n\r\n");
      fputs ($fp, $xmlReq);
      $line = "";
      $line_header = "";
      while (substr($line, 0, 11) != "<s:Envelope" && !feof($fp)) {
        $line_header .= $line;
        $line = fgets($fp, 128);
      }
      $in = $line;
      while (!feof($fp)) {
        $in .= fgets($fp, 128);
      }
      fclose($fp);
    } else {
      $line_header = "TEST\n\n";
      $in = "";

      if ($soapAction == "http://www.centiro.com/Universe.Shipping.ServiceContracts/ShipmentProcess/7/1/ShipmentProcess/UploadMultipleShipmentEvents") {
        $in = 
          "<s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\">" . 
          "<s:Body>" .
          "<UploadMultipleShipmentEventsResponse xmlns=\"http://www.centiro.com/Universe.Shipping.ServiceContracts/ShipmentProcess/7/1\">" .
          "<UploadMultipleShipmentEventsResult xmlns:a=\"http://www.centiro.com/Universe.Shipping/ShipmentProcess/7/1\" xmlns:i=\"http://www.w3.org/2001/XMLSchema-instance\">" .
          "<ProcessStatus xmlns=\"http://www.centiro.com/Universe.Common.ServiceContracts/7/1\" xmlns:b=\"http://www.centiro.com/Universe.Common.DataTypes/7/1\">" .
          "<b:Message i:nil=\"true\"/>" .
          "<b:ProcessStepStatus>Ok</b:ProcessStepStatus>" .
          "<b:Roundtrip>0,125</b:Roundtrip>" .
          "<b:Status>Ok</b:Status>" .
          "</ProcessStatus>" .
          "<MessageId i:nil=\"true\" xmlns=\"http://www.centiro.com/Universe.Common.ServiceContracts/7/1\"/>" .
          "<a:IdentifierKey>OrderNo</a:IdentifierKey>" .
          "<a:ShipmentStatus xmlns:b=\"http://www.centiro.com/Universe.Shipping.DataTypes/7/1\">" .
          "<b:ExternalId/>" .
          "<b:GlobalId/>" .
          "<b:OrderLineGlobalIdList xmlns:c=\"http://schemas.microsoft.com/2003/10/Serialization/Arrays\"/>" .
          "<b:OrderNo/>" .
          "<b:SequenceNo/>" .
          "<b:StatusCode>StoredOk</b:StatusCode>" .
          "<b:StatusMessage/>" .
          "</a:ShipmentStatus>" .
          "</UploadMultipleShipmentEventsResult>" .
          "</UploadMultipleShipmentEventsResponse>" .
          "</s:Body>" .
          "</s:Envelope>";
      } elseif ($soapAction == "http://centiro.se/facade/serviceproviders/4/0/servicecontract/IServiceProvidersFacade/UpdateServiceStatus") {
        $in = 
          "<s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\">" .
          "<s:Header>" .
          "<h:Result xmlns:h=\"http://centiro.se/facade/serviceproviders/4/0/servicecontract\" xmlns:i=\"http://www.w3.org/2001/XMLSchema-instance\">" .
          "<ErrorCode xmlns=\"http://centiro.se/facade/otherservices/4/0/datacontract\">OK</ErrorCode>" .
          "<ErrorMessage i:nil=\"true\" xmlns=\"http://centiro.se/facade/otherservices/4/0/datacontract\"/>" .
          "</h:Result>" .
          "</s:Header>" .
          "<s:Body>" .
          "<UpdateServiceStatusResponse i:nil=\"true\" xmlns=\"http://centiro.se/facade/serviceproviders/4/0/servicecontract\" xmlns:a=\"http://centiro.se/facade/serviceproviders/4/0/datacontract\" xmlns:i=\"http://www.w3.org/2001/XMLSchema-instance\"/>" .
          "</s:Body>" .
          "</s:Envelope>";
      }
  	}

    writeLog_order_status_xml("[" . date("Y-m-d H:i:s") . "]" . "\n" . $xmlReq);
    writeLog_order_status_xml("-----------------------------------------------------------------------------------");
    writeLog_order_status_xml("[" . date("Y-m-d H:i:s") . "]" . "\n" . $line_header . str_replace("><", ">\n<", $in));
//    writeLog_order_status_xml("___________________________________________________________________________________");
    return xml2array($in);
  }
}

function getTimezone($localdate)
{
  return date('I', strtotime(substr($localdate, 0, 4) . "-" . substr($localdate, 4, 2) . "-" . substr($localdate, 6, 2) . " " .
    substr($localdate, 8, 2) . ":" . substr($localdate, 10, 2) . ":" . substr($localdate, 12, 2))) == 1 ? "2" : "1";
}

function check_xml_chars($xml_str) {
  $xml_str = str_replace("&", "&amp;", $xml_str);
//  $xml_str = str_replace("'", "&apos;", $xml_str);
  $xml_str = str_replace("<", "&lt;", $xml_str);
  $xml_str = str_replace(">", "&gt;", $xml_str);
  $xml_str = str_replace('"', "&quot;", $xml_str);
  return $xml_str;
}

function writeLog_order_status_xml($log_text) {
  global $test_do_not_send, $test_send;

  if ($test_do_not_send || $test_send)
    $fileHandle = @fopen("../log/order_status_test_" . date("Ym") . ".log", 'a');
  else
    $fileHandle = @fopen("../log/order_status_" . date("Ym") . ".log", 'a');
  @fwrite($fileHandle, $log_text .  "\n");
  @fclose($fileHandle);
  return;
}

function send_mail($subj, $mail_text) {
  include_once("../include/email/htmlMimeMail.php");
  $mailObj = new htmlMimeMail();
  $mailObj->setFrom("admin@assecutor.de");
  $mailObj->setSubject($subj);
  $mailObj->setText($mail_text);
  $mailResult = $mailObj->send(array("ca@assecutor.de"), 'smtp');
}
?>