From 71b14a60b6b15527becba94d69abb06fa31cbf51 Mon Sep 17 00:00:00 2001 From: Andreas Kristiansen <6977712+AndreasK79@users.noreply.github.com> Date: Thu, 5 Feb 2026 08:19:41 +0100 Subject: [PATCH 01/12] Consolidate queries --- application/models/Cq.php | 246 +++++++++++++++++++++++++++++++++----- 1 file changed, 219 insertions(+), 27 deletions(-) diff --git a/application/models/Cq.php b/application/models/Cq.php index 2c2240604..8632ba971 100644 --- a/application/models/Cq.php +++ b/application/models/Cq.php @@ -15,30 +15,37 @@ class CQ extends CI_Model{ $qsl = $this->genfunctions->gen_qsl_from_postdata($postdata); + // Initialize all bands to dash foreach ($bands as $band) { for ($i = 1; $i <= 40; $i++) { $bandCq[$i][$band] = '-'; // Sets all to dash to indicate no result } + } - if ($postdata['worked'] != NULL) { - $cqBand = $this->getCQWorked($location_list, $band, $postdata); - foreach ($cqBand as $line) { - $bandCq[$line->col_cqz][$band] = '
col_cqz) . '","' . $band . '","All", "All","'. $postdata['mode'] . '","CQZone","")\'>W
'; - $cqZ[$line->col_cqz]['count']++; - } + // Get all worked zones for all bands in ONE query + if ($postdata['worked'] != NULL) { + $cqBand = $this->getCQWorkedAllBands($location_list, $bands, $postdata); + foreach ($cqBand as $line) { + $band = $line->col_band; + $bandCq[$line->col_cqz][$band] = '
col_cqz) . '","' . $band . '","All", "All","'. $postdata['mode'] . '","CQZone","")\'>W
'; + $cqZ[$line->col_cqz]['count']++; } - if ($postdata['confirmed'] != NULL) { - $cqBand = $this->getCQConfirmed($location_list, $band, $postdata); - foreach ($cqBand as $line) { - $bandCq[$line->col_cqz][$band] = '
col_cqz) . '","' . $band . '","All", "All","'. $postdata['mode'] . '","CQZone","'.$qsl.'")\'>C
'; - $cqZ[$line->col_cqz]['count']++; - } + } + + // Get all confirmed zones for all bands in ONE query + if ($postdata['confirmed'] != NULL) { + $cqBand = $this->getCQConfirmedAllBands($location_list, $bands, $postdata); + foreach ($cqBand as $line) { + $band = $line->col_band; + $bandCq[$line->col_cqz][$band] = '
col_cqz) . '","' . $band . '","All", "All","'. $postdata['mode'] . '","CQZone","'.$qsl.'")\'>C
'; + $cqZ[$line->col_cqz]['count']++; } } // We want to remove the worked zones in the list, since we do not want to display them if ($postdata['worked'] == NULL) { - $cqBand = $this->getCQWorked($location_list, $postdata['band'], $postdata); + // Use optimized query for all bands at once + $cqBand = $this->getCQWorkedAllBands($location_list, $bands, $postdata); foreach ($cqBand as $line) { unset($bandCq[$line->col_cqz]); } @@ -46,7 +53,8 @@ class CQ extends CI_Model{ // We want to remove the confirmed zones in the list, since we do not want to display them if ($postdata['confirmed'] == NULL) { - $cqBand = $this->getCQConfirmed($location_list, $postdata['band'], $postdata); + // Use optimized query for all bands at once + $cqBand = $this->getCQConfirmedAllBands($location_list, $bands, $postdata); foreach ($cqBand as $line) { unset($bandCq[$line->col_cqz]); } @@ -161,18 +169,130 @@ class CQ extends CI_Model{ /* - * Function gets worked and confirmed summary on each band on the active stationprofile + * Function returns all worked (but not confirmed) states for ALL bands in one query + * Returns both col_cqz and col_band to avoid N+1 queries */ - function get_cq_summary($bands, $postdata, $location_list) { - foreach ($bands as $band) { - $worked = $this->getSummaryByBand($band, $postdata, $location_list); - $confirmed = $this->getSummaryByBandConfirmed($band, $postdata, $location_list); - $cqSummary['worked'][$band] = $worked[0]->count; - $cqSummary['confirmed'][$band] = $confirmed[0]->count; + function getCQWorkedAllBands($location_list, $bands, $postdata) { + $bindings=[]; + $sql = "SELECT DISTINCT col_cqz, col_band FROM " . $this->config->item('table_name') . " thcv + WHERE station_id IN (" . $location_list . ") + AND col_cqz <= 40 AND col_cqz <> '' + AND col_band IN ('" . implode("','", $bands) . "')"; + + if ($postdata['mode'] != 'All') { + $sql .= " AND (col_mode = ? OR col_submode = ?)"; + $bindings[]=$postdata['mode']; + $bindings[]=$postdata['mode']; } - $workedTotal = $this->getSummaryByBand($postdata['band'], $postdata, $location_list); - $confirmedTotal = $this->getSummaryByBandConfirmed($postdata['band'], $postdata, $location_list); + if ($postdata['datefrom'] != NULL) { + $sql .= " AND col_time_on >= ?"; + $bindings[]=$postdata['datefrom'] . ' 00:00:00'; + } + + if ($postdata['dateto'] != NULL) { + $sql .= " AND col_time_on <= ?"; + $bindings[]=$postdata['dateto'] . ' 23:59:59'; + } + + $sql .= " AND col_prop_mode != 'SAT'"; + + // Optimized NOT IN subquery instead of NOT EXISTS + /*$sql .= " AND col_cqz NOT IN ( + SELECT col_cqz FROM " . $this->config->item('table_name') . " + WHERE station_id IN (" . $location_list . ") + AND col_cqz <> '' + AND col_band IN ('" . implode("','", $bands) . "') + AND col_prop_mode != 'SAT'"; + + if ($postdata['mode'] != 'All') { + $sql .= " AND (col_mode = ? OR col_submode = ?)"; + $bindings[]=$postdata['mode']; + $bindings[]=$postdata['mode']; + } + + if ($postdata['datefrom'] != NULL) { + $sql .= " AND col_time_on >= ?"; + $bindings[]=$postdata['datefrom'] . ' 00:00:00'; + } + + if ($postdata['dateto'] != NULL) { + $sql .= " AND col_time_on <= ?"; + $bindings[]=$postdata['dateto'] . ' 23:59:59'; + } + + $sql .= $this->genfunctions->addQslToQuery($postdata); + + $sql .= ")";*/ + + $query = $this->db->query($sql,$bindings); + + return $query->result(); + } + + /* + * Function returns all confirmed states for ALL bands in one query + * Returns both col_cqz and col_band to avoid N+1 queries + */ + function getCQConfirmedAllBands($location_list, $bands, $postdata) { + $bindings=[]; + $sql = "SELECT DISTINCT col_cqz, col_band FROM " . $this->config->item('table_name') . " thcv + WHERE station_id IN (" . $location_list . ") + AND col_cqz <= 40 AND col_cqz <> '' + AND col_band IN ('" . implode("','", $bands) . "')"; + + if ($postdata['mode'] != 'All') { + $sql .= " AND (col_mode = ? OR col_submode = ?)"; + $bindings[]=$postdata['mode']; + $bindings[]=$postdata['mode']; + } + + if ($postdata['datefrom'] != NULL) { + $sql .= " AND col_time_on >= ?"; + $bindings[]=$postdata['datefrom'] . ' 00:00:00'; + } + + if ($postdata['dateto'] != NULL) { + $sql .= " AND col_time_on <= ?"; + $bindings[]=$postdata['dateto'] . ' 23:59:59'; + } + + $sql .= " AND col_prop_mode != 'SAT'"; + + $sql .= $this->genfunctions->addQslToQuery($postdata); + + $query = $this->db->query($sql,$bindings); + + return $query->result(); + } + + /* + * Function gets worked and confirmed summary on each band on the active stationprofile + * Optimized to use just 2 queries instead of N queries per band + */ + function get_cq_summary($bands, $postdata, $location_list) { + $bandslots = $this->bands->get_worked_bands('cq'); + + foreach ($bandslots as $band) { + $cqSummary['worked'][$band] = '-'; + $cqSummary['confirmed'][$band] = '-'; + } + + // Get all worked counts in ONE query + $workedAll = $this->getSummaryByBandAllBands($bands, $postdata, $location_list, $bandslots); + foreach ($workedAll as $row) { + $cqSummary['worked'][$row->col_band] = $row->count; + } + + // Get all confirmed counts in ONE query + $confirmedAll = $this->getSummaryByBandConfirmedAllBands($bands, $postdata, $location_list, $bandslots); + foreach ($confirmedAll as $row) { + $cqSummary['confirmed'][$row->col_band] = $row->count; + } + + + $workedTotal = $this->getSummaryByBand($postdata['band'], $postdata, $location_list, $bandslots); + $confirmedTotal = $this->getSummaryByBandConfirmed($postdata['band'], $postdata, $location_list, $bandslots); $cqSummary['worked']['Total'] = $workedTotal[0]->count; $cqSummary['confirmed']['Total'] = $confirmedTotal[0]->count; @@ -180,7 +300,7 @@ class CQ extends CI_Model{ return $cqSummary; } - function getSummaryByBand($band, $postdata, $location_list) { + function getSummaryByBand($band, $postdata, $location_list, $bandslots) { $bindings=[]; $sql = "SELECT count(distinct thcv.col_cqz) as count FROM " . $this->config->item('table_name') . " thcv"; @@ -192,7 +312,7 @@ class CQ extends CI_Model{ } else if ($band == 'All') { $this->load->model('bands'); - $bandslots = $this->bands->get_worked_bands('cq'); + // $bandslots = $this->bands->get_worked_bands('cq'); $bandslots_list = "'".implode("','",$bandslots)."'"; @@ -225,7 +345,7 @@ class CQ extends CI_Model{ return $query->result(); } - function getSummaryByBandConfirmed($band, $postdata, $location_list){ + function getSummaryByBandConfirmed($band, $postdata, $location_list, $bandslots){ $bindings=[]; $sql = "SELECT count(distinct thcv.col_cqz) as count FROM " . $this->config->item('table_name') . " thcv"; @@ -237,7 +357,7 @@ class CQ extends CI_Model{ } else if ($band == 'All') { $this->load->model('bands'); - $bandslots = $this->bands->get_worked_bands('cq'); + // $bandslots = $this->bands->get_worked_bands('cq'); $bandslots_list = "'".implode("','",$bandslots)."'"; @@ -272,4 +392,76 @@ class CQ extends CI_Model{ return $query->result(); } + /* + * Gets worked CQ zone counts for ALL bands in one query using GROUP BY + * Returns col_band and count for each band + */ + function getSummaryByBandAllBands($bands, $postdata, $location_list, $bandslots) { + $bindings=[]; + $sql = "SELECT col_band, COUNT(DISTINCT thcv.col_cqz) as count FROM " . $this->config->item('table_name') . " thcv"; + + $sql .= " WHERE station_id IN (" . $location_list . ') AND col_cqz <= 40 AND col_cqz > 0'; + $sql .= " AND col_band IN ('" . implode("','", $bands) . "')"; + $sql .= " AND col_prop_mode != 'SAT'"; + + if ($postdata['mode'] != 'All') { + $sql .= " AND (col_mode = ? OR col_submode = ?)"; + $bindings[]=$postdata['mode']; + $bindings[]=$postdata['mode']; + } + + if ($postdata['datefrom'] != NULL) { + $sql .= " AND col_time_on >= ?"; + $bindings[]=$postdata['datefrom'] . ' 00:00:00'; + } + + if ($postdata['dateto'] != NULL) { + $sql .= " AND col_time_on <= ?"; + $bindings[]=$postdata['dateto'] . ' 23:59:59'; + } + + $sql .= " GROUP BY col_band"; + + $query = $this->db->query($sql,$bindings); + + return $query->result(); + } + + /* + * Gets confirmed CQ zone counts for ALL bands in one query using GROUP BY + * Returns col_band and count for each band + */ + function getSummaryByBandConfirmedAllBands($bands, $postdata, $location_list, $bandslots) { + $bindings=[]; + $sql = "SELECT col_band, COUNT(DISTINCT thcv.col_cqz) as count FROM " . $this->config->item('table_name') . " thcv"; + + $sql .= " WHERE station_id IN (" . $location_list . ') AND col_cqz <= 40 AND col_cqz > 0'; + $sql .= " AND col_band IN ('" . implode("','", $bands) . "')"; + $sql .= " AND col_prop_mode != 'SAT'"; + + if ($postdata['mode'] != 'All') { + $sql .= " AND (col_mode = ? OR col_submode = ?)"; + $bindings[]=$postdata['mode']; + $bindings[]=$postdata['mode']; + } + + if ($postdata['datefrom'] != NULL) { + $sql .= " AND col_time_on >= ?"; + $bindings[]=$postdata['datefrom'] . ' 00:00:00'; + } + + if ($postdata['dateto'] != NULL) { + $sql .= " AND col_time_on <= ?"; + $bindings[]=$postdata['dateto'] . ' 23:59:59'; + } + + $sql .= $this->genfunctions->addQslToQuery($postdata); + + $sql .= " GROUP BY col_band"; + + $query = $this->db->query($sql,$bindings); + + return $query->result(); + } + } From fc6a3c0e5044b2a9697c49857b18699c65f6a1cf Mon Sep 17 00:00:00 2001 From: Andreas Kristiansen <6977712+AndreasK79@users.noreply.github.com> Date: Mon, 23 Feb 2026 19:21:02 +0100 Subject: [PATCH 02/12] [CQ Award] Major speed increase --- application/controllers/Awards.php | 51 +-- application/models/Cq.php | 507 ++++++++++---------------- application/views/awards/cq/index.php | 15 +- 3 files changed, 231 insertions(+), 342 deletions(-) diff --git a/application/controllers/Awards.php b/application/controllers/Awards.php index 3379dc64a..168d5adac 100644 --- a/application/controllers/Awards.php +++ b/application/controllers/Awards.php @@ -666,37 +666,41 @@ class Awards extends CI_Controller { $data['bands'] = $bands; // Used for displaying selected band(s) in the table in the view - if($this->input->method() === 'post') { - $postdata['qsl'] = $this->security->xss_clean($this->input->post('qsl')); - $postdata['lotw'] = $this->security->xss_clean($this->input->post('lotw')); - $postdata['eqsl'] = $this->security->xss_clean($this->input->post('eqsl')); - $postdata['qrz'] = $this->security->xss_clean($this->input->post('qrz')); - $postdata['worked'] = $this->security->xss_clean($this->input->post('worked')); - $postdata['confirmed'] = $this->security->xss_clean($this->input->post('confirmed')); - $postdata['notworked'] = $this->security->xss_clean($this->input->post('notworked')); - $postdata['band'] = $this->security->xss_clean($this->input->post('band')); + if($this->input->method() === 'post') { + $postdata['qsl'] = ($this->input->post('qsl',true) ?? 0) == 0 ? NULL: 1; + $postdata['lotw'] = ($this->input->post('lotw',true) ?? 0) == 0 ? NULL: 1; + $postdata['eqsl'] = ($this->input->post('eqsl',true) ?? 0) == 0 ? NULL: 1; + $postdata['qrz'] = ($this->input->post('qrz',true) ?? 0) == 0 ? NULL: 1; + $postdata['clublog'] = ($this->input->post('clublog',true) ?? 0) == 0 ? NULL: 1; + $postdata['worked'] = ($this->input->post('worked',true) ?? 0) == 0 ? NULL: 1; + $postdata['confirmed'] = ($this->input->post('confirmed',true) ?? 0) == 0 ? NULL: 1; + $postdata['notworked'] = ($this->input->post('notworked',true) ?? 0) == 0 ? NULL: 1; + $postdata['band'] = $this->security->xss_clean($this->input->post('band')); $postdata['mode'] = $this->security->xss_clean($this->input->post('mode')); $postdata['datefrom'] = $this->security->xss_clean($this->input->post('dateFrom')); $postdata['dateto'] = $this->security->xss_clean($this->input->post('dateTo')); - } - else { // Setting default values at first load of page - $postdata['qsl'] = 1; - $postdata['lotw'] = 1; - $postdata['eqsl'] = 0; - $postdata['qrz'] = 0; - $postdata['worked'] = 1; - $postdata['confirmed'] = 1; - $postdata['notworked'] = 1; - $postdata['band'] = 'All'; + } + else { // Setting default values at first load of page + $postdata['qsl'] = 1; + $postdata['lotw'] = 1; + $postdata['eqsl'] = NULL; + $postdata['qrz'] = NULL; + $postdata['clublog'] = NULL; + $postdata['worked'] = 1; + $postdata['confirmed'] = 1; + $postdata['notworked'] = 1; + $postdata['band'] = 'All'; $postdata['mode'] = 'All'; $postdata['datefrom'] = null; $postdata['dateto'] = null; - } + } if ($logbooks_locations_array) { $location_list = "'".implode("','",$logbooks_locations_array)."'"; - $data['cq_array'] = $this->cq->get_cq_array($bands, $postdata, $location_list); - $data['cq_summary'] = $this->cq->get_cq_summary($bands, $postdata, $location_list); + $cq_result = $this->cq->get_cq_array($bands, $postdata, $location_list); + // Extract bands data and summary from the result + $data['cq_array'] = ($cq_result && isset($cq_result['bands'])) ? $cq_result['bands'] : null; + $data['cq_summary'] = ($cq_result && isset($cq_result['summary'])) ? $cq_result['summary'] : null; } else { $location_list = null; $data['cq_array'] = null; @@ -1618,7 +1622,8 @@ class Awards extends CI_Controller { if ($logbooks_locations_array) { $location_list = "'".implode("','",$logbooks_locations_array)."'"; - $cq_array = $this->cq->get_cq_array($bands, $postdata, $location_list, $this->user_map_color_qso, $this->user_map_color_qsoconfirm); + $cq_result = $this->cq->get_cq_array($bands, $postdata, $location_list); + $cq_array = ($cq_result && isset($cq_result['bands'])) ? $cq_result['bands'] : null; } else { $location_list = null; $cq_array = null; diff --git a/application/models/Cq.php b/application/models/Cq.php index 8632ba971..d5966bd73 100644 --- a/application/models/Cq.php +++ b/application/models/Cq.php @@ -22,124 +22,190 @@ class CQ extends CI_Model{ } } - // Get all worked zones for all bands in ONE query - if ($postdata['worked'] != NULL) { - $cqBand = $this->getCQWorkedAllBands($location_list, $bands, $postdata); - foreach ($cqBand as $line) { - $band = $line->col_band; - $bandCq[$line->col_cqz][$band] = '
col_cqz) . '","' . $band . '","All", "All","'. $postdata['mode'] . '","CQZone","")\'>W
'; - $cqZ[$line->col_cqz]['count']++; + // Initialize summary counters only for the bands passed in + foreach ($bands as $band) { + $summary['worked'][$band] = 0; + $summary['confirmed'][$band] = 0; + } + $summary['worked']['Total'] = 0; + $summary['confirmed']['Total'] = 0; + + // Track unique zone/band combinations for totals + $workedZones = []; // [band][zone] = true + $confirmedZones = []; // [band][zone] = true + + // Create a lookup array for valid bands + $validBands = array_flip($bands); // ['160m' => true, '80m' => true, etc] + + $cqdata = $this->getCqZoneData($location_list, $postdata); + $cqdata_sat = $this->getCqZoneDataSat($location_list, $postdata); + + foreach ($cqdata as $cq) { + // Skip if this band is not in our requested bands list + if (!isset($validBands[$cq->col_band])) { + continue; + } + + $cqZ[$cq->col_cqz]['count']++; // Count each cq zone + + // Check if confirmed based on the confirmation types selected in postdata + $isConfirmed = false; + $confirmationLetters = ''; + if (isset($postdata['qsl']) && $postdata['qsl'] == 1 && $cq->qsl == 1) { + $isConfirmed = true; + $confirmationLetters .= 'Q'; + } + if (isset($postdata['lotw']) && $postdata['lotw'] == 1 && $cq->lotw == 1) { + $isConfirmed = true; + $confirmationLetters .= 'L'; + } + if (isset($postdata['eqsl']) && $postdata['eqsl'] == 1 && $cq->eqsl == 1) { + $isConfirmed = true; + $confirmationLetters .= 'E'; + } + if (isset($postdata['qrz']) && $postdata['qrz'] == 1 && $cq->qrz == 1) { + $isConfirmed = true; + $confirmationLetters .= 'Z'; + } + if (isset($postdata['clublog']) && $postdata['clublog'] == 1 && $cq->clublog == 1) { + $isConfirmed = true; + $confirmationLetters .= 'C'; + } + + if ($isConfirmed) { + $bandCq[$cq->col_cqz][$cq->col_band] = '
col_cqz) . '","' . $cq->col_band . '","All", "All","'. $postdata['mode'] . '","CQZone","'.$qsl.'")\'>' . $confirmationLetters . '
'; + // Track confirmed zones for summary + if (!isset($confirmedZones[$cq->col_band][$cq->col_cqz])) { + $confirmedZones[$cq->col_band][$cq->col_cqz] = true; + $summary['confirmed'][$cq->col_band]++; + } + } else { + $bandCq[$cq->col_cqz][$cq->col_band] = '
col_cqz) . '","' . $cq->col_band . '","All", "All","'. $postdata['mode'] . '","CQZone","")\'>W
'; + } + + // Track worked zones for summary + if (!isset($workedZones[$cq->col_band][$cq->col_cqz])) { + $workedZones[$cq->col_band][$cq->col_cqz] = true; + $summary['worked'][$cq->col_band]++; } } - // Get all confirmed zones for all bands in ONE query - if ($postdata['confirmed'] != NULL) { - $cqBand = $this->getCQConfirmedAllBands($location_list, $bands, $postdata); - foreach ($cqBand as $line) { - $band = $line->col_band; - $bandCq[$line->col_cqz][$band] = '
col_cqz) . '","' . $band . '","All", "All","'. $postdata['mode'] . '","CQZone","'.$qsl.'")\'>C
'; - $cqZ[$line->col_cqz]['count']++; + foreach ($cqdata_sat as $cq) { + // Skip if this band is not in our requested bands list + if (!isset($validBands[$cq->col_band])) { + continue; + } + + $cqZ[$cq->col_cqz]['count']++; // Count each cq zone + + // Check if confirmed based on the confirmation types selected in postdata + $isConfirmed = false; + $confirmationLetters = ''; + if (isset($postdata['qsl']) && $postdata['qsl'] == 1 && $cq->qsl == 1) { + $isConfirmed = true; + $confirmationLetters .= 'Q'; + } + if (isset($postdata['lotw']) && $postdata['lotw'] == 1 && $cq->lotw == 1) { + $isConfirmed = true; + $confirmationLetters .= 'L'; + } + if (isset($postdata['eqsl']) && $postdata['eqsl'] == 1 && $cq->eqsl == 1) { + $isConfirmed = true; + $confirmationLetters .= 'E'; + } + if (isset($postdata['qrz']) && $postdata['qrz'] == 1 && $cq->qrz == 1) { + $isConfirmed = true; + $confirmationLetters .= 'Z'; + } + if (isset($postdata['clublog']) && $postdata['clublog'] == 1 && $cq->clublog == 1) { + $isConfirmed = true; + $confirmationLetters .= 'C'; + } + + if ($isConfirmed) { + $bandCq[$cq->col_cqz][$cq->col_band] = '
col_cqz) . '","' . $cq->col_band . '","All", "All","'. $postdata['mode'] . '","CQZone","'.$qsl.'")\'>' . $confirmationLetters . '
'; + // Track confirmed zones for summary + if (!isset($confirmedZones[$cq->col_band][$cq->col_cqz])) { + $confirmedZones[$cq->col_band][$cq->col_cqz] = true; + $summary['confirmed'][$cq->col_band]++; + } + } else { + $bandCq[$cq->col_cqz][$cq->col_band] = '
col_cqz) . '","' . $cq->col_band . '","All", "All","'. $postdata['mode'] . '","CQZone","")\'>W
'; + } + + // Track worked zones for summary + if (!isset($workedZones[$cq->col_band][$cq->col_cqz])) { + $workedZones[$cq->col_band][$cq->col_cqz] = true; + $summary['worked'][$cq->col_band]++; } } - // We want to remove the worked zones in the list, since we do not want to display them - if ($postdata['worked'] == NULL) { - // Use optimized query for all bands at once - $cqBand = $this->getCQWorkedAllBands($location_list, $bands, $postdata); - foreach ($cqBand as $line) { - unset($bandCq[$line->col_cqz]); + // Calculate totals across all bands (excluding SAT) + $totalWorkedZones = []; + $totalConfirmedZones = []; + foreach ($workedZones as $band => $zones) { + // Skip SAT for totals + if ($band === 'SAT') { + continue; + } + foreach ($zones as $zone => $true) { + if (!isset($totalWorkedZones[$zone])) { + $totalWorkedZones[$zone] = true; + $summary['worked']['Total']++; + } + } + } + foreach ($confirmedZones as $band => $zones) { + // Skip SAT for totals + if ($band === 'SAT') { + continue; + } + foreach ($zones as $zone => $true) { + if (!isset($totalConfirmedZones[$zone])) { + $totalConfirmedZones[$zone] = true; + $summary['confirmed']['Total']++; + } } } - // We want to remove the confirmed zones in the list, since we do not want to display them - if ($postdata['confirmed'] == NULL) { - // Use optimized query for all bands at once - $cqBand = $this->getCQConfirmedAllBands($location_list, $bands, $postdata); - foreach ($cqBand as $line) { - unset($bandCq[$line->col_cqz]); + // Remove zones based on postdata filters + for ($i = 1; $i <= 40; $i++) { + // Remove not-worked zones if filter is disabled + if ($postdata['notworked'] == NULL && $cqZ[$i]['count'] == 0) { + unset($bandCq[$i]); + continue; } - } - if ($postdata['notworked'] == NULL) { - for ($i = 1; $i <= 40; $i++) { - if ($cqZ[$i]['count'] == 0) { - unset($bandCq[$i]); - }; + // Remove worked-only zones if filter is disabled + if ($postdata['worked'] == NULL && $cqZ[$i]['count'] > 0 && !isset($totalConfirmedZones[$i])) { + unset($bandCq[$i]); + continue; + } + + // Remove confirmed zones if filter is disabled + if ($postdata['confirmed'] == NULL && isset($totalConfirmedZones[$i])) { + unset($bandCq[$i]); + continue; } } if (isset($bandCq)) { - return $bandCq; + // Return both the band data and summary + return ['bands' => $bandCq, 'summary' => $summary]; } else { return 0; } } - /* - * Function returns all worked, but not confirmed states - * $postdata contains data from the form, in this case Lotw or QSL are used - */ - function getCQWorked($location_list, $band, $postdata) { + function getCqZoneData($location_list, $postdata) { $bindings=[]; - $sql = "SELECT distinct col_cqz FROM " . $this->config->item('table_name') . " thcv - where station_id in (" . $location_list . ") and col_cqz <= 40 and col_cqz <> ''"; - - if ($postdata['mode'] != 'All') { - $sql .= " and (col_mode = ? or col_submode = ?)"; - $bindings[]=$postdata['mode']; - $bindings[]=$postdata['mode']; - } - - if ($postdata['datefrom'] != NULL) { - $sql .= " and col_time_on >= ?"; - $bindings[]=$postdata['datefrom'] . ' 00:00:00'; - } - - if ($postdata['dateto'] != NULL) { - $sql .= " and col_time_on <= ?"; - $bindings[]=$postdata['dateto'] . ' 23:59:59'; - } - - $sql .= $this->genfunctions->addBandToQuery($band,$bindings); - - $sql .= " and not exists (select 1 from " . $this->config->item('table_name') . - " where station_id in (" . $location_list . - ") and col_cqz = thcv.col_cqz and col_cqz <> '' "; - - if ($postdata['mode'] != 'All') { - $sql .= " and (col_mode = ? or col_submode = ?)"; - $bindings[]=$postdata['mode']; - $bindings[]=$postdata['mode']; - } - - if ($postdata['datefrom'] != NULL) { - $sql .= " and col_time_on >= ?"; - $bindings[]=$postdata['datefrom'] . ' 00:00:00'; - } - - if ($postdata['dateto'] != NULL) { - $sql .= " and col_time_on <= ?"; - $bindings[]=$postdata['dateto'] . ' 23:59:59'; - } - - $sql .= $this->genfunctions->addBandToQuery($band,$bindings); - - $sql .= $this->genfunctions->addQslToQuery($postdata); - - $sql .= ")"; - - $query = $this->db->query($sql,$bindings); - - return $query->result(); - } - - /* - * Function returns all confirmed states on given band and on LoTW or QSL - * $postdata contains data from the form, in this case Lotw or QSL are used - */ - function getCQConfirmed($location_list, $band, $postdata) { - $bindings=[]; - $sql = "SELECT distinct col_cqz FROM " . $this->config->item('table_name') . " thcv + $sql = "SELECT thcv.col_cqz, thcv.col_band, + MAX(case when thcv.col_lotw_qsl_rcvd ='Y' then 1 else 0 end) as lotw, + MAX(case when thcv.col_qsl_rcvd = 'Y' then 1 else 0 end) as qsl, + MAX(case when thcv.col_eqsl_qsl_rcvd = 'Y' then 1 else 0 end) as eqsl, + MAX(case when thcv.COL_QRZCOM_QSO_DOWNLOAD_STATUS= 'Y' then 1 else 0 end) as qrz, + MAX(case when thcv.COL_CLUBLOG_QSO_DOWNLOAD_STATUS = 'Y' then 1 else 0 end) as clublog + FROM " . $this->config->item('table_name') . " thcv where station_id in (" . $location_list . ") and col_cqz <= 40 and col_cqz <> ''"; if ($postdata['mode'] != 'All') { @@ -158,108 +224,45 @@ class CQ extends CI_Model{ $bindings[]=$postdata['dateto'] . ' 23:59:59'; } - $sql .= $this->genfunctions->addBandToQuery($band,$bindings); + $sql .= " and col_prop_mode != 'SAT'"; - $sql .= $this->genfunctions->addQslToQuery($postdata); + $sql .= " GROUP BY thcv.col_cqz, thcv.col_band"; $query = $this->db->query($sql,$bindings); return $query->result(); } - - /* - * Function returns all worked (but not confirmed) states for ALL bands in one query - * Returns both col_cqz and col_band to avoid N+1 queries - */ - function getCQWorkedAllBands($location_list, $bands, $postdata) { + function getCqZoneDataSat($location_list, $postdata) { $bindings=[]; - $sql = "SELECT DISTINCT col_cqz, col_band FROM " . $this->config->item('table_name') . " thcv - WHERE station_id IN (" . $location_list . ") - AND col_cqz <= 40 AND col_cqz <> '' - AND col_band IN ('" . implode("','", $bands) . "')"; + $sql = "SELECT thcv.col_cqz, 'SAT' as col_band, + MAX(case when thcv.col_lotw_qsl_rcvd ='Y' then 1 else 0 end) as lotw, + MAX(case when thcv.col_qsl_rcvd = 'Y' then 1 else 0 end) as qsl, + MAX(case when thcv.col_eqsl_qsl_rcvd = 'Y' then 1 else 0 end) as eqsl, + MAX(case when thcv.COL_QRZCOM_QSO_DOWNLOAD_STATUS= 'Y' then 1 else 0 end) as qrz, + MAX(case when thcv.COL_CLUBLOG_QSO_DOWNLOAD_STATUS = 'Y' then 1 else 0 end) as clublog + FROM " . $this->config->item('table_name') . " thcv + where station_id in (" . $location_list . ") and col_cqz <= 40 and col_cqz <> ''"; if ($postdata['mode'] != 'All') { - $sql .= " AND (col_mode = ? OR col_submode = ?)"; + $sql .= " and (col_mode = ? or col_submode = ?)"; $bindings[]=$postdata['mode']; $bindings[]=$postdata['mode']; } if ($postdata['datefrom'] != NULL) { - $sql .= " AND col_time_on >= ?"; + $sql .= " and col_time_on >= ?"; $bindings[]=$postdata['datefrom'] . ' 00:00:00'; } if ($postdata['dateto'] != NULL) { - $sql .= " AND col_time_on <= ?"; + $sql .= " and col_time_on <= ?"; $bindings[]=$postdata['dateto'] . ' 23:59:59'; } - $sql .= " AND col_prop_mode != 'SAT'"; + $sql .= " and col_prop_mode = 'SAT'"; - // Optimized NOT IN subquery instead of NOT EXISTS - /*$sql .= " AND col_cqz NOT IN ( - SELECT col_cqz FROM " . $this->config->item('table_name') . " - WHERE station_id IN (" . $location_list . ") - AND col_cqz <> '' - AND col_band IN ('" . implode("','", $bands) . "') - AND col_prop_mode != 'SAT'"; - - if ($postdata['mode'] != 'All') { - $sql .= " AND (col_mode = ? OR col_submode = ?)"; - $bindings[]=$postdata['mode']; - $bindings[]=$postdata['mode']; - } - - if ($postdata['datefrom'] != NULL) { - $sql .= " AND col_time_on >= ?"; - $bindings[]=$postdata['datefrom'] . ' 00:00:00'; - } - - if ($postdata['dateto'] != NULL) { - $sql .= " AND col_time_on <= ?"; - $bindings[]=$postdata['dateto'] . ' 23:59:59'; - } - - $sql .= $this->genfunctions->addQslToQuery($postdata); - - $sql .= ")";*/ - - $query = $this->db->query($sql,$bindings); - - return $query->result(); - } - - /* - * Function returns all confirmed states for ALL bands in one query - * Returns both col_cqz and col_band to avoid N+1 queries - */ - function getCQConfirmedAllBands($location_list, $bands, $postdata) { - $bindings=[]; - $sql = "SELECT DISTINCT col_cqz, col_band FROM " . $this->config->item('table_name') . " thcv - WHERE station_id IN (" . $location_list . ") - AND col_cqz <= 40 AND col_cqz <> '' - AND col_band IN ('" . implode("','", $bands) . "')"; - - if ($postdata['mode'] != 'All') { - $sql .= " AND (col_mode = ? OR col_submode = ?)"; - $bindings[]=$postdata['mode']; - $bindings[]=$postdata['mode']; - } - - if ($postdata['datefrom'] != NULL) { - $sql .= " AND col_time_on >= ?"; - $bindings[]=$postdata['datefrom'] . ' 00:00:00'; - } - - if ($postdata['dateto'] != NULL) { - $sql .= " AND col_time_on <= ?"; - $bindings[]=$postdata['dateto'] . ' 23:59:59'; - } - - $sql .= " AND col_prop_mode != 'SAT'"; - - $sql .= $this->genfunctions->addQslToQuery($postdata); + $sql .= " GROUP BY thcv.col_cqz"; $query = $this->db->query($sql,$bindings); @@ -268,34 +271,23 @@ class CQ extends CI_Model{ /* * Function gets worked and confirmed summary on each band on the active stationprofile - * Optimized to use just 2 queries instead of N queries per band + * Now uses data from get_cq_array instead of separate queries - much more efficient! */ function get_cq_summary($bands, $postdata, $location_list) { - $bandslots = $this->bands->get_worked_bands('cq'); + $result = $this->get_cq_array($bands, $postdata, $location_list); - foreach ($bandslots as $band) { + if ($result && isset($result['summary'])) { + return $result['summary']; + } + + // Fallback to empty structure if something went wrong + $cqSummary = []; + foreach ($bands as $band) { $cqSummary['worked'][$band] = '-'; $cqSummary['confirmed'][$band] = '-'; } - - // Get all worked counts in ONE query - $workedAll = $this->getSummaryByBandAllBands($bands, $postdata, $location_list, $bandslots); - foreach ($workedAll as $row) { - $cqSummary['worked'][$row->col_band] = $row->count; - } - - // Get all confirmed counts in ONE query - $confirmedAll = $this->getSummaryByBandConfirmedAllBands($bands, $postdata, $location_list, $bandslots); - foreach ($confirmedAll as $row) { - $cqSummary['confirmed'][$row->col_band] = $row->count; - } - - - $workedTotal = $this->getSummaryByBand($postdata['band'], $postdata, $location_list, $bandslots); - $confirmedTotal = $this->getSummaryByBandConfirmed($postdata['band'], $postdata, $location_list, $bandslots); - - $cqSummary['worked']['Total'] = $workedTotal[0]->count; - $cqSummary['confirmed']['Total'] = $confirmedTotal[0]->count; + $cqSummary['worked']['Total'] = '-'; + $cqSummary['confirmed']['Total'] = '-'; return $cqSummary; } @@ -345,123 +337,4 @@ class CQ extends CI_Model{ return $query->result(); } - function getSummaryByBandConfirmed($band, $postdata, $location_list, $bandslots){ - $bindings=[]; - $sql = "SELECT count(distinct thcv.col_cqz) as count FROM " . $this->config->item('table_name') . " thcv"; - - $sql .= " where station_id in (" . $location_list . ') and col_cqz <= 40 and col_cqz > 0'; - - if ($band == 'SAT') { - $sql .= " and thcv.col_prop_mode = ?"; - $bindings[]=$band; - } else if ($band == 'All') { - $this->load->model('bands'); - - // $bandslots = $this->bands->get_worked_bands('cq'); - - $bandslots_list = "'".implode("','",$bandslots)."'"; - - $sql .= " and thcv.col_band in (" . $bandslots_list . ")" . - " and thcv.col_prop_mode !='SAT'"; - } else { - $sql .= " and thcv.col_prop_mode !='SAT'"; - $sql .= " and thcv.col_band = ?"; - $bindings[]=$band; - } - - if ($postdata['mode'] != 'All') { - $sql .= " and (col_mode = ? or col_submode = ?)"; - $bindings[]=$postdata['mode']; - $bindings[]=$postdata['mode']; - } - - if ($postdata['datefrom'] != NULL) { - $sql .= " and col_time_on >= ?"; - $bindings[]=$postdata['datefrom'] . ' 00:00:00'; - } - - if ($postdata['dateto'] != NULL) { - $sql .= " and col_time_on <= ?"; - $bindings[]=$postdata['dateto'] . ' 23:59:59'; - } - - $sql .= $this->genfunctions->addQslToQuery($postdata); - - $query = $this->db->query($sql,$bindings); - - return $query->result(); - } - - /* - * Gets worked CQ zone counts for ALL bands in one query using GROUP BY - * Returns col_band and count for each band - */ - function getSummaryByBandAllBands($bands, $postdata, $location_list, $bandslots) { - $bindings=[]; - $sql = "SELECT col_band, COUNT(DISTINCT thcv.col_cqz) as count FROM " . $this->config->item('table_name') . " thcv"; - - $sql .= " WHERE station_id IN (" . $location_list . ') AND col_cqz <= 40 AND col_cqz > 0'; - $sql .= " AND col_band IN ('" . implode("','", $bands) . "')"; - $sql .= " AND col_prop_mode != 'SAT'"; - - if ($postdata['mode'] != 'All') { - $sql .= " AND (col_mode = ? OR col_submode = ?)"; - $bindings[]=$postdata['mode']; - $bindings[]=$postdata['mode']; - } - - if ($postdata['datefrom'] != NULL) { - $sql .= " AND col_time_on >= ?"; - $bindings[]=$postdata['datefrom'] . ' 00:00:00'; - } - - if ($postdata['dateto'] != NULL) { - $sql .= " AND col_time_on <= ?"; - $bindings[]=$postdata['dateto'] . ' 23:59:59'; - } - - $sql .= " GROUP BY col_band"; - - $query = $this->db->query($sql,$bindings); - - return $query->result(); - } - - /* - * Gets confirmed CQ zone counts for ALL bands in one query using GROUP BY - * Returns col_band and count for each band - */ - function getSummaryByBandConfirmedAllBands($bands, $postdata, $location_list, $bandslots) { - $bindings=[]; - $sql = "SELECT col_band, COUNT(DISTINCT thcv.col_cqz) as count FROM " . $this->config->item('table_name') . " thcv"; - - $sql .= " WHERE station_id IN (" . $location_list . ') AND col_cqz <= 40 AND col_cqz > 0'; - $sql .= " AND col_band IN ('" . implode("','", $bands) . "')"; - $sql .= " AND col_prop_mode != 'SAT'"; - - if ($postdata['mode'] != 'All') { - $sql .= " AND (col_mode = ? OR col_submode = ?)"; - $bindings[]=$postdata['mode']; - $bindings[]=$postdata['mode']; - } - - if ($postdata['datefrom'] != NULL) { - $sql .= " AND col_time_on >= ?"; - $bindings[]=$postdata['datefrom'] . ' 00:00:00'; - } - - if ($postdata['dateto'] != NULL) { - $sql .= " AND col_time_on <= ?"; - $bindings[]=$postdata['dateto'] . ' 23:59:59'; - } - - $sql .= $this->genfunctions->addQslToQuery($postdata); - - $sql .= " GROUP BY col_band"; - - $query = $this->db->query($sql,$bindings); - - return $query->result(); - } - } diff --git a/application/views/awards/cq/index.php b/application/views/awards/cq/index.php index e48984808..b002eac0f 100644 --- a/application/views/awards/cq/index.php +++ b/application/views/awards/cq/index.php @@ -113,14 +113,18 @@ input->post('lotw', TRUE) || $this->input->method() !== 'post') echo ' checked="checked"'; ?> > -
+
input->post('eqsl', TRUE)) echo ' checked="checked"'; ?> >
-
+
input->post('qrz', TRUE)) echo ' checked="checked"'; ?> >
+
+ input->post('clublog', TRUE)) echo ' checked="checked"'; ?> > + +
@@ -185,6 +189,13 @@ '.__("(Q)SL-Paper-Card").", "; + echo __("(L)oTW").", "; + echo __("(e)QSL").", "; + echo __('QR(Z)-"confirmation"').", "; + echo __("(C)lublog").", "; + echo __("(W)orked").''; echo " From e1f7f23a6467917934a31af544300ec833ba593f Mon Sep 17 00:00:00 2001 From: Andreas Kristiansen <6977712+AndreasK79@users.noreply.github.com> Date: Tue, 24 Feb 2026 09:43:42 +0100 Subject: [PATCH 03/12] Fixed map --- application/controllers/Awards.php | 44 ++++++++++++------------------ application/models/Cq.php | 17 +++++++++++- 2 files changed, 33 insertions(+), 28 deletions(-) diff --git a/application/controllers/Awards.php b/application/controllers/Awards.php index 168d5adac..dd3ed5957 100644 --- a/application/controllers/Awards.php +++ b/application/controllers/Awards.php @@ -1604,8 +1604,20 @@ class Awards extends CI_Controller { $logbooks_locations_array = $this->logbooks_model->list_logbook_relationships($this->session->userdata('active_station_logbook')); $this->load->model('cq'); + $this->load->model('bands'); - $bands[] = $this->input->post('band'); + $data['worked_bands'] = $this->bands->get_worked_bands('cq'); + + if ($this->input->post('band') == 'All') { // Did the user specify a band? If not, use all bands + $bands = $data['worked_bands']; + } + else { + $bands[] = $this->input->post('band'); + } + + // $data['bands'] = $bands; // Used for displaying selected band(s) in the table in the view + + // $bands[] = $this->input->post('band'); $postdata['qsl'] = $this->input->post('qsl') == 0 ? NULL: 1; $postdata['lotw'] = $this->input->post('lotw') == 0 ? NULL: 1; @@ -1617,37 +1629,15 @@ class Awards extends CI_Controller { $postdata['notworked'] = $this->input->post('notworked') == 0 ? NULL: 1; $postdata['band'] = $this->security->xss_clean($this->input->post('band')); $postdata['mode'] = $this->security->xss_clean($this->input->post('mode')); - $postdata['datefrom'] = $this->security->xss_clean($this->input->post('datefrom')); - $postdata['dateto'] = $this->security->xss_clean($this->input->post('dateto')); + $postdata['datefrom'] = $this->security->xss_clean($this->input->post('dateFrom')); + $postdata['dateto'] = $this->security->xss_clean($this->input->post('dateTo')); if ($logbooks_locations_array) { $location_list = "'".implode("','",$logbooks_locations_array)."'"; - $cq_result = $this->cq->get_cq_array($bands, $postdata, $location_list); - $cq_array = ($cq_result && isset($cq_result['bands'])) ? $cq_result['bands'] : null; + $zones = $this->cq->get_cq_array($bands, $postdata, $location_list, true); } else { $location_list = null; - $cq_array = null; - } - - $zones = array(); - - foreach ($cq_array as $cq => $value) { - foreach ($value as $key) { - if($key != "") { - if (strpos($key, '>W<') !== false) { - $zones[] = 'W'; - break; - } - if (strpos($key, '>C<') !== false) { - $zones[] = 'C'; - break; - } - if (strpos($key, '-') !== false) { - $zones[] = '-'; - break; - } - } - } + $zones = array(); } header('Content-Type: application/json'); diff --git a/application/models/Cq.php b/application/models/Cq.php index d5966bd73..de1772676 100644 --- a/application/models/Cq.php +++ b/application/models/Cq.php @@ -6,7 +6,7 @@ class CQ extends CI_Model{ $this->load->library('Genfunctions'); } - function get_cq_array($bands, $postdata, $location_list) { + function get_cq_array($bands, $postdata, $location_list, $map = false) { $cqZ = array(); // Used for keeping track of which states that are not worked for ($i = 1; $i <= 40; $i++) { @@ -189,6 +189,21 @@ class CQ extends CI_Model{ } } + // If this is for the map, return simplified format + if ($map) { + $mapZones = []; + for ($i = 1; $i <= 40; $i++) { + if ($cqZ[$i]['count'] == 0) { + $mapZones[$i-1] = '-'; // Not worked + } elseif (isset($totalConfirmedZones[$i])) { + $mapZones[$i-1] = 'C'; // Confirmed + } else { + $mapZones[$i-1] = 'W'; // Worked but not confirmed + } + } + return $mapZones; + } + if (isset($bandCq)) { // Return both the band data and summary return ['bands' => $bandCq, 'summary' => $summary]; From 10e66bbdad9365887c6056d0656ecd164266fa0d Mon Sep 17 00:00:00 2001 From: Andreas Kristiansen <6977712+AndreasK79@users.noreply.github.com> Date: Tue, 24 Feb 2026 10:00:07 +0100 Subject: [PATCH 04/12] Removed unused functions --- application/models/Cq.php | 68 --------------------------------------- 1 file changed, 68 deletions(-) diff --git a/application/models/Cq.php b/application/models/Cq.php index de1772676..36c3243df 100644 --- a/application/models/Cq.php +++ b/application/models/Cq.php @@ -284,72 +284,4 @@ class CQ extends CI_Model{ return $query->result(); } - /* - * Function gets worked and confirmed summary on each band on the active stationprofile - * Now uses data from get_cq_array instead of separate queries - much more efficient! - */ - function get_cq_summary($bands, $postdata, $location_list) { - $result = $this->get_cq_array($bands, $postdata, $location_list); - - if ($result && isset($result['summary'])) { - return $result['summary']; - } - - // Fallback to empty structure if something went wrong - $cqSummary = []; - foreach ($bands as $band) { - $cqSummary['worked'][$band] = '-'; - $cqSummary['confirmed'][$band] = '-'; - } - $cqSummary['worked']['Total'] = '-'; - $cqSummary['confirmed']['Total'] = '-'; - - return $cqSummary; - } - - function getSummaryByBand($band, $postdata, $location_list, $bandslots) { - $bindings=[]; - $sql = "SELECT count(distinct thcv.col_cqz) as count FROM " . $this->config->item('table_name') . " thcv"; - - $sql .= " where station_id in (" . $location_list . ') and col_cqz <= 40 and col_cqz > 0'; - - if ($band == 'SAT') { - $sql .= " and thcv.col_prop_mode = ?"; - $bindings[]=$band; - } else if ($band == 'All') { - $this->load->model('bands'); - - // $bandslots = $this->bands->get_worked_bands('cq'); - - $bandslots_list = "'".implode("','",$bandslots)."'"; - - $sql .= " and thcv.col_band in (" . $bandslots_list . ")" . - " and thcv.col_prop_mode !='SAT'"; - } else { - $sql .= " and thcv.col_prop_mode !='SAT'"; - $sql .= " and thcv.col_band = ?"; - $bindings[]=$band; - } - - if ($postdata['mode'] != 'All') { - $sql .= " and (col_mode = ? or col_submode = ?)"; - $bindings[]=$postdata['mode']; - $bindings[]=$postdata['mode']; - } - - if ($postdata['datefrom'] != NULL) { - $sql .= " and col_time_on >= ?"; - $bindings[]=$postdata['datefrom'] . ' 00:00:00'; - } - - if ($postdata['dateto'] != NULL) { - $sql .= " and col_time_on <= ?"; - $bindings[]=$postdata['dateto'] . ' 23:59:59'; - } - - $query = $this->db->query($sql,$bindings); - - return $query->result(); - } - } From c0e97984ed96be968b8c4c61779903f13388465a Mon Sep 17 00:00:00 2001 From: Andreas Kristiansen <6977712+AndreasK79@users.noreply.github.com> Date: Tue, 24 Feb 2026 10:05:49 +0100 Subject: [PATCH 05/12] Removed commented out stuff --- application/controllers/Awards.php | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/application/controllers/Awards.php b/application/controllers/Awards.php index dd3ed5957..e94f8dfcf 100644 --- a/application/controllers/Awards.php +++ b/application/controllers/Awards.php @@ -1604,21 +1604,17 @@ class Awards extends CI_Controller { $logbooks_locations_array = $this->logbooks_model->list_logbook_relationships($this->session->userdata('active_station_logbook')); $this->load->model('cq'); - $this->load->model('bands'); + $this->load->model('bands'); $data['worked_bands'] = $this->bands->get_worked_bands('cq'); - if ($this->input->post('band') == 'All') { // Did the user specify a band? If not, use all bands + if ($this->input->post('band') == 'All') { $bands = $data['worked_bands']; } else { $bands[] = $this->input->post('band'); } - // $data['bands'] = $bands; // Used for displaying selected band(s) in the table in the view - - // $bands[] = $this->input->post('band'); - $postdata['qsl'] = $this->input->post('qsl') == 0 ? NULL: 1; $postdata['lotw'] = $this->input->post('lotw') == 0 ? NULL: 1; $postdata['eqsl'] = $this->input->post('eqsl') == 0 ? NULL: 1; From e491772589157ceddf765b17e0ef69abac92d935 Mon Sep 17 00:00:00 2001 From: Andreas Kristiansen <6977712+AndreasK79@users.noreply.github.com> Date: Tue, 24 Feb 2026 22:13:30 +0100 Subject: [PATCH 06/12] Hide total if Band = SAT --- application/controllers/Awards.php | 2 ++ application/views/awards/cq/index.php | 20 ++++++++++++++------ 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/application/controllers/Awards.php b/application/controllers/Awards.php index e94f8dfcf..6ccffc138 100644 --- a/application/controllers/Awards.php +++ b/application/controllers/Awards.php @@ -695,6 +695,8 @@ class Awards extends CI_Controller { $postdata['dateto'] = null; } + $data['posted_band'] = $postdata['band']; + if ($logbooks_locations_array) { $location_list = "'".implode("','",$logbooks_locations_array)."'"; $cq_result = $this->cq->get_cq_array($bands, $postdata, $location_list); diff --git a/application/views/awards/cq/index.php b/application/views/awards/cq/index.php index b002eac0f..f55bbe32e 100644 --- a/application/views/awards/cq/index.php +++ b/application/views/awards/cq/index.php @@ -227,20 +227,28 @@ foreach($bands as $band) { echo ''; } - echo " - + if ($posted_band != 'SAT') { + echo ""; + } + echo ""; - foreach ($cq_summary['worked'] as $dxcc) { // Fills the table with the data - echo ''; + foreach ($cq_summary['worked'] as $cqz => $value) { // Fills the table with the data + if ($posted_band == 'SAT' && $cqz == 'Total') { + continue; + } + echo ''; } echo ""; - foreach ($cq_summary['confirmed'] as $dxcc) { // Fills the table with the data - echo ''; + foreach ($cq_summary['confirmed'] as $cqz => $value) { // Fills the table with the data + if ($posted_band == 'SAT' && $cqz == 'Total') { + continue; + } + echo ''; } echo ' From 775973c61413eea5e54e5f351754468badbdef19 Mon Sep 17 00:00:00 2001 From: Andreas Kristiansen <6977712+AndreasK79@users.noreply.github.com> Date: Wed, 25 Feb 2026 06:55:39 +0100 Subject: [PATCH 07/12] Fix sat for map --- application/models/Cq.php | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/application/models/Cq.php b/application/models/Cq.php index 36c3243df..5b22615d0 100644 --- a/application/models/Cq.php +++ b/application/models/Cq.php @@ -192,13 +192,25 @@ class CQ extends CI_Model{ // If this is for the map, return simplified format if ($map) { $mapZones = []; - for ($i = 1; $i <= 40; $i++) { - if ($cqZ[$i]['count'] == 0) { - $mapZones[$i-1] = '-'; // Not worked - } elseif (isset($totalConfirmedZones[$i])) { - $mapZones[$i-1] = 'C'; // Confirmed - } else { - $mapZones[$i-1] = 'W'; // Worked but not confirmed + if ($bands[0] == 'SAT') { + for ($i = 1; $i <= 40; $i++) { + if ($cqZ[$i]['count'] == 0) { + $mapZones[$i-1] = '-'; // Not worked + } elseif (isset($confirmedZones['SAT'][$i])) { + $mapZones[$i-1] = 'C'; // Confirmed + } else { + $mapZones[$i-1] = 'W'; // Worked but not confirmed + } + } + } else { + for ($i = 1; $i <= 40; $i++) { + if ($cqZ[$i]['count'] == 0) { + $mapZones[$i-1] = '-'; // Not worked + } elseif (isset($totalConfirmedZones[$i])) { + $mapZones[$i-1] = 'C'; // Confirmed + } else { + $mapZones[$i-1] = 'W'; // Worked but not confirmed + } } } return $mapZones; From a9d7fc222c2b98385d120299b7fb37237a291ad2 Mon Sep 17 00:00:00 2001 From: Andreas Kristiansen <6977712+AndreasK79@users.noreply.github.com> Date: Wed, 25 Feb 2026 06:57:25 +0100 Subject: [PATCH 08/12] Fix total for map --- application/models/Cq.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/application/models/Cq.php b/application/models/Cq.php index 5b22615d0..d06aafa4f 100644 --- a/application/models/Cq.php +++ b/application/models/Cq.php @@ -204,12 +204,12 @@ class CQ extends CI_Model{ } } else { for ($i = 1; $i <= 40; $i++) { - if ($cqZ[$i]['count'] == 0) { - $mapZones[$i-1] = '-'; // Not worked - } elseif (isset($totalConfirmedZones[$i])) { + if (isset($totalConfirmedZones[$i])) { $mapZones[$i-1] = 'C'; // Confirmed - } else { + } else if (isset($totalWorkedZones[$i])) { $mapZones[$i-1] = 'W'; // Worked but not confirmed + } else { + $mapZones[$i-1] = '-'; // Not worked } } } From 3bd8a035345145beaf9e1374c915feab5b42f24f Mon Sep 17 00:00:00 2001 From: Andreas Kristiansen <6977712+AndreasK79@users.noreply.github.com> Date: Wed, 25 Feb 2026 08:16:05 +0100 Subject: [PATCH 09/12] Total in bold. Separate SAT column in summary --- application/views/awards/cq/index.php | 42 +++++++++++++++++++++------ 1 file changed, 33 insertions(+), 9 deletions(-) diff --git a/application/views/awards/cq/index.php b/application/views/awards/cq/index.php index f55bbe32e..5f42cf33e 100644 --- a/application/views/awards/cq/index.php +++ b/application/views/awards/cq/index.php @@ -224,32 +224,56 @@ "; - foreach($bands as $band) { - echo ''; - } - if ($posted_band != 'SAT') { - echo ""; - } + $addsat=''; + foreach($bands as $band) { + if ($band != 'SAT') { + echo ''; + } else { + $addsat=''; + } + } + echo ''; + if (count($bands) > 1) { + echo ''; + } + echo $addsat; echo ""; - + $sat_value = ''; foreach ($cq_summary['worked'] as $cqz => $value) { // Fills the table with the data if ($posted_band == 'SAT' && $cqz == 'Total') { continue; } - echo ''; + if ($cqz == 'SAT') { + $sat_value = ''; + } else { + echo ''; + } } + if (count($bands) > 1) { + echo ''; + } + echo $sat_value; echo ""; + $sat_value = ''; foreach ($cq_summary['confirmed'] as $cqz => $value) { // Fills the table with the data if ($posted_band == 'SAT' && $cqz == 'Total') { continue; } - echo ''; + if ($cqz == 'SAT') { + $sat_value = ''; + } else { + echo ''; + } } + if (count($bands) > 1) { + echo ''; + } + echo $sat_value; echo '
' . $band . '" . __("Total") . "
" . __("Total") . "
" . __("Total worked") . "' . $dxcc . '' . $value . '
" . __("Total confirmed") . "' . $dxcc . '' . $value . '
' . $band . '" . __("Total") . "
' . $band . '' . $band . '' . __("Total (ex SAT)") . '
" . __("Total worked") . "' . $value . '' . $value . '' . $value . '
" . __("Total confirmed") . "' . $value . '' . $value . '' . $value . '
From 6cd41f6715d64df9d181961b0df9163499219204 Mon Sep 17 00:00:00 2001 From: Andreas Kristiansen <6977712+AndreasK79@users.noreply.github.com> Date: Wed, 25 Feb 2026 08:29:05 +0100 Subject: [PATCH 10/12] Fix summary again. Add band in map legend --- application/views/awards/cq/index.php | 8 +++++--- assets/js/sections/cqmap.js | 2 ++ 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/application/views/awards/cq/index.php b/application/views/awards/cq/index.php index 5f42cf33e..7d06f01cf 100644 --- a/application/views/awards/cq/index.php +++ b/application/views/awards/cq/index.php @@ -232,7 +232,9 @@ $addsat='' . $band . ''; } } - echo '' . __("Total (ex SAT)") . ''; + if ($posted_band != 'SAT') { + echo '' . __("Total (ex SAT)") . ''; + } if (count($bands) > 1) { echo ''; } @@ -242,7 +244,7 @@ " . __("Total worked") . ""; $sat_value = ''; - foreach ($cq_summary['worked'] as $cqz => $value) { // Fills the table with the data + foreach ($cq_summary['worked'] as $cqz => $value) { if ($posted_band == 'SAT' && $cqz == 'Total') { continue; } @@ -260,7 +262,7 @@ echo " " . __("Total confirmed") . ""; $sat_value = ''; - foreach ($cq_summary['confirmed'] as $cqz => $value) { // Fills the table with the data + foreach ($cq_summary['confirmed'] as $cqz => $value) { if ($posted_band == 'SAT' && $cqz == 'Total') { continue; } diff --git a/assets/js/sections/cqmap.js b/assets/js/sections/cqmap.js index eb493716a..82ca2903c 100644 --- a/assets/js/sections/cqmap.js +++ b/assets/js/sections/cqmap.js @@ -119,6 +119,8 @@ function load_cq_map2(data) { legend.onAdd = function(map) { var div = L.DomUtil.create("div", "legend"); div.innerHTML += "

