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) }} %)
+
+ N2C:{{ campaign.active_preorder_count.not2connect_count }} /
+ {{ campaign.count_total_units.total_unit_count_not2connect }}
+ ({{ ((campaign.active_preorder_count.not2connect_count / campaign.count_total_units.total_unit_count_not2connect) * 100 || 0).toFixed(2) }} %)
+