diff --git a/application/Preorder/PreorderModel.php b/application/Preorder/PreorderModel.php index b36aaf7c6..da1872fd7 100644 --- a/application/Preorder/PreorderModel.php +++ b/application/Preorder/PreorderModel.php @@ -1190,25 +1190,36 @@ class PreorderModel public static function countActivePreorder($preorderCampaignId = null) { $db = FronkDB::singleton(); - $where = " AND h.rimo_op_state != 'Not2Connect'"; + // The base WHERE clause no longer excludes 'Not2Connect' states. + // It only filters for active, non-deleted preorders. + $where = "p.deleted = 0 AND tt_preorderstatus.code NOT IN (20) AND tt_preorderstatus.code < 899"; if ($preorderCampaignId) { - $where .= " AND p.preordercampaign_id = $preorderCampaignId"; + $where .= " AND p.preordercampaign_id = " . (int)$preorderCampaignId; } $sql = "SELECT - COALESCE(SUM(CASE - WHEN h.tool_building_type = 2 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."`.Hausnummer h ON p.adb_hausnummer_id = h.id - LEFT JOIN `".FRONKDB_DBNAME."`.Preorderstatus tt_preorderstatus ON p.status_id = tt_preorderstatus.id - WHERE p.deleted = 0 AND tt_preorderstatus.code NOT IN (20) AND tt_preorderstatus.code < 899" . $where; + -- MD count: Sums connection counts for preorders in Multi-Dwelling Units (tool_building_type = 2) + COALESCE(SUM(CASE + WHEN h.tool_building_type = 2 THEN COALESCE(p.connection_count, 1) + ELSE 0 + END), 0) AS md_count, + + -- Total count: Sums all connection counts for active preorders + COALESCE(SUM(COALESCE(p.connection_count, 1)), 0) AS total_count, + + -- NEW Not2Connect count: Sums connection counts only for preorders where the building state is 'Not2Connect' + COALESCE(SUM(CASE + WHEN h.rimo_op_state = 'Not2Connect' THEN COALESCE(p.connection_count, 1) + ELSE 0 + END), 0) AS not2connect_count + FROM + `".FRONKDB_DBNAME."`.Preorder p + LEFT JOIN `".ADDRESSDB_DBNAME."`.Hausnummer h ON p.adb_hausnummer_id = h.id + LEFT JOIN `".FRONKDB_DBNAME."`.Preorderstatus tt_preorderstatus ON p.status_id = tt_preorderstatus.id + WHERE " . $where; $queryStart = microtime(true); - $res = $db->query($sql . $where); + $res = $db->query($sql); mfLoghandler::singleton()->debug("[Query took: ".(microtime(true) - $queryStart)." seconds] " . $sql); if ($db->num_rows($res)) { @@ -1216,43 +1227,82 @@ class PreorderModel return [ 'md_count' => (int)$data->md_count, 'sd_count' => (int)($data->total_count - $data->md_count), - 'total_count' => (int)$data->total_count + 'total_count' => (int)$data->total_count, + 'not2connect_count' => (int)$data->not2connect_count // New return value ]; } return [ 'md_count' => 0, 'sd_count' => 0, - 'total_count' => 0 + 'total_count' => 0, + 'not2connect_count' => 0 ]; } public static function countTotalUnits($preorderCampaignId = null) { $db = FronkDB::singleton(); - $where = " h.rimo_type != 'greenfield' AND h.rimo_op_state != 'Not2Connect'"; + // The new WHERE condition is more complex and implemented directly in the main query. + $where = "1=1"; if ($preorderCampaignId) { - $where .= " AND pc.id = $preorderCampaignId"; + $where .= " AND pc.id = " . (int)$preorderCampaignId; } + // This query now implements the conditional logic for counting units. + // A unit is counted if its building type is standard, OR if its type is special AND has an active preorder. $sql = "SELECT - pc.id AS campaign_id, - COUNT(w.id) AS total_unit_count, - SUM(CASE - WHEN h.tool_building_type IN (0, 1) THEN 1 - ELSE 0 - END) AS total_unit_count_sd, - SUM(CASE - WHEN h.tool_building_type = 2 THEN 1 - ELSE 0 - END) 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 - LEFT JOIN `".ADDRESSDB_DBNAME."`.Hausnummer h ON n.id = h.netzgebiet_id - LEFT JOIN `".ADDRESSDB_DBNAME."`.Wohneinheit w ON h.id = w.hausnummer_id - WHERE $where - GROUP BY pc.id"; + pc.id AS campaign_id, + + -- Total unit count based on the new logic + COUNT(w.id) AS total_unit_count, + + -- SD unit count (Single Dwelling) + SUM(CASE + WHEN h.tool_building_type IN (0, 1) THEN 1 + ELSE 0 + END) AS total_unit_count_sd, + + -- MD unit count (Multi Dwelling) + SUM(CASE + WHEN h.tool_building_type = 2 THEN 1 + ELSE 0 + END) AS total_unit_count_md, + + -- NEW Not2Connect unit count + SUM(CASE + WHEN h.rimo_op_state = 'Not2Connect' THEN 1 + ELSE 0 + END) AS total_unit_count_not2connect + FROM `".FRONKDB_DBNAME."`.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 + LEFT JOIN `".ADDRESSDB_DBNAME."`.Hausnummer h ON n.id = h.netzgebiet_id + LEFT JOIN `".ADDRESSDB_DBNAME."`.Wohneinheit w ON h.id = w.hausnummer_id + -- Subquery to find all buildings that have at least one active preorder + LEFT JOIN ( + SELECT p_sub.adb_hausnummer_id + FROM `".FRONKDB_DBNAME."`.Preorder p_sub + JOIN `".FRONKDB_DBNAME."`.Preorderstatus ps_sub ON p_sub.status_id = ps_sub.id + WHERE p_sub.deleted = 0 AND ps_sub.code NOT IN (20) AND ps_sub.code < 899 + GROUP BY p_sub.adb_hausnummer_id + ) AS active_preorders ON h.id = active_preorders.adb_hausnummer_id + WHERE + ($where) + AND + ( + -- Condition 1: Include unit if its building rimo_type is NOT one of the special types. + h.rimo_type NOT IN ('greenfield', 'other', 'transmitting station', 'transformer station', 'outdoor cabinet') + + OR + + -- Condition 2: OR if the rimo_type IS special (or NULL), include it ONLY IF an active preorder exists for the building. + ( + (h.rimo_type IS NULL OR h.rimo_type IN ('greenfield', 'other', 'transmitting station', 'transformer station', 'outdoor cabinet')) + AND active_preorders.adb_hausnummer_id IS NOT NULL + ) + ) + GROUP BY pc.id"; $queryStart = microtime(true); $res = $db->query($sql); @@ -1263,14 +1313,16 @@ class PreorderModel return [ 'total_unit_count' => (int)$data->total_unit_count, 'total_unit_count_sd' => (int)$data->total_unit_count_sd, - 'total_unit_count_md' => (int)$data->total_unit_count_md + 'total_unit_count_md' => (int)$data->total_unit_count_md, + 'total_unit_count_not2connect' => (int)$data->total_unit_count_not2connect // New return value ]; } return [ 'total_unit_count' => 0, 'total_unit_count_sd' => 0, - 'total_unit_count_md' => 0 + 'total_unit_count_md' => 0, + 'total_unit_count_not2connect' => 0 ]; } @@ -1354,6 +1406,9 @@ ORDER BY $addressDbName = defined('ADDRESSDB_DBNAME') ? ADDRESSDB_DBNAME : 'addressdb'; $safeCampaignId = (int)$campaignId; + // add time debug + $startTime = microtime(true); + $sql = " SELECT h.id AS hausnummer_id, h.gps_lat, h.gps_long, h.rimo_type, h.rimo_op_state, h.rimo_ex_state, h.hausnummer, @@ -1376,7 +1431,14 @@ ORDER BY ORDER BY h.id "; + // die with query time + $result = $db->query($sql); + + $endTime = microtime(true); + $executionTime = $endTime - $startTime; + die("Query executed in {$executionTime} seconds.\n"); + return $result ? $result->fetch_all(MYSQLI_ASSOC) : []; } diff --git a/application/Preordercampaign/PreordercampaignController.php b/application/Preordercampaign/PreordercampaignController.php index b3b8fa9b4..1ec43a17e 100644 --- a/application/Preordercampaign/PreordercampaignController.php +++ b/application/Preordercampaign/PreordercampaignController.php @@ -24,6 +24,7 @@ class PreordercampaignController extends mfBaseController { json_decode($this->me->getFlag("preorder_networks")->value() ?: '[]') )); + array_map('unlink', glob(TEMP_DIR . "/Preordercampaign/*.json")); $campaigns = array_map(function ($c) { diff --git a/db/migrations/20250918133500_preorder_add_wohneinheit_index.php b/db/migrations/20250918133500_preorder_add_wohneinheit_index.php new file mode 100644 index 000000000..50c7f7714 --- /dev/null +++ b/db/migrations/20250918133500_preorder_add_wohneinheit_index.php @@ -0,0 +1,20 @@ +getEnvironment() !== 'thetool') return; + + $sql = "ALTER TABLE `Preorder` ADD INDEX `idx_adb_wohneinheit_id` (`adb_wohneinheit_id`)"; + $this->execute($sql); + } + + public function down(): void { + if ($this->getEnvironment() !== 'thetool') return; + + $sql = "ALTER TABLE `Preorder` DROP INDEX `idx_adb_wohneinheit_id`"; + $this->execute($sql); + } +} diff --git a/public/js/pages/PreorderRimoTypeMap/PreorderRimoTypeMap.css b/public/js/pages/PreorderRimoTypeMap/PreorderRimoTypeMap.css index 50ade9541..087836799 100644 --- a/public/js/pages/PreorderRimoTypeMap/PreorderRimoTypeMap.css +++ b/public/js/pages/PreorderRimoTypeMap/PreorderRimoTypeMap.css @@ -8,6 +8,7 @@ } .map-filter-container { + margin-left: 40px; display: flex; gap: 0.5rem; flex-wrap: wrap; @@ -88,11 +89,12 @@ } .tooltip-content-wrapper.marker-label-highlight { - background-color: rgba(248, 215, 218, 0.9); - border-color: #e57373; - color: #721c24; + background-color: #dc3545; /* A solid, vibrant red */ + border-color: #c82333; /* A slightly darker border for definition */ + color: white; /* White text for maximum contrast */ } + .tooltip-content-wrapper.marker-label-saturated { background-color: #28a745; /* A solid, vibrant green */ border-color: #218838; /* A slightly darker border for definition */ diff --git a/public/js/pages/Preordercampaign/Preordercampaign.js b/public/js/pages/Preordercampaign/Preordercampaign.js index ded63d7b9..dfdc1d4f8 100644 --- a/public/js/pages/Preordercampaign/Preordercampaign.js +++ b/public/js/pages/Preordercampaign/Preordercampaign.js @@ -44,6 +44,11 @@ Vue.component('Preordercampaign', { {{ campaign.count_total_units.total_unit_count }} ({{ ((campaign.active_preorder_count.total_count / (campaign.count_total_units.total_unit_count)) * 100 || 0).toFixed(1) }} %) +