" + lang_general_word_colors + "

"; + var band = $('#band2').val(); + div.innerHTML += "

Band: " + band + "

"; div.innerHTML += "" + lang_general_word_confirmed + " (" + confirmed + ")
"; div.innerHTML += "" + lang_general_word_worked_not_confirmed + " (" + workednotconfirmed + ")
"; div.innerHTML += "" + lang_general_word_not_worked + " (" + notworked + ")
"; From 5205cdcad30322762cbdda7814547e6802d7cd9c Mon Sep 17 00:00:00 2001 From: Andreas Kristiansen <6977712+AndreasK79@users.noreply.github.com> Date: Wed, 25 Feb 2026 08:51:59 +0100 Subject: [PATCH 11/12] Update assets/js/sections/cqmap.js Co-authored-by: Florian (DF2ET) --- assets/js/sections/cqmap.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets/js/sections/cqmap.js b/assets/js/sections/cqmap.js index 82ca2903c..9641548e0 100644 --- a/assets/js/sections/cqmap.js +++ b/assets/js/sections/cqmap.js @@ -118,9 +118,9 @@ function load_cq_map2(data) { legend.onAdd = function(map) { var div = L.DomUtil.create("div", "legend"); - div.innerHTML += "

" + lang_general_word_colors + "

"; var band = $('#band2').val(); div.innerHTML += "

