diff --git a/application/DashboardNew/DashboardNewController.php b/application/DashboardNew/DashboardNewController.php new file mode 100644 index 000000000..f9c382807 --- /dev/null +++ b/application/DashboardNew/DashboardNewController.php @@ -0,0 +1,230 @@ +loadMe(); + $this->layout()->set("me", $me); + $this->me = $me; + } + + protected function indexAction() { +// $this->layout()->set('additionalJS', ["plugins/chart.js/chart.4.4.6.js", "plugins/chart.js/chartjs-adapter-moment.min.js"]); + Helper::renderVue($this, "DashboardNew", $this->mod, []); + } + + + protected function getNetOwnerFilterOptionsAction() { + if (!$this->me->is("Admin")) return; // TODO: enable for RML and Energie Steiermark + + $allPreorderCampaigns = PreordercampaignModel::getAll(); + $netowners = []; + + foreach ($allPreorderCampaigns as $campaign) { + $network = new Network($campaign->network_id); + $networkOwner = new Address($network->owner_id); + $ownerName = $networkOwner->getCompanyOrName(); + + if (!in_array($network->owner_id, array_column($netowners, 'value'))) { + $netowners[] = ['text' => $ownerName, 'value' => $network->owner_id]; + } + } + + self::returnJson($netowners); + } + + protected function getCampaignFilterOptionsAction() { + if (!$this->me->is("Admin")) return; // TODO: enable for RML and Energie Steiermark + $post = json_decode(file_get_contents('php://input'), true); + $netowner_ids = isset($post['netOwners']) ? [$post['netOwners']] : []; + $campaigns = []; + + $all_campaigns = PreordercampaignModel::getAll(); + + if (!empty($netowner_ids)) { + foreach ($all_campaigns as $campaign) { + $networkOwner = $campaign->network->owner_id; + if (!in_array($networkOwner, $netowner_ids)) continue; + if (!in_array($campaign->id, array_column($campaigns, 'value'))) { + $campaigns[] = ['text' => $campaign->name, 'value' => $campaign->id]; + } + } + } else { + foreach ($all_campaigns as $campaign) { + if (!in_array($campaign->id, array_column($campaigns, 'value'))) { + $campaigns[] = ['text' => $campaign->name, 'value' => $campaign->id]; + } + } + } + + self::returnJson($campaigns); + } + + protected function getCampaignGemeindeFilterOptionsAction() { + if (!$this->me->is("Admin")) return; // TODO: enable for RML and Energie Steiermark + $post = json_decode(file_get_contents('php://input'), true); + $netowner_ids = isset($post['netOwners']) ? [$post['netOwners']] : []; + $campaign_ids = isset($post['campaigns']) ? [$post['campaigns']] : []; + $campaigns = []; + + $all_campaigns = PreordercampaignModel::getAll(); + + if (!empty($netowner_ids)) { + foreach ($all_campaigns as $campaign) { + $networkOwner = $campaign->network->owner_id; + if (!in_array($networkOwner, $netowner_ids)) continue; + if (in_array($campaign->id, $campaign_ids)) continue; + $campaigns[] = $campaign->id; + } + } else { + foreach ($all_campaigns as $campaign) { + if (in_array($campaign->id, $campaign_ids)) continue; + $campaigns[] = $campaign->id; + } + } + + if (!empty($campaign_ids)) { + self::returnJson($this->getGemeindenFromCampaigns($campaign_ids)); + return; + } + + self::returnJson($this->getGemeindenFromCampaigns($campaigns)); + } + + private function getGemeindenFromCampaigns($campaignids = []) { + $gemeinden = []; + + foreach ($campaignids as $campaign_id) { + $campaign = new Preordercampaign($campaign_id); + if (!$campaign || !$campaign->network_id || !$campaign->network->adb_netzgebiet_id) continue; + + $gems = $campaign->network->adb_netzgebiet->gemeinden; + + if (!is_array($gems)) continue; + + foreach ($gems as $gem) { + if (!in_array($gem->id, array_column($gemeinden, 'value'))) $gemeinden[] = ['text' => $gem->name, 'value' => $gem->id]; + } + } + ksort($gemeinden); + + return $gemeinden; + } + + + protected function getDashboardDataAction() { + $post = json_decode(file_get_contents('php://input'), true); + $netowner_ids = $post['netOwners'] === '' ? [] : [$post['netOwners']] ?? []; + $campaign_ids = $post['campaigns'] === '' ? [] : [$post['campaigns']] ?? []; + $gemeinde_ids = $post['gemeinden'] === '' ? [] : [$post['gemeinden']] ?? []; + + if (!empty($netowner_ids)) { + $campaign_ids = empty($campaign_ids) ? + array_map(fn($campaign) => $campaign->id, PreordercampaignModel::getAll()) : + $campaign_ids; + + $campaign_ids = array_filter($campaign_ids, function ($campaign_id) use ($netowner_ids) { + $campaign = new Preordercampaign($campaign_id); + return in_array($campaign->network->owner_id, $netowner_ids); + }); + } + + $order_max_homes = $this->getTotalHomes($campaign_ids, $gemeinde_ids); + + $efh_connection_types = ["single-dwelling", "business"]; + $mph_connection_types = ["apartment-building", "apartment", "multi-dwelling"]; + + $countFunction = function($params, $statusFlag = null) use ($campaign_ids, $gemeinde_ids) { + $baseParams = ["preordercampaign_id" => $campaign_ids]; + if (!empty($gemeinde_ids)) { + $baseParams["gemeinde_id"] = $gemeinde_ids; + } + $params = array_merge($baseParams, $params); + return $statusFlag ? + PreorderModel::countStatusFlagsActive($params, $statusFlag) : + PreorderModel::countActive($params); + }; + + $counts = [ + 'count_orders' => $countFunction([]), + 'total_efh_orders' => $countFunction(["connection_type" => $efh_connection_types]), + 'total_efh_orders_vorsorge' => $countFunction(["connection_type" => $efh_connection_types, "type" => "provision"]), + 'total_efh_orders_vollanschluss' => $countFunction(["connection_type" => $efh_connection_types, "type" => "order"]), + 'total_mph_orders' => $countFunction(["connection_type" => $mph_connection_types]), + 'total_mph_orders_vorsorge' => $countFunction(["connection_type" => $mph_connection_types, "type" => "provision"]), + 'total_mph_orders_vollanschluss' => $countFunction(["connection_type" => $mph_connection_types, "type" => "order"]), + 'baufortschritt_140' => $countFunction([">status_code" => "139"]), + 'installationspaket_erhalten' => $countFunction(["connection_type" => $efh_connection_types], 145), + 'lehrrohr_im_haus' => $countFunction(["connection_type" => $efh_connection_types], 200), + 'inhouse_kabel_verlegt_efh' => $countFunction(["connection_type" => $efh_connection_types], 242), + 'inhouse_kabel_verlegt_mph' => $countFunction(["connection_type" => $mph_connection_types], 242), + 'installationsfortschritt_245' => $countFunction([">status_code" => "244"]), + 'ont_installiert_300' => $countFunction([">status_code" => "299"]), + 'vollanschluss_dokumentiert_350' => $countFunction(["status_code" => ["350","500"], "type" => "order"]), + 'vorsorge_dokumentiert_351' => $countFunction(["status_code" => ["351","500"], "type" => "provision"]), + 'provider_bestellt_500' => $countFunction(["status_code" => "500"]) + ]; + + self::returnJson([ + 'order_max_home_addrdb' => $order_max_homes, + 'order_actual_order' => $counts['count_orders'], + 'order_efh' => $counts['total_efh_orders'], + 'order_efh_vorsorge' => $counts['total_efh_orders_vorsorge'], + 'order_efh_vollanschluss' => $counts['total_efh_orders_vollanschluss'], + 'order_mph' => $counts['total_mph_orders'], + 'order_mph_vorsorge' => $counts['total_mph_orders_vorsorge'], + 'order_mph_vollanschluss' => $counts['total_mph_orders_vollanschluss'], + 'baufortschritt_140' => $counts['baufortschritt_140'], + 'installationspaket_erhalten' => $counts['installationspaket_erhalten'], + 'lehrrohr_im_haus' => $counts['lehrrohr_im_haus'], + 'inhouse_kabel_verlegt_efh' => $counts['inhouse_kabel_verlegt_efh'], + 'inhouse_kabel_verlegt_mph' => $counts['inhouse_kabel_verlegt_mph'], + 'installationsfortschritt_245' => $counts['installationsfortschritt_245'], + 'ont_installiert_300' => $counts['ont_installiert_300'], + 'vollanschluss_dokumentiert_350' => $counts['vollanschluss_dokumentiert_350'], + 'vorsorge_dokumentiert_351' => $counts['vorsorge_dokumentiert_351'], + 'provider_bestellt_500' => $counts['provider_bestellt_500'] + ]); + } + + + private function getTotalHomes(array $preordercampaign_id = [], array $gemeinde_id = []) { + $baseSQL = "SELECT COUNT(adb_wohneinheit.id) as cnt FROM `" . ADDRESSDB_DBNAME . "`.Wohneinheit adb_wohneinheit + LEFT JOIN `" . ADDRESSDB_DBNAME . "`.Hausnummer adb_hausnummer ON (adb_wohneinheit.hausnummer_id = adb_hausnummer.id) + LEFT JOIN `" . ADDRESSDB_DBNAME . "`.Strasse adb_strasse ON (adb_hausnummer.strasse_id = adb_strasse.id) + WHERE 1=1"; + + $where = ""; + + if (!empty($preordercampaign_id)) { + $netzgebiet_ids = []; + foreach ($preordercampaign_id as $campaign_id) { + $campaign = new Preordercampaign($campaign_id); + if ($campaign->network_id) { + $network = new Network($campaign->network_id); + $netzgebiet_ids[] = $network->adb_netzgebiet_id; + } + } + + $where .= " AND adb_hausnummer.netzgebiet_id IN (" . implode(',', array_map('intval', $netzgebiet_ids)) . ")"; + } + + if (!empty($gemeinde_id)) { + $where .= " AND adb_strasse.gemeinde_id IN (" . implode(',', array_map('intval', $gemeinde_id)) . ")"; + } + + $sql = $baseSQL . $where; + + $res = $this->db()->query($sql); + if ($this->db()->num_rows($res)) { + $data = $this->db()->fetch_object($res); + return $data->cnt; + } + return 0; + } + + +} \ No newline at end of file diff --git a/application/Preorder/PreorderModel.php b/application/Preorder/PreorderModel.php index 1a97fbe11..4edfe6bb5 100644 --- a/application/Preorder/PreorderModel.php +++ b/application/Preorder/PreorderModel.php @@ -365,7 +365,6 @@ class PreorderModel { && !array_key_exists("status_id", $filter) && !array_key_exists("status_id", $filter) ) { $filter["debug($sql); $res = $db->query($sql); @@ -833,5 +832,42 @@ class PreorderModel { //var_dump($filter, $where);exit; return $where; } - + + public static function countStatusFlagsActive($filter = [], $statusFlag = null) { + if ($statusFlag === null) { + die("Please select a statusflag"); + } + + if(!is_array($filter)) return false; + + if(!array_key_exists("deleted", $filter)) { + $filter["deleted"] = null; + } + + if( !array_key_exists("status_code", $filter) && !array_key_exists("status_code", $filter) + && !array_key_exists("status_id", $filter) && !array_key_exists("status_id", $filter) ) { + $filter["debug($sql); + + $res = $db->query($sql); + if ($db->num_rows($res)) { + $data = $db->fetch_object($res); + return $data->cnt; + } + return 0; + } + + } diff --git a/application/Preordercampaign/Preordercampaign.php b/application/Preordercampaign/Preordercampaign.php index 9044951ac..820276619 100644 --- a/application/Preordercampaign/Preordercampaign.php +++ b/application/Preordercampaign/Preordercampaign.php @@ -126,8 +126,10 @@ class Preordercampaign extends mfBaseModel { $total_md = 0; $netzgebiet_ids = null; - foreach($this->getProperty("salesclusters") as $scluster) { - if($scluster->id) $netzgebiet_ids[] = $scluster->id; + if ($this->getProperty("salesclusters")) { + foreach($this->getProperty("salesclusters") as $scluster) { + if($scluster->id) $netzgebiet_ids[] = $scluster->id; + } } if(is_array($netzgebiet_ids) && count($netzgebiet_ids)) { foreach(ADBNetzgebietModel::search(["netzgebiet_id" => $netzgebiet_ids]) as $netzgebiet) { diff --git a/db/migrations/20250109160000_add_preorderstatusflagvalue_index.php b/db/migrations/20250109160000_add_preorderstatusflagvalue_index.php new file mode 100644 index 000000000..2e19dc04c --- /dev/null +++ b/db/migrations/20250109160000_add_preorderstatusflagvalue_index.php @@ -0,0 +1,19 @@ +getEnvironment() == "thetool") { + //VoiceCallHistory Table add start index + $this->table("PreorderStatusflagValue")->addIndex(["flag_id"])->save(); + } + } + + public function down(): void { + if ($this->getEnvironment() == "thetool") { + $this->table("PreorderStatusflagValue")->removeIndex(["flag_id"])->save(); + } + } +} diff --git a/public/js/pages/DashboardNew/DashboardNew.css b/public/js/pages/DashboardNew/DashboardNew.css new file mode 100644 index 000000000..f9cf0c655 --- /dev/null +++ b/public/js/pages/DashboardNew/DashboardNew.css @@ -0,0 +1,55 @@ +.dashboard-container { + width: 100%; + max-width: 600px; + margin: 0 auto; +} + +.dashboard-content { + display: flex; + flex-direction: column; + gap: 1rem; +} + +.filter-section, +.campaign-section { + width: 100%; +} + +.dashboard-cards { + display: grid; + grid-template-columns: repeat(3, 1fr); + gap: 1rem; +} + +.dashboard-data-selector { + display: grid; + grid-template-columns: repeat(3, 1fr); + gap: 1rem; +} + + +@media (min-width: 768px) { + .dashboard-content { + display: grid; + grid-template-columns: repeat(2, 1fr); + gap: 1rem; + } +} + +@media (max-width: 767px) { + .filter-section, + .campaign-section { + grid-column: 1 / -1; + } + + .dashboard-cards { + grid-template-columns: repeat(2, 1fr); + } + + + .dashboard-data-selector { + grid-template-columns: repeat(1, 1fr); + } +} + + diff --git a/public/js/pages/DashboardNew/DashboardNew.js b/public/js/pages/DashboardNew/DashboardNew.js new file mode 100644 index 000000000..80c0a4ff9 --- /dev/null +++ b/public/js/pages/DashboardNew/DashboardNew.js @@ -0,0 +1,273 @@ +Vue.component('dashboard-location-selector', { + template: ` +
+ + + +
+ `, + props: + { + selectedNetworkOwner: {type: String, required: true}, + selectedCampaign: {type: String, required: true}, + selectedGemeinde: {type: String, required: true}, + } + , + data() { + return { + filterOptions: { + netOwners: [], + campaigns: [], + gemeinden: [], + }, + }; + }, + async mounted() { + await this.fetchNetOwnerFilterOptions(); + await this.fetchCampaignFilterOptions(); + await this.fetchCampaignGemeindeFilterOptions(); + }, + methods: { + async fetchNetOwnerFilterOptions() { + const response = await axios.get(`${window.TT_CONFIG['BASE_URL']}/getNetOwnerFilterOptions`); + this.filterOptions.netOwners = [{value: 'all', text: 'Alle'}, ...response.data]; + }, + async fetchCampaignFilterOptions() { + const response = await axios.post(`${window.TT_CONFIG['BASE_URL']}/getCampaignFilterOptions`, {netOwners: this.selectedNetworkOwner === 'all' ? undefined : this.selectedNetworkOwner}); + this.filterOptions.campaigns = [{value: 'all', text: 'Alle'}, ...response.data]; + }, + async fetchCampaignGemeindeFilterOptions() { + const response = await axios.post(`${window.TT_CONFIG['BASE_URL']}/getCampaignGemeindeFilterOptions`, + {netOwners: this.selectedNetworkOwner === 'all' ? undefined : this.selectedNetworkOwner, campaigns: this.selectedCampaign === 'all' ? undefined : this.selectedCampaign}); + this.filterOptions.gemeinden = [{value: 'all', text: 'Alle'}, ...response.data]; + }, + }, + watch: { + selectedNetworkOwner() { + this.fetchCampaignFilterOptions(); + this.fetchCampaignGemeindeFilterOptions(); + }, + selectedCampaign() { + this.fetchCampaignGemeindeFilterOptions(); + } + }, +}); + +Vue.component('tt-dashboard-display-card', { + props: ['header', 'icon', 'text', 'subHeaders', 'color'], + computed: { + cardHeight() { + return `${96 + 25 * this.subHeaders.length}px`; + } + }, + template: ` +
+
+
+
+ +
+
{{ header }}
+

{{ text }}

+
+

{{ subHeader }}

+
+
+
+
+ ` +}); + + +Vue.component('dashboard-new', { + template: ` + + +
+ +
+

Bestellungen

+
+ + + +
+
+

Baufortschritt

+
+ + + + + +
+
+

Installationsfortschritt

+
+ + + + + +
+
+
+ `, + data() { + return { + dashboardData: { + order_max_home_addrdb: 0, + order_actual_order: "0", + order_efh: "0", + order_efh_vorsorge: "0", + order_efh_vollanschluss: "0", + order_mph: "0", + order_mph_vorsorge: "0", + order_mph_vollanschluss: "0", + baufortschritt_140: "0", + installationspaket_erhalten: "0", + lehrrohr_im_haus: "0", + inhouse_kabel_verlegt_efh: "0", + inhouse_kabel_verlegt_mph: "0", + installationsfortschritt_245: "0", + ont_installiert_300: "0", + vollanschluss_dokumentiert_350: "0", + vorsorge_dokumentiert_351: "0", + provider_bestellt_500: "0" + }, + selectedNetworkOwner: 'all', + selectedCampaign: 'all', + selectedGemeinde: 'all', + isLoading: false + }; + }, + async mounted() { + await this.fetchDashboardData(); + }, + methods: { + async fetchDashboardData() { + this.isLoading = true; + try { + const response = await axios.post(`${window.TT_CONFIG['BASE_URL']}/getDashboardData`, { + netOwners: this.selectedNetworkOwner === 'all' ? '' : this.selectedNetworkOwner, + campaigns: this.selectedCampaign === 'all' ? '' : this.selectedCampaign, + gemeinden: this.selectedGemeinde === 'all' ? '' : this.selectedGemeinde, + }); + + console.log(response.data); + this.dashboardData = response.data; + } catch (error) { + console.error('Error fetching dashboard data:', error); + } finally { + this.isLoading = false; + } + } + }, + watch: { + selectedNetworkOwner() { + this.fetchDashboardData(); + }, + selectedCampaign() { + this.fetchDashboardData(); + }, + selectedGemeinde() { + this.fetchDashboardData(); + } + } +});