Merge branch 'fronkdev' into 'master'

ADB Rimo Import Broker

See merge request fronk/thetool!1009
This commit is contained in:
Frank Schubert
2025-02-11 14:02:54 +00:00
7 changed files with 455 additions and 31 deletions

View File

@@ -90,6 +90,21 @@
<hr class="mt-3 mb-3" />
<h4>Berechtigungen</h4>
<div class="form-group row">
<label class="col-lg-2 col-form-label" for="sender_reply_to">Berechtigte Firmen</label>
<div class="col-lg-10">
<select class="form-control select2" name="address_id[]" id="adb_hausnummer_id" multiple="multiple">
<?php foreach(AddressModel::search(["addresstype" => TT_NETWORK_ROLES_WITH_OWNER]) as $address): ?>
<option value="<?=$address->id?>" <?=(array_key_exists($address->id, $project->addresses)) ? "selected='selected'" : ""?>><?=$address->getCompanyOrName()?><?=($address->customer_number) ? " (".$address->customer_number.")" : ""?></option>
<?php endforeach; ?>
</select>
</div>
</div>
<hr class="mt-3 mb-3" />
<div class="form-group row">
<label class="col-lg-2 col-form-label" for="note">Interne Notiz</label>
<div class="col-lg-10">
@@ -120,12 +135,6 @@
closeOnSelect: false
});
$('#adb_hausnummer_id').on('select2:close', function(e) {
if(!$('#adb_hausnummer_id').val()) {
$('#new-address-toggle').show();
}
});
</script>
<?php include(realpath(dirname(__FILE__) . "/../../$mfLayoutPackage") . "/footer.php"); ?>

View File