Band: " + band + "

"; + div.innerHTML += "

" + lang_general_word_colors + "

"; div.innerHTML += "" + lang_general_word_confirmed + " (" + confirmed + ")
"; div.innerHTML += "" + lang_general_word_worked_not_confirmed + " (" + workednotconfirmed + ")
"; div.innerHTML += "" + lang_general_word_not_worked + " (" + notworked + ")
"; From 321b19b9cdb19464c2b63c81181917c38933b5de Mon Sep 17 00:00:00 2001 From: Andreas Kristiansen <6977712+AndreasK79@users.noreply.github.com> Date: Wed, 25 Feb 2026 09:06:52 +0100 Subject: [PATCH 12/12] Remove the word color in legend --- assets/js/sections/cqmap.js | 1 - 1 file changed, 1 deletion(-) diff --git a/assets/js/sections/cqmap.js b/assets/js/sections/cqmap.js index 9641548e0..5b71bc50f 100644 --- a/assets/js/sections/cqmap.js +++ b/assets/js/sections/cqmap.js @@ -120,7 +120,6 @@ function load_cq_map2(data) { var div = L.DomUtil.create("div", "legend"); var band = $('#band2').val(); div.innerHTML += "

Band: " + band + "

"; - div.innerHTML += "

" + lang_general_word_colors + "

"; div.innerHTML += "" + lang_general_word_confirmed + " (" + confirmed + ")
"; div.innerHTML += "" + lang_general_word_worked_not_confirmed + " (" + workednotconfirmed + ")
"; div.innerHTML += "" + lang_general_word_not_worked + " (" + notworked + ")
";