From f42e4720006b9dc31c4f1c623df865a2a4019c39 Mon Sep 17 00:00:00 2001 From: Luca Haid Date: Wed, 5 Mar 2025 16:32:20 +0000 Subject: [PATCH] Preorder campaign rework --- application/ADBHausnummer/ADBHausnummer.php | 4 +- application/Preorder/PreorderModel.php | 69 ++- .../PreordercampaignController.php | 484 ++++++++---------- ...305160000_add_preorder_db_improvements.php | 20 + lib/FronkDB/FronkDB.php | 9 +- .../Preordercampaign/Preordercampaign.css | 36 ++ .../Preordercampaign/Preordercampaign.js | 103 ++++ .../vue/tt-components/css/tt-table.css | 2 +- .../vue/tt-components/tt-table-crud.js | 3 +- public/plugins/vue/tt-components/tt-table.js | 26 +- 10 files changed, 465 insertions(+), 291 deletions(-) create mode 100644 db/migrations/20250305160000_add_preorder_db_improvements.php create mode 100644 public/js/pages/Preordercampaign/Preordercampaign.css create mode 100644 public/js/pages/Preordercampaign/Preordercampaign.js diff --git a/application/ADBHausnummer/ADBHausnummer.php b/application/ADBHausnummer/ADBHausnummer.php index e0e9f4ce5..df17b46b0 100644 --- a/application/ADBHausnummer/ADBHausnummer.php +++ b/application/ADBHausnummer/ADBHausnummer.php @@ -75,13 +75,13 @@ class ADBHausnummer extends mfBaseModel { } public function getBuildingType() { - $rimo_type = strtolower($this->rimo_type); + $rimo_type = $this->rimo_type === NULL ? '' : strtolower($this->rimo_type); if(array_key_exists($this->rimo_type, TT_ADB_GDA_TYPES)) { return TT_ADB_GDA_TYPES[$this->rimo_type]; } - $gdaeigenschaft = strtolower($this->gdaeigenschaft); + $gdaeigenschaft = $this->gdaeigenschaft === NULL ? '' : strtolower($this->gdaeigenschaft); if(array_key_exists($gdaeigenschaft, TT_ADB_GDA_TYPES)) { return TT_ADB_GDA_TYPES[$gdaeigenschaft]; } diff --git a/application/Preorder/PreorderModel.php b/application/Preorder/PreorderModel.php index ac9362696..1fee012ed 100644 --- a/application/Preorder/PreorderModel.php +++ b/application/Preorder/PreorderModel.php @@ -927,11 +927,72 @@ class PreorderModel return 0; } - public static function countHistoryStatus($filter = [], $status_code = null) - { - if ($status_code === null) { - die("Please select a status code"); + public static function countActivePreorder($preorderCampaignId = null) { + $db = FronkDB::singleton(); + + $where = "1=1 "; + if ($preorderCampaignId) { + $where .= " AND p.preordercampaign_id = $preorderCampaignId"; + } + + $sql = "SELECT + COALESCE(SUM(CASE + WHEN LOWER(vh.gdaeigenschaft) IN ('multi dwelling', 'mehrparteienhaus', 'gebaeude mit 2 oder mehr wohnungen', 'gebäude mit 2 oder mehr wohnungen', 'wohngebaeude fuer gemeinschaften', 'wohngebäude für gemeinschaften', 'hotels und aehnliche gebaeude', 'hotels und ähnliche gebäude', 'wohngebäude mit 2 und mehr wohnungen') + OR LOWER(vh.rimo_type) IN ('multi dwelling', 'mehrparteienhaus', 'gebaeude mit 2 oder mehr wohnungen', 'gebäude mit 2 oder mehr wohnungen', 'wohngebaeude fuer gemeinschaften', 'wohngebäude für gemeinschaften', 'hotels und aehnliche gebaeude', 'hotels und ähnliche gebäude', 'wohngebäude mit 2 und mehr wohnungen') + THEN COALESCE(p.connection_count, 1) + ELSE 0 + END), 0) AS md_count, + COALESCE(SUM(COALESCE(p.connection_count, 1)), 0) AS total_count + +FROM + `".FRONKDB_DBNAME."`.Preorder p +LEFT JOIN `".ADDRESSDB_DBNAME."`.view_hausnummer vh ON p.adb_hausnummer_id = vh.hausnummer_id +LEFT JOIN `".FRONKDB_DBNAME."`.Preorderstatus tt_preorderstatus ON p.status_id = tt_preorderstatus.id +WHERE p.deleted = 0 AND tt_preorderstatus.code < 899"; + + $queryStart = microtime(true); + $res = $db->query($sql . $where); + mfLoghandler::singleton()->debug("[Query took: ".(microtime(true) - $queryStart)." seconds] " . $sql); + if ($db->num_rows($res)) { + $data = $db->fetch_object($res); + return ['md_count' => $data->md_count, 'sd_count' => $data->total_count - $data->md_count, 'total_count' => $data->total_count]; + } + return ['md_count' => 0, 'sd_count' => 0, 'total_count' => 0]; + } + + public static function countTotalUnits($preorderCampaignId = null) { + $db = FronkDB::singleton(); + + $where = "1=1 "; + if ($preorderCampaignId) { + $where .= " AND pc.id = $preorderCampaignId"; + } + + $sql = "SELECT + pc.id AS campaign_id, + COALESCE(SUM(n.unit_count), 0) AS total_unit_count, + COALESCE(SUM(n.unit_count_sd), 0) AS total_unit_count_sd, + COALESCE(SUM(n.unit_count_md), 0) AS total_unit_count_md +FROM Preordercampaign pc +LEFT JOIN `".FRONKDB_DBNAME."`.PreordercampaignSalescluster pcs ON pc.id = pcs.preordercampaign_id +LEFT JOIN `".ADDRESSDB_DBNAME."`.Netzgebiet n ON pcs.salescluster_id = n.id +WHERE $where +GROUP BY pc.id"; + + $queryStart = microtime(true); + $res = $db->query($sql); + mfLoghandler::singleton()->debug("[Query took: ".(microtime(true) - $queryStart)." seconds] " . $sql); + if ($db->num_rows($res)) { + $data = $db->fetch_object($res); + return ['total_unit_count' => $data->total_unit_count, 'total_unit_count_sd' => $data->total_unit_count_sd, 'total_unit_count_md' => $data->total_unit_count_md]; } + return ['total_unit_count' => 0, 'total_unit_count_sd' => 0, 'total_unit_count_md' => 0]; + } + + public static function countHistoryStatus($filter = [], $status_code = null) { + if ($status_code === null) { + die("Please select a status code"); + } if (!is_array($filter)) return false; diff --git a/application/Preordercampaign/PreordercampaignController.php b/application/Preordercampaign/PreordercampaignController.php index fbc8494f0..01508ff1e 100644 --- a/application/Preordercampaign/PreordercampaignController.php +++ b/application/Preordercampaign/PreordercampaignController.php @@ -1,120 +1,74 @@ needlogin=true; - $me = new User(); - $me->loadMe(); - $this->me = $me; - $this->layout()->set("me",$me); - - if(!$me->is(["Admin", "netowner", "salespartner"]) && !$me->can("Preorder")) { - $this->redirect("Dashboard"); + + protected function init() { + $this->needlogin = true; + $me = new User(); + $me->loadMe(); + $this->me = $me; + $this->layout()->set("me", $this->me); + + if (!$this->me->is(["Admin", "netowner", "salespartner"]) && !$this->me->can("Preorder")) $this->redirect("Dashboard"); + if ($this->me->is("Preorderlogistics")) $this->redirect("Preorderlogistics"); + if ($this->me->is("Preorderfront")) $this->redirect("Preorder"); } - } - - protected function indexAction() { - if($this->me->is("Preorderlogistics")) { - $this->redirect("Preorderlogistics"); + + protected function indexAction() { + $isAdmin = $this->me->is("Admin"); + + $filter = []; + if ($isAdmin) $my_networks = NetworkModel::getAll(); + else $filter['network_id'] = array_unique(array_merge( + array_column($this->me->myNetworks(["netowner", "salespartner"]), 'id'), + json_decode($this->me->getFlag("preorder_networks")->value() ?: '[]') + )); + + + + $campaigns = array_map(function ($c) { + return [ + 'id' => $c->id, + 'network_id' => $c->network_id, + 'network_name' => $c->network->name, + 'network_owner_name' => $c->network->owner->getCompanyOrName(), + 'name' => $c->name, + 'area' => $c->area, + 'from' => $c->from, + 'to' => $c->to, + 'rimo_workoders' => $c->workorder_count, + 'active_preorder_count' => PreorderModel::countActivePreorder($c->id), + 'count_total_units' => PreorderModel::countTotalUnits($c->id), + ]; + }, PreordercampaignModel::search($filter)); + + $net_owners = array_map(function ($n) { + return [ + 'value' => $n->getCompanyOrName(), + 'text' => $n->getCompanyOrName() + ]; + }, $isAdmin ? $this->getNetworkOwners(array_column($my_networks, 'id')) : []); + + Helper::renderVue($this, "Preordercampaign", "Vorbestellkampagnen", + [ + "NETWORK_OWNER_OPTIONS" => $net_owners, + "SHOW_MISC_BUTTONS" => in_array($this->me->address_id, [1, 4807], true), + "IS_ADMIN" => $isAdmin, + "CAMPAIGNS" => $campaigns, + "VIEW_URL" => self::getUrl("Preorder", "Index"), + "PREORDER_DISCOUNT_IMPORT_URL" => self::getUrl("Preorderdiscount", "import"), + "PREORDER_STATUS_UPDATE_IMPORT_URL" => self::getUrl("Preorder", "statusupdateimport"), + "ADD_PREORDER_URL" => self::getUrl("Preorder", "add"), + "DOWNLOAD_ADDON_SERVICES_URL" => self::getUrl("Preordercampaign", "downloadAddonServices"), + "PREORDER_NOTIFICATION_URL" => self::getUrl("Preordernotification", "Index"), + "ADD_URL" => self::getUrl("Preordercampaign", "add"), + "EDIT_URL" => self::getUrl("Preordercampaign", "edit"), + "ADMIN_URL" => self::getUrl("Preordercampaign", "admin"), + ]); } - - - $this->layout()->setTemplate("Preordercampaign/Index"); - - $this->layout->set("filter", $this->request->filter); - - $filter = []; - if($this->request->filter) { - $filter = $this->getPreparedFilter($this->request->filter); - } - - // pagination defaults - $pagination = []; - $pagination['start'] = 0; - $pagination['count'] = 20; - $pagination['maxItems'] = 0; - - if(is_numeric($this->request->s)) { - $pagination['start'] = intval($this->request->s); - } - - $my_networks = []; - //var_dump($filter);exit; - if($this->me->is("Admin")) { - if(!is_array($filter['network_id']) && $filter['network_id']) { - $my_networks[] = new Network($filter['network_id']); - } else { - $my_networks = NetworkModel::getAll(); - } - $this->layout()->set("mynetworks", NetworkModel::getAll()); - - $netowners = $this->getNetworkOwners($my_network_ids); - $this->layout()->set("netowners", $netowners); - - } else { - $use_filter_network = false; - $my_networks = $this->me->myNetworks(["netowner", "salespartner"]); - - // check users allowed networks - $user_network_ids = $this->me->getFlag("preorder_networks")->value(); - if($user_network_ids) { - $user_network_ids = json_decode($user_network_ids); - } - - if(is_array($user_network_ids) && count($user_network_ids)) { - - if(!$my_networks) { - foreach($user_network_ids as $mnid) { - $my_networks[] = new Network($mnid); - } - } else { - //var_dump($user_network_ids, $my_networks);exit; - $new_my_networks = []; - foreach($my_networks as $network) { - if(in_array($network->id, $user_network_ids)) { - $new_my_networks[$network->id] = $network; - } - } - $my_networks = $new_my_networks; - } - } - - //var_dump($my_networks);exit; - foreach($my_networks as $mn) { - if($mn->id == $filter['network_id']) { - $use_filter_network = true; - break; - } - } - - $this->layout()->set("mynetworks", $my_networks); - - if($use_filter_network) { - $my_networks = []; - $my_networks[] = new Network($filter['network_id']); - } - - $my_network_ids = []; - foreach($my_networks as $network) { - $my_network_ids[] = $network->id; - } - $filter['network_id'] = $my_network_ids; - } - - - $pagination['maxItems'] = PreordercampaignModel::count($filter); - $campaigns = PreordercampaignModel::search($filter, $pagination); - - $this->layout()->set("pagination", $pagination); - $this->layout()->set("campaigns", $campaigns); - - - } - private function getPreparedFilter($filter) { $new_filter = []; - + if(array_key_exists("netowner", $filter) && $filter['netowner']) { if($this->me->is("Admin")) { $owner_id = $filter['netowner']; @@ -126,7 +80,7 @@ class PreordercampaignController extends mfBaseController { unset($filter['netowner']); } } - + if(array_key_exists("name", $filter) && $filter['name']) { $new_filter['name%'] = "%".$filter['name']; unset($filter['name']); @@ -135,17 +89,17 @@ class PreordercampaignController extends mfBaseController { $new_filter['area%'] = "%".$filter['area']; unset($filter['area']); } - + foreach($filter as $name => $value) { $new_filter[$name] = $value; } - + return $new_filter; } - + private function getNetworkOwners() { $owners = []; - + $sql = "SELECT Address.* FROM Preordercampaign LEFT JOIN Network ON (Preordercampaign.network_id = Network.id) LEFT JOIN Address ON (Network.owner_id = Address.id) @@ -153,65 +107,65 @@ class PreordercampaignController extends mfBaseController { ORDER BY Address.company, Address.lastname, Address.firstname "; $res = $this->db()->query($sql); - if($this->db()->num_rows($reso)) { + if($this->db()->num_rows($res)) { while($data = $this->db()->fetch_object($res)) { $owners[] = new Address($data->id); } } - + return $owners; } - + protected function addAction() { if(!$this->me->is("Admin")) { $this->redirect("Preordercampaign"); } - + $this->layout()->setTemplate("Preordercampaign/Form"); - + if($this->me->isAdmin()) { $this->layout()->set("networks", NetworkModel::getAll()); } else { $this->layout()->set("networks", $this->me->my_networks); } - + $this->layout()->set("types", BuildingtypeModel::getAll()); $this->layout()->set("statuses", BuildingstatusModel::getAll()); - + $this->layout()->set("networksections", NetworksectionModel::getAll()); - + $this->layout()->set("adb_netzgebiete", ADBNetzgebietModel::getAll()); - - + + } - + protected function editAction() { if(!$this->me->is("Admin")) { $this->redirect("Preordercampaign"); } - + $id = $this->request->id; if(!is_numeric($id) || !$id) { $this->layout()->setFlash("Vorbestellkampagne nicht gefunden", "error"); $this->redirect("Preordercampaign"); } - + $campaign = new Preordercampaign($id); if(!$campaign->id) { $this->layout()->setFlash("Vorbestellkampagne nicht gefunden", "error"); $this->redirect("Preordercampaign"); } - + $this->layout()->set("campaign", $campaign); - + return $this->addAction(); } - + protected function saveAction() { if(!$this->me->is("Admin")) { $this->redirect("Preordercampaign"); } - + $r = $this->request; //var_dump($r->get());exit; $id = $r->id; @@ -226,7 +180,7 @@ class PreordercampaignController extends mfBaseController { $id = false; $mode = "add"; } - + $data = []; $data['network_id'] = $r->network_id; $data['name'] = trim($r->name); @@ -238,15 +192,15 @@ class PreordercampaignController extends mfBaseController { $data["cifcableurl"] = trim($r->cifcableurl); $data["from_email_name"] = trim($r->from_email_name); $data["from_email"] = trim($r->from_email); - + if($r->from) { $data['from'] = self::dateToTimestamp($r->from); } - + if($r->to) { $data['to'] = self::dateToTimestamp($r->to); } - + if($r->fulfillment == "thirdparty") { $data['fulfillment'] = "thirdparty"; } elseif($r->fulfillment == "rimo") { @@ -254,7 +208,7 @@ class PreordercampaignController extends mfBaseController { } else { $data['fulfillment'] = "thetool"; } - + if($r->oaid_origin == "ofaa") { $data['oaid_origin'] = "ofaa"; } elseif($r->oaid_origin == "thetool") { @@ -262,7 +216,7 @@ class PreordercampaignController extends mfBaseController { } else { $data['oaid_origin'] = "other"; } - + if($r->product_type == "setup_only") { $data['product_type'] = "setup_only"; } elseif($r->product_type == "no_setup") { @@ -270,7 +224,7 @@ class PreordercampaignController extends mfBaseController { } else { $data['product_type'] = "all"; } - + if(is_array($r->required_fields) && count($r->required_fields)) { $rfields = []; foreach(['contact_type'] as $afield) { @@ -282,25 +236,25 @@ class PreordercampaignController extends mfBaseController { } else { $data['required_preorder_fields'] = null; } - + if($r->district_is_city == 1) { $data['district_is_city'] = 1; } else { $data['district_is_city'] = 0; } - + if($r->hausnummer_add_zusatz == 1) { $data['hausnummer_add_zusatz'] = 1; } else { $data['hausnummer_add_zusatz'] = 0; } - + if($r->exist_is_error == 1) { $data['exist_is_error'] = 1; } else { $data['exist_is_error'] = 0; } - + //var_dump($r->banned_rimo_fcp);exit; if($r->banned_rimo_fcp && is_array($r->banned_rimo_fcp) && count($r->banned_rimo_fcp)) { $banned_fcp_json = json_encode($r->banned_rimo_fcp); @@ -312,27 +266,27 @@ class PreordercampaignController extends mfBaseController { } else { $data["banned_rimo_fcp"] = null; } - + $data['edit_by'] = $this->me->id; - + if($mode == "add") { $data['create_by'] = $this->me->id; $campaign = PreordercampaignModel::create($data); } else { $campaign->update($data); } - + $new_id = $campaign->save(); if(!$new_id) { $this->layout()->setFlash("Fehler beim Speichern", "error"); $this->layout()->set("campaign", $campaign); return $this->add(); } - + if(is_array($r->types) && count($r->types)) { $campaign->addTypes($r->types); } - + //var_dump($r->adb_netzgebiet_ids);exit; foreach(PreordercampaignSalesclusterModel::search(['preordercampaign_id' => $campaign->id]) as $pcg) { $pcg->delete(); @@ -342,12 +296,12 @@ class PreordercampaignController extends mfBaseController { foreach($r->adb_netzgebiet_ids as $netzgebiet_id) { $pcg = PreordercampaignSalesclusterModel::getFirst(['preordercampaign_id' => $campaign->id, 'salescluster_id' => $netzgebiet_id]); if($pcg) continue; - + $pcg = PreordercampaignSalesclusterModel::create(['preordercampaign_id' => $campaign->id, 'salescluster_id' => $netzgebiet_id]); $pcg->save(); } } - + foreach(PreordercampaignApiuserModel::search(['preordercampaign_id' => $campaign->id]) as $pca) { $pca->delete(); } @@ -355,12 +309,12 @@ class PreordercampaignController extends mfBaseController { foreach($r->apiusers as $user_id) { $pca = PreordercampaignApiuserModel::getFirst(['preordercampaign_id' => $campaign->id, 'worker_id' => $user_id]); if($pca) continue; - + $pca = PreordercampaignApiuserModel::create(['preordercampaign_id' => $campaign->id, 'worker_id' => $user_id]); $pca->save(); } } - + foreach(PreordercampaignOriginhostnameModel::search(['preordercampaign_id' => $campaign->id]) as $origin) { $origin->delete(); } @@ -449,7 +403,7 @@ class PreordercampaignController extends mfBaseController { $op->delete(); // automatically deletes isps too } } - + if(is_array($r->passive_operators)) { if(!count($r->passive_operators)) { @@ -548,7 +502,7 @@ class PreordercampaignController extends mfBaseController { } $this->redirect("Preordercampaign", "Edit", ['id' => $new_id]); - + } protected function billingAction() { @@ -583,28 +537,28 @@ class PreordercampaignController extends mfBaseController { $this->layout()->setFlash("Vorbestellkampagne nicht gefunden", "error"); $this->redirect("Preordercampaign"); } - + $campaign = new Preordercampaign($id); if(!$campaign->id) { $this->layout()->setFlash("Vorbestellkampagne nicht gefunden", "error"); $this->redirect("Preordercampaign"); } - + $this->layout()->set("campaign", $campaign); $preorders = PreorderModel::searchActive(["preordercampaign_id" => $id, "add-where" => "AND JSON_LENGTH(addon_services) > 1"]); - + if(!count($preorders)) { $this->layout->setFlash("Keine Vorbestellungen mit bestellten Dienstleistungen gefunden."); $this->redirect("Preordercampaign"); } - + $csv = []; foreach($preorders as $preorder) { $sjson = json_decode($preorder->addon_services); if(!$sjson) { continue; } - + // address data and stuff $general = [ "ucode" => $preorder->ucode, @@ -629,7 +583,7 @@ class PreordercampaignController extends mfBaseController { "phone" => $preorder->phone, "email" => $preorder->email, ]; - + if($preorder->adb_wohneinheit_id) { $general["block"] = $preorder->adb_wohneinheit->block; $general["stiege"] = $preorder->adb_wohneinheit->stiege; @@ -637,10 +591,10 @@ class PreordercampaignController extends mfBaseController { $general["tuer"] = $preorder->adb_wohneinheit->tuer; $general["zusatz"] = $preorder->adb_wohneinheit->zusatz; } - + foreach($sjson as $service) { if(!$service->ordered) continue; - + $s = $general; $s["service"] = $service->service; $data = []; @@ -654,7 +608,7 @@ class PreordercampaignController extends mfBaseController { $this->layout()->setTemplate("Preordercampaign/services.csv"); $this->layout()->set("csv", $csv); } - + } protected function apiAction() { @@ -727,55 +681,55 @@ class PreordercampaignController extends mfBaseController { protected function adminAction() { $this->layout()->setTemplate("Preordercampaign/Admin"); - + $id = $this->request->id; if(!is_numeric($id) || !$id) { $this->layout()->setFlash("Vorbestellkampagne nicht gefunden", "error"); $this->redirect("Preordercampaign"); } - + $campaign = new Preordercampaign($id); if(!$campaign->id) { $this->layout()->setFlash("Vorbestellkampagne nicht gefunden", "error"); $this->redirect("Preordercampaign"); } - + $this->layout()->set("campaign", $campaign); } - + protected function updateUnitOAIDsAction() { $this->layout()->setTemplate("Preordercampaign/Admin"); - + $id = $this->request->id; if(!is_numeric($id) || !$id) { $this->layout()->setFlash("Vorbestellkampagne nicht gefunden", "error"); $this->redirect("Preordercampaign"); } - + $campaign = new Preordercampaign($id); if(!$campaign->id) { $this->layout()->setFlash("Vorbestellkampagne nicht gefunden", "error"); $this->redirect("Preordercampaign"); } - + $updated_units = 0; - + foreach(PreorderModel::searchActive(["preordercampaign_id" => $id, 'deleted' => 0]) as $preorder) { if(!$preorder->adb_wohneinheit_id) continue; if(!$preorder->oaid) continue; $unit = $preorder->adb_wohneinheit; - + if(!$preorder->oaid || $unit->oaid != $preorder->oaid) { $preorder->save(); $updated_units++; } } - + $this->layout()->setFlash("$updated_units Wohneinheiten aktualisiert", "success"); $this->redirect("Preordercampaign", "Admin", ["id" => $id]); - + } - + protected function assignOpenAccessIdsToPreordersAction() { $this->layout()->setTemplate("Preordercampaign/Admin"); @@ -784,7 +738,7 @@ class PreordercampaignController extends mfBaseController { $this->layout()->setFlash("Vorbestellkampagne nicht gefunden", "error"); $this->redirect("Preordercampaign"); } - + $campaign = new Preordercampaign($id); if(!$campaign->id) { $this->layout()->setFlash("Vorbestellkampagne nicht gefunden", "error"); @@ -795,20 +749,20 @@ class PreordercampaignController extends mfBaseController { $this->layout()->setFlash("Kampagne unterstützt keine OAIDs", "warning"); $this->redirect("Preordercampaign", "Admin", ["id" => $id]); } - + $assigned_oaids = 0; $multiple_unit = 0; - + foreach(PreorderModel::searchActive(["preordercampaign_id" => $id, "oaid" => null, "connection_count" => 1]) as $preorder) { if($preorder->type == "interest") { continue; } - + if($preorder->oaid) { $this->log->warning(__METHOD__.": OAID is set already"); continue; } - + if(!$preorder->adb_wohneinheit_id) { //echo "Keine Wohneinheit in Preorder (".$preorder->id.") ".$preorder->ucode." ".$preorder->oaid."\n"; continue; @@ -818,55 +772,55 @@ class PreordercampaignController extends mfBaseController { $this->log->error(__METHOD__.": Wohneinheit nicht gefunden (Preorder ".$preorder->id." ".$preorder->ucode." ".$preorder->oaid.")"); continue; } - + /*if(!$wohneinheit->extref) { continue; }*/ - + $wohneinheit_count = PreorderModel::countActive(["adb_wohneinheit_id" => $wohneinheit->id]); if($wohneinheit_count > 1) { $this->log->error(__METHOD__.": Wohneinheit ".$wohneinheit->id." is assigned to multiple preorders!"); $multiple_unit++; continue; } - + $netowner = new Address($campaign->network->owner_id); //var_dump($netowner);exit; // get random active OAID from network owner pool - + $oaid_attributes = [ "owner_id" => $netowner->id, "origin" => $campaign->oaid_origin ]; - + if($this->request->origin_id) { $oaid_attributes["origin_id"] = $this->request->origin_id; } - + $preorder->setOrCreateOaid($oaid_attributes); - + /*if($wohneinheit->oaid != $oaid->oaid) { $wohneinheit->oaid = $oaid->oaid; $wohneinheit->save(); }*/ - + $assigned_oaids++; - + } - + $this->layout()->setFlash("$assigned_oaids OAIDs wurden Vorbestellungen zugewiesen", "success"); $this->redirect("Preordercampaign", "Admin", ["id" => $id]); } - + protected function createRimoWorkordersAction() { $this->layout()->setTemplate("Preordercampaign/Admin"); - + $id = $this->request->id; if(!is_numeric($id) || !$id) { $this->layout()->setFlash("Vorbestellkampagne nicht gefunden", "error"); $this->redirect("Preordercampaign"); } - + $campaign = new Preordercampaign($id); if(!$campaign->id) { $this->layout()->setFlash("Vorbestellkampagne nicht gefunden", "error"); @@ -877,21 +831,21 @@ class PreordercampaignController extends mfBaseController { $this->layout()->setFlash("Kampagne unterstützt keine OAIDs, somit können keine Workorders erstellt werden", "warning"); $this->redirect("Preordercampaign", "Admin", ["id" => $id]); } - + $missing_units = []; $missing_extrefs = []; $workorders_created = 0; $workorders_failed = 0; - + foreach(PreorderModel::searchActive(["preordercampaign_id" => $id, "rimo_workorder" => false, "connection_count" => 1]) as $preorder) { if($preorder->workorder_export_date) { $this->log->warning(__METHOD__.": workorder_export_date not null"); } - + if($preorder->type == "interest" || $preorder->type == "legacytransfer") { continue; } - + if(!$preorder->adb_wohneinheit_id) { //echo "Keine Wohneinheit in Preorder (".$preorder->id.") ".$preorder->ucode." ".$preorder->oaid."\n"; $missing_units[] = $preorder; @@ -902,19 +856,19 @@ class PreordercampaignController extends mfBaseController { $this->log->error(__METHOD__.": Wohneinheit nicht gefunden (Preorder ".$preorder->id." ".$preorder->ucode." ".$preorder->oaid.")"); continue; } - + if(!$wohneinheit->extref) { $missing_extrefs[] = $preorder; continue; } - + if(!$preorder->oaid) { $preorder->setOrCreateOaid(); if(!$preorder->oaid) { continue; } } - + $oaid = OpenAccessIdModel::getFirstOaid($wohneinheit->oaid); if(!$oaid) { $this->log->warning(__METHOD__.": OAID '".$wohneinheit->oaid."' not found"); @@ -955,50 +909,50 @@ class PreordercampaignController extends mfBaseController { $wo->save(); $workorders_created++; } - + $errors = []; $warnings = []; - + if(count($missing_units)) { $warnings[] = count($missing_units)." Vobestellungen ohne Wohneinheit"; } if(count($missing_extrefs)) { $warnings[] = count($missing_extrefs)." Wohneinheiten ohne extref (SDIHome_)"; } - - + + if($workorders_failed) { $errors[] = "$workorders_failed Workorders konnten nicht erstellt werden."; } - - + + if(count($errors)) { $this->layout()->setFlash(implode("
\n", $errors), "error"); } if(count($warnings)) { $this->layout()->setFlash(implode("
\n", $warnings), "warning"); } - + if($workorders_created) { $this->layout()->setFlash("$workorders_created Workorders erfolgreich erstellt", "success"); } else { $this->layout()->setFlash("Es konnten keine Workorders erstellt werden", "info"); } - + $this->redirect("Preordercampaign", "Admin", ["id" => $id]); - + } - + protected function exportOaidsToRimoAction() { - + $this->layout()->setTemplate("Preordercampaign/Admin"); - + $id = $this->request->id; if(!is_numeric($id) || !$id) { $this->layout()->setFlash("Vorbestellkampagne nicht gefunden", "error"); $this->redirect("Preordercampaign"); } - + $campaign = new Preordercampaign($id); if(!$campaign->id) { $this->layout()->setFlash("Vorbestellkampagne nicht gefunden", "error"); @@ -1009,19 +963,19 @@ class PreordercampaignController extends mfBaseController { $this->layout()->setFlash("Kampagne unterstützt keine OAIDs", "warning"); $this->redirect("Preordercampaign", "Admin", ["id" => $id]); } - + $oaid_assigned = 0; $missing_units = 0; $missing_extrefs = 0; $missing_oaid = 0; - + foreach(PreorderModel::searchActive(["preordercampaign_id" => $id, "connection_count" => 1]) as $preorder) { if($preorder->type == "interest") { $this->log->debug(__METHOD__.": Ignoring Preorder ".$preorder->id.": is interest"); continue; } - + if(!$preorder->adb_wohneinheit_id) { //echo "Keine Wohneinheit in Preorder (".$preorder->id.") ".$preorder->ucode." ".$preorder->oaid."\n"; //$this->log->debug(__METHOD__.": Ignoring Preorder ".$preorder->id.": missing unit"); @@ -1033,17 +987,17 @@ class PreordercampaignController extends mfBaseController { $this->log->error(__METHOD__.": Wohneinheit nicht gefunden (Preorder ".$preorder->id." ".$preorder->ucode." ".$preorder->oaid.")"); continue; } - + if(!$wohneinheit->extref) { $missing_extrefs++; continue; } - + if(!$preorder->oaid) { $missing_oaid++; continue; } - + // TODO; OpenaccessID::exportToRimoFtu $oaid = OpenAccessIdModel::getFirstOaid($wohneinheit->oaid); if(!$oaid) { @@ -1055,21 +1009,21 @@ class PreordercampaignController extends mfBaseController { $oaid_assigned++; } } - + $this->layout()->setFlash("$oaid_assigned OAIDs erfolgreich erstellt und/oder FTUs zugeordnet.
$missing_units missing units
$missing_extrefs missing extref
$missing_oaid missing oaid"); $this->redirect("Preordercampaign", "Admin", ["id" => $id]); - + } - + protected function updateOaidFromUnitAction() { $this->layout()->setTemplate("Preordercampaign/Admin"); - + $id = $this->request->id; if(!is_numeric($id) || !$id) { $this->layout()->setFlash("Vorbestellkampagne nicht gefunden", "error"); $this->redirect("Preordercampaign"); } - + $campaign = new Preordercampaign($id); if(!$campaign->id) { $this->layout()->setFlash("Vorbestellkampagne nicht gefunden", "error"); @@ -1080,15 +1034,15 @@ class PreordercampaignController extends mfBaseController { $this->layout()->setFlash("Kampagne unterstützt keine OAIDs", "warning"); $this->redirect("Preordercampaign", "Admin", ["id" => $id]); } - + $oaid_updated = 0; - + foreach(PreorderModel::searchActive(["preordercampaign_id" => $id, "connection_count" => 1]) as $preorder) { if($preorder->type == "interest") { //$this->log->debug(__METHOD__.": Ignoring Preorder ".$preorder->id.": is interest"); continue; } - + if(!$preorder->adb_wohneinheit_id) { //echo "Keine Wohneinheit in Preorder (".$preorder->id.") ".$preorder->ucode." ".$preorder->oaid."\n"; $this->log->debug(__METHOD__.": Ignoring Preorder ".$preorder->id.": missing unit"); @@ -1100,34 +1054,34 @@ class PreordercampaignController extends mfBaseController { $this->log->error(__METHOD__.": Wohneinheit nicht gefunden (Preorder ".$preorder->id." ".$preorder->ucode." ".$preorder->oaid.")"); continue; } - + if(!$wohneinheit->extref) { $missing_extrefs++; continue; } - + if(!$preorder->oaid) { continue; } - + $oaid = OpenAccessIdModel::getFirstOaid($wohneinheit->oaid); if(!$oaid) { $this->log->warning("Cannot export OAID to rimo because not found: ".$wohneinheit->oaid." (Preorder ".$preorder->id." ".$preorder->ucode." ".$preorder->oaid.")"); continue; } //var_dump($oaid);exit; - - - + + + if($oaid->adb_wohneinheit_id != $wohneinheit->id) { //$rimo = new OpenAccessId_Helper_Rimo($oaid->oaid); - + $unit_ftu_data = $wohneinheit->ftu_data; //var_dump($unit_ftu_data); if(!$unit_ftu_data) { continue; } - + $oaid_ftu = $oaid->getExportData("rimo"); //var_dump($oaid_ftu); if($oaid_ftu->ftu_id) { @@ -1149,34 +1103,34 @@ class PreordercampaignController extends mfBaseController { //var_dump($oaid);exit; $oaid->save(); - - - + + + } } - + $this->layout()->setFlash("Done.", "success"); $this->redirect("Preordercampaign", "Admin", ["id" => $id]); - + } - + protected function splitMultipleConnectionsAction() { $id = $this->request->id; if(!is_numeric($id) || !$id) { $this->layout()->setFlash("Vorbestellkampagne nicht gefunden", "error"); $this->redirect("Preordercampaign"); } - + $campaign = new Preordercampaign($id); if(!$campaign->id) { $this->layout()->setFlash("Vorbestellkampagne nicht gefunden", "error"); $this->redirect("Preordercampaign"); } - + $orders_split = 0; $orders_new = 0; $missing_units = 0; - + foreach(PreorderModel::searchActive(["preordercampaign_id" => $campaign->id, "connection_count" => 2]) as $preorder) { // check if we have enough units with extref $wohneinheiten = ADBWohneinheitModel::search(["hausnummer_id" => $preorder->adb_hausnummer_id]); @@ -1199,9 +1153,9 @@ class PreordercampaignController extends mfBaseController { //echo $preorder->id." balh\n"; } } - + if(count($additional_units)) $available_units = array_merge($available_units, $additional_units); - + if($preorder->connection_count > count($available_units)) { $missing_units++; continue; @@ -1229,31 +1183,31 @@ class PreordercampaignController extends mfBaseController { $preorder->delete_reason = "connection_split"; $preorder->save(); } - + if($missing_units) { $this->layout()->setFlash("$missing_units Bestellungen konnten nicht geteilt werden, da nicht genug Wohneinheiten verfügbar sind.", "warning"); } - + $this->layout()->setFlash("$orders_split Bestellungen in $orders_new Bestellungen aufgeteilt.", "success"); $this->redirect("Preordercampaign", "Admin", ["id" => $id]); } - + protected function addUnitsAction() { $id = $this->request->id; if(!is_numeric($id) || !$id) { $this->layout()->setFlash("Vorbestellkampagne nicht gefunden", "error"); $this->redirect("Preordercampaign"); } - + $campaign = new Preordercampaign($id); if(!$campaign->id) { $this->layout()->setFlash("Vorbestellkampagne nicht gefunden", "error"); $this->redirect("Preordercampaign"); } - + $units_added = 0; $missing_units = 0; - + foreach(PreorderModel::searchActive(['preordercampaign_id' => $campaign->id, 'adb_wohneinheit_id' => null, 'connection_count' => 1, "connection_type" => "single-dwelling"]) as $preorder) { if($preorder->adb_wohneinheit_id) { continue; @@ -1262,7 +1216,7 @@ class PreordercampaignController extends mfBaseController { echo "missing hausnummer Preorder ".$preorder->id."\n"; continue; } - + $wohneinheiten = ADBWohneinheitModel::search(['hausnummer_id' => $preorder->adb_hausnummer_id]); if(!count($wohneinheiten)) { $missing_units++; @@ -1275,52 +1229,52 @@ class PreordercampaignController extends mfBaseController { $unit = $wohneinheiten[0]; $preorder->adb_wohneinheit_id = $unit->id; $preorder->save(); - + $units_added++; continue; } - - + + if($unit_count > 1) { // legacy comment: assume its single-dwelling with erroneously high door count // current comment: Just use any unit $unit_candidates = []; - + foreach($wohneinheiten as $unit) { if(!$unit->tuer) continue; if($unit->tuer > 1) { $unit_candidates[$unit->tuer] = $unit; } } - + // no candidates with door number -> use any if(!count($unit_candidates)) { foreach($wohneinheiten as $unit) { $unit_candidates[] = $unit; } } - + if(count($unit_candidates)) { ksort($unit_candidates, SORT_NUMERIC); $new_unit = array_shift($unit_candidates); $preorder->adb_wohneinheit_id = $new_unit->id; $preorder->save(); - + $units_added++; continue; } } - + $i++; } - + if($missing_units) { $this->layout()->setFlash("Für $missing_units Bestellungen wurde keine Wohneinheit gefunden.", "warning"); } - + $this->layout()->setFlash("$units_added Wohneinheiten eingetragen.", "success"); $this->redirect("Preordercampaign", "Admin", ["id" => $id]); - + } - + } \ No newline at end of file diff --git a/db/migrations/20250305160000_add_preorder_db_improvements.php b/db/migrations/20250305160000_add_preorder_db_improvements.php new file mode 100644 index 000000000..425413f3b --- /dev/null +++ b/db/migrations/20250305160000_add_preorder_db_improvements.php @@ -0,0 +1,20 @@ +getEnvironment() == "thetool") { + $this->table("PreordercampaignSalescluster")->addIndex(["preordercampaign_id","salescluster_id"])->save(); + $this->table("RimoWorkorder")->addIndex(["adb_wohneinheit_id"])->save(); + } + } + + public function down(): void { + if ($this->getEnvironment() == "thetool") { + $this->table("PreordercampaignSalescluster")->removeIndex(["preordercampaign_id","salescluster_id"])->save(); + $this->table("RimoWorkorder")->removeIndex(["adb_wohneinheit_id"])->save(); + } + } +} diff --git a/lib/FronkDB/FronkDB.php b/lib/FronkDB/FronkDB.php index 7bce93c99..98dc060fd 100644 --- a/lib/FronkDB/FronkDB.php +++ b/lib/FronkDB/FronkDB.php @@ -1,17 +1,16 @@ host = $host; diff --git a/public/js/pages/Preordercampaign/Preordercampaign.css b/public/js/pages/Preordercampaign/Preordercampaign.css new file mode 100644 index 000000000..3899b6cc7 --- /dev/null +++ b/public/js/pages/Preordercampaign/Preordercampaign.css @@ -0,0 +1,36 @@ +.campaign-grid { + display: grid; + grid-template-columns: auto 1fr; + gap: 0.75rem; + align-items: center; +} + +.campaign-icon, +.campaign-icon > i{ + font-size: 24px !important; + padding: 0.25rem; +} + +.campaign-icon:hover { + opacity: 0.8; +} + +.progress-grid { + display: grid; + grid-template-columns: auto repeat(3, max-content); + gap: 0.4rem; +} + +.progress-row > *:nth-child(n+2) { + text-align: right; + font-variant-numeric: tabular-nums; +} + +.preorder-campaign-table-actions > a > i { + font-size: 17px !important; +} + +.preorder-campaign-table-actions { + display: flex; + justify-content: space-between; +} \ No newline at end of file diff --git a/public/js/pages/Preordercampaign/Preordercampaign.js b/public/js/pages/Preordercampaign/Preordercampaign.js new file mode 100644 index 000000000..d033dd557 --- /dev/null +++ b/public/js/pages/Preordercampaign/Preordercampaign.js @@ -0,0 +1,103 @@ +Vue.component('Preordercampaign', { + template: ` + + + + + + + + + + + + + + + + + + + `, + + data() { + return { + window: window, + PreordercampaignTableConfig: { + key: 'PreordercampaignTable', + tableHeader: 'Vorbestellkampagnen', + defaultPageSize: 25, + headers: [ + {text: 'Status', key: 'status', class: 'text-center',sortable: false,filter:false, priority: 20}, + {text: '', key: 'add', class: 'text-center',filter:false, sortable: false, priority: 18}, + {text: 'Netzgebiet', key: 'network_name', priority: 19}, + {text: 'Name', key: 'name', priority: 14}, + {text: 'Fortschritt', key: 'progress', priority: 17,filter:false,sortable: false}, + {text: 'Workorders', key: 'rimo_workoders', class: 'text-center', priority: 16,filter:false}, + {text: 'Von', key: 'from', class: 'text-center', priority: 13,filter:false,sortable: false}, + {text: 'Bis', key: 'to', class: 'text-center', priority: 12,filter:false,sortable: false}, + {text: 'Aktionen', key: 'actions', class: 'text-center', sortable: false, priority: 21,filter:false} + ], + customRowClass: (row) => { + if (row.from <= Date.now()/1000 && row.to >= Date.now()/1000) { + return 'active'; + } + } + } + } + }, + mounted() { + if (window.TT_CONFIG.IS_ADMIN === "1") { + this.PreordercampaignTableConfig.headers.splice(3, 0, {text: 'Netzbesitzer', key: 'network_owner_name', priority: 4, filter: 'select', filterOptions: window['TT_CONFIG']['NETWORK_OWNER_OPTIONS']}); + } + }, + methods: { + formatDate: date => window.moment(date * 1000).format('DD.MM.YYYY'), + } +}); diff --git a/public/plugins/vue/tt-components/css/tt-table.css b/public/plugins/vue/tt-components/css/tt-table.css index 02fa54d34..e52c028a5 100644 --- a/public/plugins/vue/tt-components/css/tt-table.css +++ b/public/plugins/vue/tt-components/css/tt-table.css @@ -83,7 +83,7 @@ } .tt-table.table-sm > tbody > tr > td * { - font-size: 13px; + font-size: 14px; } .tt-table.table-sm > tbody > tr { diff --git a/public/plugins/vue/tt-components/tt-table-crud.js b/public/plugins/vue/tt-components/tt-table-crud.js index 0df34a368..2c1894797 100644 --- a/public/plugins/vue/tt-components/tt-table-crud.js +++ b/public/plugins/vue/tt-components/tt-table-crud.js @@ -66,8 +66,9 @@ Vue.component('tt-table-crud', { - + + diff --git a/public/plugins/vue/tt-components/tt-table.js b/public/plugins/vue/tt-components/tt-table.js index cde183b3b..f543b07a9 100644 --- a/public/plugins/vue/tt-components/tt-table.js +++ b/public/plugins/vue/tt-components/tt-table.js @@ -825,16 +825,16 @@ Vue.component('tt-table', { } }) -Vue.config.errorHandler = function (err, vm, info) { - // still log errors to the console - console.error(info, err, vm); - - if (typeof vm.config.key === 'string') { - // check if document.querySelector table.tt-table exists aswell if it has atleast 3 elements - const table = document.querySelector('table.tt-table'); - if (!table || !table.querySelectorAll('tr').length > 2) { - // localStorage.removeItem(`tt-table-${vm.config.key}`); - // window.location.reload(); - } - } -} \ No newline at end of file +// Vue.config.errorHandler = function (err, vm, info) { +// // still log errors to the console +// console.error(info, err, vm); +// +// if (typeof vm.config.key === 'string') { +// // check if document.querySelector table.tt-table exists aswell if it has atleast 3 elements +// const table = document.querySelector('table.tt-table'); +// if (!table || !table.querySelectorAll('tr').length > 2) { +// // localStorage.removeItem(`tt-table-${vm.config.key}`); +// // window.location.reload(); +// } +// } +// } \ No newline at end of file