@@ -4,6 +4,7 @@ class ConstructionConsentProject extends mfBaseModel {
private $consents;
private $networks;
private $adb_networks;
private $addresses;
protected function beforeUpdate($data) {
if(!array_key_exists("edit_by", $data)) {
@@ -18,11 +19,21 @@ class ConstructionConsentProject extends mfBaseModel {
public function getProperty($name) {
if($this->$name == null) {
if($name == "addresses") {
$addresses = ConstructionConsentProjectAddress::search(["constructionconsentproject_id" => $this->id]);
if(!count($addresses)) {
return [];
}
foreach($addresses as $address) {
$this->addresses[$address->address->id] = $address;
}
return $this->addresses;
}
if($name == "consents") {
$consents = ConstructionConsent::search(["constructionconsentproject_id" => $this->id]);
if(!$consents) {
return [];
}
$this->consents = $consents;
return $this->consents;

View File

@@ -133,30 +133,21 @@ class ConstructionConsentProjectController extends mfBaseController {
return $this->addAction();
}
$netzgebiete = [];
if(!$project->save()) {
$this->layout()->setFlash("Fehler beim Speichern", "error");
return $this->addAction();
}
// save networks
$netzgebiete = [];
foreach($r->adb_netzgebiet_id as $netzgebiet_id) {
$netzgebiet = new ADBNetzgebiet($netzgebiet_id);
if(!$netzgebiet->id) continue;
$netzgebiete[] = $netzgebiet_id;
}
/*
if($mode == "add") {
$project = ConstructionConsentProject::create($data);
} else {
$project->update($data);
}*/
//save networks
foreach($netzgebiete as $netzgebiet_id) {
$ccn = ConstructionConsentNetwork::getFirst(["constructionconsentproject_id" => $project->id, "adb_netzgebiet_id" => $netzgebiet_id]);
if(!$ccn) {
@@ -167,17 +158,40 @@ class ConstructionConsentProjectController extends mfBaseController {
$ccn->save();
}
}
foreach(ConstructionConsentNetwork::search(["constructionconsentproject_id" => $project->id]) as $ccn) {
if(!in_array($ccn->adb_netzgebiet_id, $netzgebiete)) {
$ccn->delete();
}
}
//var_dump($r->get());exit;
// save addresses
$addresses = [];
foreach($r->address_id as $address_id) {
$address = new Address($address_id);
if(!$address->id) continue;
$addresses[] = $address_id;
}
foreach($addresses as $address_id) {
$cca = ConstructionConsentProjectAddress::getFirst(["constructionconsentproject_id" => $project->id, "address_id" => $address_id]);
if(!$cca) {
$cca = ConstructionConsentProjectAddress::create([
"constructionconsentproject_id" => $project->id,
"address_id" => $address_id
]);
$cca->save();
}
}
foreach(ConstructionConsentProjectAddress::search(["constructionconsentproject_id" => $project->id]) as $cca) {
if(!in_array($cca->address_id, $addresses)) {
$cca->delete();
}
}
$this->layout()->setFlash("Zustimmungserklärungsprojekt erfolgreich gespeichert", "success");
$this->redirect("ConstructionConsentProject");
}

View File

@@ -0,0 +1,36 @@
<?php
declare(strict_types=1);
use Phinx\Migration\AbstractMigration;
final class CreateConstructionConsentProjectAddress extends AbstractMigration
{
public function up(): void
{
if($this->getEnvironment() == "thetool") {
$table = $this->table("ConstructionConsentProjectAddress");
$table->addColumn("constructionconsentproject_id", "integer", ["null" => false]);
$table->addColumn("address_id", "integer", ["null" => false]);
$table->addColumn("create_by", "integer", ["null" => false]);
$table->addColumn("edit_by", "integer", ["null" => false]);
$table->addColumn("create", "integer", ["null" => false]);
$table->addColumn("edit", "integer", ["null" => false]);
$table->create();
}
if($this->getEnvironment() == "addressdb") {
}
}
public function down(): void
{
if($this->getEnvironment() == "thetool") {
$this->table("ConstructionConsentProjectAddress")->drop()->save();
}
if($this->getEnvironment() == "addressdb") {
}
}
}

View File

@@ -71,13 +71,13 @@ class AddressHelper
if (array_key_exists(3, $m)) {
$addresszusatz = trim($m[3]);
}
} elseif (preg_match('/^(\D+)\s+(\d+[a-z0-9\/&#._-]*)(?:\s+((?:gesch(?:ae|ä)ft|werkstatt|schmiede|[^ ]*garage|betrieb und wohnungen|stg|paketlogistik|cafe|pavillon|pfarrheim|[^ ]*haus|[^ ]*geb(?:ae|ä)ude|[^ ]*halle|[^ ]*schule|Öhlmühle)(?:\s+[a-z0-9]+)?))?/i', $strasse_hausnummer, $m)) {
} elseif (preg_match('/^(.+)\s+(\d+[a-z0-9\/&#._-]*)(.+)?/i', $strasse_hausnummer, $m)) {
$strasse_name = trim($m[1]);
$hausnummer_name = trim($m[2]);
if (array_key_exists(3, $m)) {
$addresszusatz = trim($m[3]);
}
} elseif (preg_match('/^(.+)\s+(\d+[a-z0-9\/&#._-]*)(.+)?/i', $strasse_hausnummer, $m)) {
} elseif (preg_match('/^(\D+)\s+(\d+[a-z0-9\/&#._-]*)(?:\s+((?:gesch(?:ae|ä)ft|werkstatt|schmiede|[^ ]*garage|betrieb und wohnungen|stg|paketlogistik|cafe|pavillon|pfarrheim|[^ ]*haus|[^ ]*geb(?:ae|ä)ude|[^ ]*halle|[^ ]*schule|Öhlmühle)(?:\s+[a-z0-9]+)?))?/i', $strasse_hausnummer, $m)) {
$strasse_name = trim($m[1]);
$hausnummer_name = trim($m[2]);
if (array_key_exists(3, $m)) {

View File

@@ -0,0 +1,353 @@
#!/usr/bin/php
<?php
if (PHP_SAPI !== 'cli') {
die("This program can only be run on the command line.\n");
}
/*
fclose(STDIN);
fclose(STDOUT);
fclose(STDERR);
$STDIN = fopen('/dev/null', 'r');
$STDOUT = fopen('/dev/null', 'w');
$STDERR = fopen('/dev/null', 'w');
*/
require("../../config/config.php");
define('mfUI',"cli");
define('FRONKDB_SQLDEBUG',false);
define("MFBASE_BYPASS_LOGIN", true);
error_reporting(E_ALL & ~(E_NOTICE | E_STRICT | E_DEPRECATED));
if(defined('MFLOCALE_TIME')) {
setlocale(LC_TIME, MFLOCALE_TIME);
}
if(defined('MFLOCALE_MONETARY')) {
setlocale(LC_MONETARY, MFLOCALE_MONETARY);
}
if(defined('MFLOCALE_NUMERIC')) {
setlocale(LC_NUMERIC, MFLOCALE_NUMERIC);
}
require_once(LIBDIR."/mvcfronk/mfRouter/mfRouter.php");
require_once(LIBDIR."/mvcfronk/mfBase/mfBaseModel.php");
require_once(LIBDIR."/mvcfronk/mfBase/mfBaseController.php");
$me = new User(1);
define("INTERNAL_USER_ID", $me->id);
define("INTERNAL_USER_USERNAME", $me->username);
$request = array();
// Put commandline arguments into $request
if(count($argv)) {
$args=$argv;
array_shift($args); // shift scriptname off of args array
foreach($args as $i => $arg) {
if(preg_match('/^--(.+)/',$arg,$m)) {
if(isset($args[$i+1]) && !preg_match('/^-/',$args[$i+1])) {
$request[$m[1]] = $args[$i+1];
} else {
$request[$m[1]] = true;
}
} elseif(preg_match('/^-([a-zA-Z])(.+)/', $arg, $m)) {
$request[$m[1]] = $m[2];
} elseif(preg_match('/^-([^-])/', $arg, $m)) {
if(isset($args[$i+1]) && !preg_match('/^-/',$args[$i+1])) {
$request[$m[1]] = $args[$i + 1];
} else {
$request[$m[1]] = true;
}
}
}
}
require_once(LIBDIR."/mvcfronk/mfRouter/mfRouter.php");
$log = mfLoghandler::singleton();
cli_set_process_title("thetool-adb-rimo-import-broker");
pcntl_async_signals(true);
pcntl_signal(SIGTERM, 'signalHandler');
$forkcount = 0;
$childpids = [];
if(pidislocked()) {
echo "ADB Rimo Import Broker läuft bereits (pidfile vorhanden)\n";
exit;
}
if(!lockpid()) {
$log->error(__FILE__.": Error creating lock file!");
die("Error creating lock file!\n");
}
$max_processes = 10;
$all_pids = [];
$jobs = [];
$clusters = loadClusters();
foreach($clusters as $cluster) {
$proc = [
"cluster" => $cluster["cluster"],
"cluster_id" => $cluster["cluster"]->id,
"apiOwner" => $cluster["apiOwner"],
"apiUrl" => $cluster["apiUrl"],
"apiToken" => $cluster["apiKey"],
//"pid" => false,
"processtitle" => "ADB Import ".$cluster["cluster"]->name,
"start" => false,
];
$jobs[$cluster["cluster"]->id] = $proc;
}
$all_procs = $jobs;
$fork_delay = 0;
while(1) {
//echo "while\n";
//sleep(5);
$processes = [];
$idle_proc_count = 0;
foreach($jobs as $proc) {
if($proc["start"]) {
continue;
}
$idle_proc_count++;
$processes[] = [
"cluster_id" => $proc["cluster_id"],
"pid" => false,
"processtitle" => "ADB Import ".$proc["cluster_id"],
];
}
//echo "[parent] $idle_proc_count processes to be started\n";
// if no running processes remain -> exit
if(!$idle_proc_count && !count($all_pids)) {
echo "No more idle or running processes. Exiting.\n";
break;
}
//var_dump($processes);
foreach($processes as $key => $proc) {
if($proc["pid"]) {
// process is running already, nothing to do here
echo "[parent] ".$proc["cluster_id"]." pid exists (".$proc["pid"].")\n";
continue;
}
$cluster_id = $proc["cluster_id"];
if(isset($childpids[$cluster_id])) {
echo "[parent] job for ".$proc["cluster_id"]." exists\n";
//echo "cannot start new $taskname job, because another one is running already\n";
continue;
}
// delay for 10 minutes before forking new process
if($fork_delay) {
echo "[parent] fork delay: $fork_delay\n";
$fork_delay--;
sleep(1);
break;
}
if(count($all_pids) >= $max_processes) {
echo "[parent] max processes reached. Currently ".count($all_pids)." running processes.\n";
$fork_delay = 10;
sleep(1);
break;
}
echo "[parent] forking for $cluster_id\n";
$pid = pcntl_fork();
$fork_delay = 10;
if($pid === -1) {
$log->debug("error forking");
exit;
} elseif($pid > 0) {
// in parent
$forkcount++;
$childpids[$cluster_id] = $pid;
$proc["pid"] = $pid;
$all_pids[$pid] = $proc;
$jobs[$key]["start"] = date("d.m.Y H:i:s");
} else {
// in child
$mypid = getmypid();
echo "[$mypid] Starting import for ".$proc["cluster_id"]."\n";
try {
cli_set_process_title($proc["processtitle"]);
$script_name = __DIR__ . "/rimo-import.php";
if(!file_exists($script_name)) {
echo "[$mypid] Runner $script_name not found\n";
}
echo "[$mypid] executing $script_name ".$proc["cluster_id"]."\n";
pcntl_exec($script_name, [$proc["cluster_id"]]);
//only reachable on error
echo "[$mypid] Error exec()'ing ".$proc["processtitle"]."!\n";
} catch(\Exception $e) {
// exit child process on error
echo "$mypid caught exception: " . $e->getMessage();
echo $e->getTraceAsString()."\n";
exit;
}
exit; // make sure child exits when done
}
//sleep(5);
}
if(count($all_pids)) {
$status = false;
$return_pid = pcntl_wait($status, WNOHANG);
if($return_pid) {
echo "child $return_pid returned\n";
$pid_proc = $all_pids[$return_pid];
$pid_task = $pid_proc["cluster_id"];
$childpids[$pid_task] = null;
unset($all_pids[$return_pid]);
unset($jobs[$pid_task]);
}
}
/*echo "No more PIDs, exiting loop\n";
break;*/
//sleep(5);
}
unlockpid();
function loadClusters() {
$clusters = [];
$netowners = ["estmk", "rml"];
$apiEdition = "prod";
foreach ($netowners as $apiOwner) {
$apiData = TT_RIMO_API_CREDS[$apiOwner][$apiEdition];
$apiUrl = $apiData["url"];
$apiToken = $apiData["key"];
if (!$apiUrl || !$apiToken) {
echo "Api Daten für $apiOwner unvollständig\n";
}
$epGetClusters = $apiUrl . RIMO_API_JSON_EP_GET_CLUSTERS;
$baseParams = ['apiKey' => $apiToken];
$ctxOptsGet = [
'http' => [
'method' => 'GET',
'header' => 'accept: application/json'
]
];
/*
* Get RIMO Sales Clusters
*/
$params = $baseParams;
$qs = http_build_query($params);
$req_url = $epGetClusters . "?" . $qs;
$req_ctx = stream_context_create($ctxOptsGet);
//echo $req_url."\n";
$responseText = file_get_contents($req_url, false, $req_ctx);
if ($responseText === false) {
echo "($apiOwner) Error fetching clusters\n";
exit;
}
$clustersResponse = json_decode($responseText);
//var_dump($clustersResponse);
//exit;
if (!is_object($clustersResponse) || !property_exists($clustersResponse, "item") || !is_array($clustersResponse->item) || !count($clustersResponse->item)) {
die("($apiOwner) Invalid GetClusters Response\n");
}
foreach ($clustersResponse->item as $cluster) {
$cluster_data = ["apiOwner" => $apiOwner, "apiKey" => $apiToken, "apiUrl" => $apiUrl, "cluster" => $cluster];
$clusters[] = $cluster_data;
}
}
return $clusters;
}
function signalHandler($sig) {
//global $continue;
global $childpids;
global $invoice_job_lock;
//$continue = false;
//echo "in signal handler\n";
if(count($childpids)) {
foreach($childpids as $taskname => $pids) {
foreach($pids as $childpid) {
posix_kill($childpid, SIGTERM);
}
}
}
unlockpid();
exit;
}
function client_log($pid, $text, $severity = "notice") {
global $log;
global $is_daemon;
if($is_daemon) {
echo "[".date('Y-m-d H:i:s')."] [$pid] $text\n";
}
$log->$severity($text);
return true;
}
function pidislocked() {
$pidfile = __DIR__."/.adb-rimo-import-broker.lock";
if(file_exists($pidfile)) {
return true;
}
return false;
}
function lockpid() {
$pid = getmypid();
$pidfile = __DIR__."/.adb-rimo-import-broker.lock";
file_put_contents($pidfile, $pid);
if(file_exists($pidfile)) {
return true;
}
return false;
}
function unlockpid() {
$pidfile = __DIR__."/.adb-rimo-import-broker.lock";
if(file_exists($pidfile)) {
unlink($pidfile);
return true;
}
return false;
}

View File

@@ -45,11 +45,12 @@ if ($argc > 1) {
}
//$netowners = ["estmk", "rml"];
//$netowners = ["estmk", "rml"];
$netowners = ["sbidi"];
$netowners = ["estmk", "rml"];
//$netowners = ["sbidi"];
//$netowners = ["rml"];
$apiEdition = "prod";
$startdate = date("Y-m-d");
$starttime = date("Y-m-d.H-i");
$clusters = [];
@@ -700,8 +701,8 @@ foreach ($clusters as $cluster_data) {
//echo "Updating Workorder $rimo_workorder_id ($workorder_home_id)\n";
if ($workorder_status != $wo->rimo_status) {
\mfValuecache::singleton()->set("adbhausnummer-save-nesting-level-".$hausnummer->id, 0);
\mfValuecache::singleton()->set("adbwohneinheit-save-nesting-level-".$unit->id, 0);
//\mfValuecache::singleton()->set("adbhausnummer-save-nesting-level-".$hausnummer->id, 0);
\mfValuecache::singleton()->set("adbwohneinheit-save-nesting-level-".$wo_home->id, 0);
$wo->rimo_status = $workorder_status ?: "";
$wo->save();
}
@@ -723,8 +724,8 @@ foreach ($clusters as $cluster_data) {
//if(($option_wo_ignore_status == "Documented" && $workorder_status == "Documented") || $workorder_status == "Cancelled") continue; // dont import status > Executed
\mfValuecache::singleton()->set("adbhausnummer-save-nesting-level-".$hausnummer->id, 0);
\mfValuecache::singleton()->set("adbwohneinheit-save-nesting-level-".$unit->id, 0);
//\mfValuecache::singleton()->set("adbhausnummer-save-nesting-level-".$hausnummer->id, 0);
\mfValuecache::singleton()->set("adbwohneinheit-save-nesting-level-".$wo_home->id, 0);
//echo "Creating Workorder $rimo_workorder_id ($workorder_home_id)\n";
$wo = \RimoWorkorderModel::create([
"adb_wohneinheit_id" => $wo_home->id,
@@ -745,7 +746,7 @@ foreach ($clusters as $cluster_data) {
if ($addressErrors) {
$netzname = preg_replace('/[^a-z0-9.-]/i', "_", $adb_netzgebiet->name);
$out_folder = dirname(__FILE__) . "/output/$starttime";
$out_folder = dirname(__FILE__) . "/output/$startdate";
if (!file_exists($out_folder)) {
mkdir($out_folder);
}