diff --git a/application/controllers/Monthlyreport.php b/application/controllers/Monthlyreport.php index ce78fde4f..34423c0c4 100644 --- a/application/controllers/Monthlyreport.php +++ b/application/controllers/Monthlyreport.php @@ -121,6 +121,7 @@ class Monthlyreport extends CI_Controller { 'new_countries_satellite' => $report['new_dxcc_satellite'], 'new_countries_eme' => $report['new_dxcc_eme'], 'new_gridsquares' => $report['new_grids'], + 'new_gridsquares_by_band' => $report['new_grids_by_band'], 'new_gridsquares_hf' => $report['new_grids_hf'], 'new_gridsquares_satellite' => $report['new_grids_satellite'], 'new_gridsquares_eme' => $report['new_grids_eme'], @@ -129,7 +130,8 @@ class Monthlyreport extends CI_Controller { 'bands_used' => $report['bands'], 'continents_worked' => $report['continents'], 'satellite_qsos' => $report['satellite_qsos'], - 'eme_qsos' => $report['eme_qsos'] + 'eme_qsos' => $report['eme_qsos'], + 'satellite_breakdown' => $report['satellite_breakdown'] ), 'statistics' => array( 'qsos_per_day' => round($report['total_qsos'] / date('t', strtotime("$year-$month-01")), 2), @@ -202,7 +204,15 @@ class Monthlyreport extends CI_Controller { foreach ($report['new_dxcc_by_band'] as $band => $dxcc_list) { $text .= "\n{$band} (" . count($dxcc_list) . " new):\n"; foreach ($dxcc_list as $dxcc) { - $text .= " - {$dxcc['name']}\n"; + $text .= " - {$dxcc['name']}"; + if (!empty($dxcc['callsign'])) { + $text .= " (worked {$dxcc['callsign']}"; + if (!empty($dxcc['mode'])) { + $text .= " on {$dxcc['mode']}"; + } + $text .= ")"; + } + $text .= "\n"; } } $text .= "\n"; @@ -212,7 +222,15 @@ class Monthlyreport extends CI_Controller { $text .= "NEW COUNTRIES VIA SATELLITE\n"; $text .= "---------------------------\n"; foreach ($report['new_dxcc_satellite'] as $dxcc) { - $text .= "- {$dxcc['name']}\n"; + $text .= "- {$dxcc['name']}"; + if (!empty($dxcc['callsign'])) { + $text .= " (worked {$dxcc['callsign']}"; + if (!empty($dxcc['mode'])) { + $text .= " on {$dxcc['mode']}"; + } + $text .= ")"; + } + $text .= "\n"; } $text .= "\n"; } @@ -221,7 +239,15 @@ class Monthlyreport extends CI_Controller { $text .= "NEW COUNTRIES VIA EME (MOONBOUNCE)\n"; $text .= "----------------------------------\n"; foreach ($report['new_dxcc_eme'] as $dxcc) { - $text .= "- {$dxcc['name']}\n"; + $text .= "- {$dxcc['name']}"; + if (!empty($dxcc['callsign'])) { + $text .= " (worked {$dxcc['callsign']}"; + if (!empty($dxcc['mode'])) { + $text .= " on {$dxcc['mode']}"; + } + $text .= ")"; + } + $text .= "\n"; } $text .= "\n"; } @@ -230,37 +256,27 @@ class Monthlyreport extends CI_Controller { $text .= "NEW GRIDSQUARES THIS MONTH\n"; $text .= "--------------------------\n"; - if (count($report['new_grids_hf']) > 0) { - $text .= "HF/VHF Terrestrial (" . count($report['new_grids_hf']) . "):\n"; - $grids_per_line = 10; - $grid_list = array_column($report['new_grids_hf'], 'grid'); - for ($i = 0; $i < count($grid_list); $i += $grids_per_line) { - $text .= implode(', ', array_slice($grid_list, $i, $grids_per_line)) . "\n"; - } - $text .= "\n"; - } - - if (count($report['new_grids_satellite']) > 0) { - $text .= "Satellite (" . count($report['new_grids_satellite']) . "):\n"; - $grids_per_line = 10; - $grid_list = array_column($report['new_grids_satellite'], 'grid'); - for ($i = 0; $i < count($grid_list); $i += $grids_per_line) { - $text .= implode(', ', array_slice($grid_list, $i, $grids_per_line)) . "\n"; - } - $text .= "\n"; - } - - if (count($report['new_grids_eme']) > 0) { - $text .= "EME (Moonbounce) (" . count($report['new_grids_eme']) . "):\n"; - $grids_per_line = 10; - $grid_list = array_column($report['new_grids_eme'], 'grid'); - for ($i = 0; $i < count($grid_list); $i += $grids_per_line) { - $text .= implode(', ', array_slice($grid_list, $i, $grids_per_line)) . "\n"; + if (!empty($report['new_grids_by_band'])) { + foreach ($report['new_grids_by_band'] as $band => $grids_list) { + $text .= "\n{$band} (" . count($grids_list) . " new):\n"; + foreach ($grids_list as $grid) { + $text .= " {$grid['grid']}"; + if (!empty($grid['callsign'])) { + $text .= " ({$grid['callsign']}"; + if (!empty($grid['satellite'])) { + $text .= " via {$grid['satellite']}"; + } + if (!empty($grid['mode'])) { + $text .= " - {$grid['mode']}"; + } + $text .= ")"; + } + $text .= "\n"; + } } } - } - - $text .= "MODES USED\n"; + $text .= "\n"; + } $text .= "MODES USED\n"; $text .= "----------\n"; foreach ($report['modes'] as $mode => $count) { $text .= sprintf("%-10s %d QSOs\n", $mode, $count); @@ -295,7 +311,15 @@ class Monthlyreport extends CI_Controller { if ($report['satellite_qsos'] > 0) { $text .= "SATELLITE ACTIVITY\n"; $text .= "------------------\n"; - $text .= "Total Satellite QSOs: {$report['satellite_qsos']}\n\n"; + $text .= "Total Satellite QSOs: {$report['satellite_qsos']}\n"; + + if (!empty($report['satellite_breakdown'])) { + $text .= "\nQSOs per Satellite:\n"; + foreach ($report['satellite_breakdown'] as $sat) { + $text .= sprintf(" %-20s %3d QSOs (%s%%)\n", $sat['satellite'], $sat['qso_count'], $sat['percentage']); + } + } + $text .= "\n"; } if ($report['eme_qsos'] > 0) { diff --git a/application/models/Monthlyreport_model.php b/application/models/Monthlyreport_model.php index afba7741e..f4094e26f 100644 --- a/application/models/Monthlyreport_model.php +++ b/application/models/Monthlyreport_model.php @@ -32,6 +32,7 @@ class Monthlyreport_model extends CI_Model { 'new_dxcc_satellite' => $this->get_new_dxcc_by_prop($logbooks_locations_array, $start_date, $end_date, $prev_month_end, 'SAT'), 'new_dxcc_eme' => $this->get_new_dxcc_by_prop($logbooks_locations_array, $start_date, $end_date, $prev_month_end, 'EME'), 'new_grids' => $this->get_new_gridsquares($logbooks_locations_array, $start_date, $end_date, $prev_month_end), + 'new_grids_by_band' => $this->get_new_gridsquares_by_band($logbooks_locations_array, $start_date, $end_date, $prev_month_end), 'new_grids_satellite' => $this->get_new_gridsquares_by_prop($logbooks_locations_array, $start_date, $end_date, $prev_month_end, 'SAT'), 'new_grids_eme' => $this->get_new_gridsquares_by_prop($logbooks_locations_array, $start_date, $end_date, $prev_month_end, 'EME'), 'new_grids_hf' => $this->get_new_gridsquares_hf($logbooks_locations_array, $start_date, $end_date, $prev_month_end), @@ -432,6 +433,152 @@ class Monthlyreport_model extends CI_Model { return $new_dxcc; } + /** + * Get new gridsquares by band + */ + private function get_new_gridsquares_by_band($locations, $start_date, $end_date, $prev_month_end) { + $new_grids_by_band = array(); + + // Get all bands worked this month, plus propagation mode to separate SAT/EME + $this->db->distinct(); + $this->db->select('COL_BAND, COL_PROP_MODE'); + $this->db->from($this->config->item('table_name')); + $this->db->where_in('station_id', $locations); + $this->db->where('COL_TIME_ON >=', $start_date); + $this->db->where('COL_TIME_ON <=', $end_date); + $this->db->where('COL_BAND IS NOT NULL'); + $this->db->where('COL_BAND !=', ''); + $bands_query = $this->db->get(); + + foreach ($bands_query->result() as $band_row) { + $band = $band_row->COL_BAND; + $prop_mode = $band_row->COL_PROP_MODE; + + // Group SAT and EME separately, not by frequency band + if ($prop_mode == 'SAT') { + $band_key = 'Satellite'; + } elseif ($prop_mode == 'EME') { + $band_key = 'EME'; + } else { + $band_key = $band; + } + + if (!isset($new_grids_by_band[$band_key])) { + $new_grids_by_band[$band_key] = array(); + } + + // Get all gridsquares worked on this band/prop this month + $this->db->select('COL_CALL, COL_GRIDSQUARE, COL_VUCC_GRIDS, COL_TIME_ON, COL_MODE, COL_SUBMODE, COL_SAT_NAME'); + $this->db->from($this->config->item('table_name')); + $this->db->where_in('station_id', $locations); + $this->db->where('COL_TIME_ON >=', $start_date); + $this->db->where('COL_TIME_ON <=', $end_date); + $this->db->where('COL_BAND', $band); + + // Filter by propagation mode + if ($prop_mode) { + $this->db->where('COL_PROP_MODE', $prop_mode); + } else { + // For terrestrial, exclude SAT and EME + $this->db->where('(COL_PROP_MODE IS NULL OR (COL_PROP_MODE != "SAT" AND COL_PROP_MODE != "EME"))', NULL, FALSE); + } + + $this->db->order_by('COL_TIME_ON', 'ASC'); + + $query = $this->db->get(); + $grid_data = array(); + + foreach ($query->result() as $row) { + $mode = !empty($row->COL_SUBMODE) ? $row->COL_SUBMODE : $row->COL_MODE; + + // Process main gridsquare (first 4 characters only) + if (!empty($row->COL_GRIDSQUARE) && strlen($row->COL_GRIDSQUARE) >= 4) { + $grid_4char = strtoupper(substr($row->COL_GRIDSQUARE, 0, 4)); + if (!isset($grid_data[$grid_4char])) { + $grid_data[$grid_4char] = array( + 'callsign' => $row->COL_CALL, + 'satellite' => !empty($row->COL_SAT_NAME) ? $row->COL_SAT_NAME : '', + 'mode' => $mode, + 'time' => $row->COL_TIME_ON + ); + } + } + + // Process VUCC grids (first 4 characters only) + if (!empty($row->COL_VUCC_GRIDS)) { + $vucc_grids = explode(',', $row->COL_VUCC_GRIDS); + foreach ($vucc_grids as $grid) { + $grid = trim($grid); + if (strlen($grid) >= 4) { + $grid_4char = strtoupper(substr($grid, 0, 4)); + if (!isset($grid_data[$grid_4char])) { + $grid_data[$grid_4char] = array( + 'callsign' => $row->COL_CALL, + 'satellite' => !empty($row->COL_SAT_NAME) ? $row->COL_SAT_NAME : '', + 'mode' => $mode, + 'time' => $row->COL_TIME_ON + ); + } + } + } + } + } + + // Check each grid to see if it was worked before on this band/prop + foreach ($grid_data as $grid => $data) { + // Check if this grid was worked before this month on this band/prop + $this->db->select('COUNT(*) as count'); + $this->db->from($this->config->item('table_name')); + $this->db->where_in('station_id', $locations); + $this->db->where('COL_BAND', $band); + if ($prop_mode) { + $this->db->where('COL_PROP_MODE', $prop_mode); + } else { + $this->db->where('(COL_PROP_MODE IS NULL OR (COL_PROP_MODE != "SAT" AND COL_PROP_MODE != "EME"))', NULL, FALSE); + } + $this->db->where('COL_TIME_ON <', $start_date); + $this->db->group_start(); + $this->db->where('UPPER(SUBSTR(COL_GRIDSQUARE, 1, 4)) =', $grid); + $this->db->or_like('COL_VUCC_GRIDS', $grid); + $this->db->group_end(); + + $prev_query = $this->db->get(); + $prev_row = $prev_query->row(); + + // If not worked before on this band/prop, it's new + if ($prev_row->count == 0) { + // Avoid duplicates in the same band_key + $already_added = false; + foreach ($new_grids_by_band[$band_key] as $existing) { + if ($existing['grid'] == $grid) { + $already_added = true; + break; + } + } + + if (!$already_added) { + $new_grids_by_band[$band_key][] = array( + 'grid' => $grid, + 'callsign' => $data['callsign'], + 'satellite' => $data['satellite'], + 'mode' => $data['mode'] + ); + } + } + } + } + + // Remove bands with no new grids + $new_grids_by_band = array_filter($new_grids_by_band, function($arr) { + return !empty($arr); + }); + + // Sort bands in proper amateur radio order + $new_grids_by_band = $this->sort_bands_array($new_grids_by_band); + + return $new_grids_by_band; + } + /** * Get new gridsquares worked this month (first time ever) - All modes */ diff --git a/application/views/monthlyreport/report.php b/application/views/monthlyreport/report.php index bc08476a0..ad61ee959 100644 --- a/application/views/monthlyreport/report.php +++ b/application/views/monthlyreport/report.php @@ -213,77 +213,99 @@ - - 0) { ?> + + $grids_list) { + if ($band != 'Satellite' && $band != 'EME') { + $terrestrial_grids[$band] = $grids_list; + } + } + } + + if (!empty($terrestrial_grids)) { + ?>
-
New Gridsquares This Month
+
New Gridsquares by Band
- - 0) { ?> -
-
HF/VHF Terrestrial ()
-
- -
-
- - - - - + $grids_list) { + $icon = ''; + ?> +
+
( new)
+
+ +
+
+ + + + + +
-
- + +
-
- - 0) { ?> -
-
Satellite ()
-
- -
-
- - - - - - -
-
- -
-
- - - 0) { ?> -
-
EME (Moonbounce) ()
-
- -
-
- - - - - -
-
- -
-
- -
- + + 0) { ?> +
+
+
New Gridsquares via Satellite ()
+
+
+
+ +
+
+ + + + + + +
+
+ +
+
+
+ + + + 0) { ?> +
+
+
New Gridsquares via EME (Moonbounce) ()
+
+
+
+ +
+
+ + + + + +
+
+ +
+
+
+