2024-02-17 17:54:35 +00:00
|
|
|
<?php
|
|
|
|
|
|
|
|
|
|
class Workabledxcc_model extends CI_Model
|
|
|
|
|
{
|
2025-08-11 14:50:56 +01:00
|
|
|
// Cache for DXCC lookups to avoid repeated queries
|
|
|
|
|
private $dxccCache = array();
|
|
|
|
|
private $workedCache = array();
|
2026-03-26 15:00:56 +00:00
|
|
|
private $includeSatelliteWorked = null;
|
2025-08-11 14:50:56 +01:00
|
|
|
|
2026-03-26 14:36:29 +00:00
|
|
|
/**
|
|
|
|
|
* Normalize DXpedition callsigns for display.
|
2026-03-26 14:44:23 +00:00
|
|
|
* Placeholder values like F/H and M/S are rendered as "Unknown".
|
2026-03-26 14:36:29 +00:00
|
|
|
*
|
|
|
|
|
* @param string|null $callsign
|
|
|
|
|
* @return string
|
|
|
|
|
*/
|
|
|
|
|
public function normalizeDxpedCallsign($callsign)
|
|
|
|
|
{
|
|
|
|
|
$normalized = strtoupper(trim((string) $callsign));
|
|
|
|
|
|
|
|
|
|
if ($normalized === '') {
|
2026-03-26 14:44:23 +00:00
|
|
|
return 'Unknown';
|
2026-03-26 14:36:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Filter out placeholder/non-callsign patterns such as F/H, M/S.
|
|
|
|
|
if (preg_match('/^[A-Z]\/[A-Z]$/', $normalized)) {
|
2026-03-26 14:44:23 +00:00
|
|
|
return 'Unknown';
|
2026-03-26 14:36:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return $normalized;
|
|
|
|
|
}
|
|
|
|
|
|
2025-08-11 14:50:56 +01:00
|
|
|
/**
|
|
|
|
|
* Batch DXCC lookup for multiple callsigns
|
|
|
|
|
* @param array $callsigns Array of callsigns
|
|
|
|
|
* @param array $dates Array of dates corresponding to callsigns
|
|
|
|
|
* @return array Array of DXCC entities indexed by callsign index
|
|
|
|
|
*/
|
|
|
|
|
public function batchDxccLookup($callsigns, $dates)
|
|
|
|
|
{
|
|
|
|
|
$this->load->model('logbook_model');
|
|
|
|
|
$entities = array();
|
|
|
|
|
|
|
|
|
|
foreach ($callsigns as $index => $callsign) {
|
|
|
|
|
$cacheKey = $callsign . '_' . $dates[$index];
|
|
|
|
|
|
|
|
|
|
if (!isset($this->dxccCache[$cacheKey])) {
|
|
|
|
|
$dxccInfo = $this->logbook_model->dxcc_lookup($callsign, $dates[$index]);
|
|
|
|
|
$this->dxccCache[$cacheKey] = isset($dxccInfo['entity']) ? $dxccInfo['entity'] : null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$entities[$index] = $this->dxccCache[$cacheKey];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return $entities;
|
|
|
|
|
}
|
2024-02-17 17:54:35 +00:00
|
|
|
|
2025-08-11 14:50:56 +01:00
|
|
|
/**
|
|
|
|
|
* Batch check if DXCC entities have been worked/confirmed
|
|
|
|
|
* @param array $entities Array of unique DXCC entities
|
|
|
|
|
* @return array Array of worked/confirmed status indexed by entity
|
|
|
|
|
*/
|
|
|
|
|
public function batchDxccWorkedStatus($entities)
|
|
|
|
|
{
|
|
|
|
|
if (empty($entities)) {
|
|
|
|
|
return array();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$user_default_confirmation = $this->session->userdata('user_default_confirmation');
|
|
|
|
|
$this->load->model('logbooks_model');
|
|
|
|
|
$logbooks_locations_array = $this->logbooks_model->list_logbook_relationships($this->session->userdata('active_station_logbook'));
|
|
|
|
|
|
|
|
|
|
if (empty($logbooks_locations_array)) {
|
2025-08-11 16:08:06 +01:00
|
|
|
return array_fill_keys($entities, [
|
|
|
|
|
'workedBefore' => false,
|
|
|
|
|
'confirmed' => false,
|
|
|
|
|
'workedViaSatellite' => false
|
|
|
|
|
]);
|
2025-08-11 14:50:56 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$results = array();
|
|
|
|
|
|
|
|
|
|
// Build confirmation criteria once
|
|
|
|
|
$confirmationCriteria = $this->buildConfirmationCriteria($user_default_confirmation);
|
|
|
|
|
|
2025-08-11 16:08:06 +01:00
|
|
|
// Debug: Log entities being checked
|
|
|
|
|
log_message('debug', 'Workable DXCC: Checking entities: ' . implode(', ', $entities));
|
|
|
|
|
|
|
|
|
|
// Batch query for worked status (terrestrial)
|
2025-08-11 14:50:56 +01:00
|
|
|
$workedResults = $this->batchWorkedQuery($entities, $logbooks_locations_array);
|
|
|
|
|
|
2025-08-11 16:08:06 +01:00
|
|
|
// Batch query for confirmed status (terrestrial)
|
2025-08-11 14:50:56 +01:00
|
|
|
$confirmedResults = $this->batchConfirmedQuery($entities, $logbooks_locations_array, $confirmationCriteria);
|
|
|
|
|
|
2025-08-11 16:08:06 +01:00
|
|
|
// Batch query for satellite contacts
|
|
|
|
|
$satelliteResults = $this->batchSatelliteQuery($entities, $logbooks_locations_array);
|
2026-03-26 15:00:56 +00:00
|
|
|
$includeSatelliteWorked = $this->shouldIncludeSatelliteWorked();
|
2025-08-11 16:08:06 +01:00
|
|
|
|
|
|
|
|
// Debug: Log results
|
|
|
|
|
log_message('debug', 'Workable DXCC: Worked results: ' . json_encode($workedResults));
|
|
|
|
|
log_message('debug', 'Workable DXCC: Confirmed results: ' . json_encode($confirmedResults));
|
|
|
|
|
log_message('debug', 'Workable DXCC: Satellite results: ' . json_encode($satelliteResults));
|
|
|
|
|
|
2025-08-11 14:50:56 +01:00
|
|
|
// Combine results
|
|
|
|
|
foreach ($entities as $entity) {
|
2026-03-26 15:00:56 +00:00
|
|
|
$workedTerrestrial = isset($workedResults[$entity]);
|
|
|
|
|
$workedSatellite = isset($satelliteResults[$entity]);
|
2025-08-11 14:50:56 +01:00
|
|
|
$results[$entity] = [
|
2026-03-26 15:00:56 +00:00
|
|
|
'workedBefore' => $workedTerrestrial || ($includeSatelliteWorked && $workedSatellite),
|
2025-08-11 16:08:06 +01:00
|
|
|
'confirmed' => isset($confirmedResults[$entity]),
|
2026-03-26 15:00:56 +00:00
|
|
|
'workedViaSatellite' => $workedSatellite
|
2025-08-11 14:50:56 +01:00
|
|
|
];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return $results;
|
2026-03-26 15:00:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Check if the logged-in user wants SAT QSOs to count as "worked" in DXpedition status.
|
|
|
|
|
*
|
|
|
|
|
* @return bool
|
|
|
|
|
*/
|
|
|
|
|
private function shouldIncludeSatelliteWorked()
|
|
|
|
|
{
|
|
|
|
|
if ($this->includeSatelliteWorked !== null) {
|
|
|
|
|
return $this->includeSatelliteWorked;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$this->load->model('user_options_model');
|
|
|
|
|
$option = $this->user_options_model->get_options('dashboard', [
|
|
|
|
|
'option_name' => 'dashboard_dxpedition_sat_worked',
|
|
|
|
|
'option_key' => 'enabled',
|
|
|
|
|
])->row();
|
|
|
|
|
|
|
|
|
|
$this->includeSatelliteWorked = isset($option->option_value) && $option->option_value === 'true';
|
|
|
|
|
return $this->includeSatelliteWorked;
|
2025-08-11 14:50:56 +01:00
|
|
|
}
|
|
|
|
|
|
2025-08-14 15:36:38 +01:00
|
|
|
/**
|
|
|
|
|
* Batch check IOTA worked/confirmed status
|
|
|
|
|
* @param array $iotas Array of unique IOTA tags
|
|
|
|
|
* @return array Array indexed by IOTA tag with ['worked'=>bool,'confirmed'=>bool]
|
|
|
|
|
*/
|
|
|
|
|
public function batchIotaWorkedStatus($iotas)
|
|
|
|
|
{
|
|
|
|
|
if (empty($iotas)) {
|
|
|
|
|
return array();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$user_default_confirmation = $this->session->userdata('user_default_confirmation');
|
|
|
|
|
$this->load->model('logbooks_model');
|
|
|
|
|
$logbooks_locations_array = $this->logbooks_model->list_logbook_relationships($this->session->userdata('active_station_logbook'));
|
|
|
|
|
|
|
|
|
|
if (empty($logbooks_locations_array)) {
|
|
|
|
|
$out = [];
|
|
|
|
|
foreach ($iotas as $i) {
|
|
|
|
|
$out[$i] = ['worked' => false, 'confirmed' => false];
|
|
|
|
|
}
|
|
|
|
|
return $out;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Build confirmation criteria once
|
|
|
|
|
$confirmationCriteria = $this->buildConfirmationCriteria($user_default_confirmation);
|
|
|
|
|
|
|
|
|
|
// Build case-insensitive WHERE conditions for COL_IOTA
|
|
|
|
|
$whereConditions = array();
|
|
|
|
|
foreach ($iotas as $iota) {
|
|
|
|
|
$whereConditions[] = "UPPER(COL_IOTA) = UPPER('" . $this->db->escape_str($iota) . "')";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (empty($whereConditions)) {
|
|
|
|
|
return array();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$whereClause = '(' . implode(' OR ', $whereConditions) . ')';
|
|
|
|
|
|
|
|
|
|
// Worked query (any mode)
|
|
|
|
|
$this->db->select('COL_IOTA')
|
|
|
|
|
->distinct()
|
|
|
|
|
->from($this->config->item('table_name'))
|
|
|
|
|
->where_in('station_id', $logbooks_locations_array)
|
|
|
|
|
->where($whereClause);
|
|
|
|
|
|
|
|
|
|
$workedQuery = $this->db->get();
|
|
|
|
|
log_message('debug', 'Workable DXCC IOTA worked query: ' . $this->db->last_query());
|
|
|
|
|
|
|
|
|
|
$workedResults = array();
|
|
|
|
|
foreach ($workedQuery->result() as $row) {
|
|
|
|
|
foreach ($iotas as $iota) {
|
|
|
|
|
if (strtoupper($row->COL_IOTA) === strtoupper($iota)) {
|
|
|
|
|
$workedResults[$iota] = true;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Confirmed query (apply confirmation criteria, exclude satellite confirmations if desired)
|
|
|
|
|
$confirmedResults = array();
|
|
|
|
|
if ($confirmationCriteria !== '1=0') {
|
|
|
|
|
$this->db->select('COL_IOTA')
|
|
|
|
|
->distinct()
|
|
|
|
|
->from($this->config->item('table_name'))
|
|
|
|
|
->where($confirmationCriteria)
|
|
|
|
|
->where_in('station_id', $logbooks_locations_array)
|
|
|
|
|
->where($whereClause);
|
|
|
|
|
|
|
|
|
|
$confirmedQuery = $this->db->get();
|
|
|
|
|
foreach ($confirmedQuery->result() as $row) {
|
|
|
|
|
foreach ($iotas as $iota) {
|
|
|
|
|
if (strtoupper($row->COL_IOTA) === strtoupper($iota)) {
|
|
|
|
|
$confirmedResults[$iota] = true;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$out = array();
|
|
|
|
|
foreach ($iotas as $iota) {
|
|
|
|
|
$out[$iota] = [
|
|
|
|
|
'worked' => isset($workedResults[$iota]),
|
|
|
|
|
'confirmed' => isset($confirmedResults[$iota])
|
|
|
|
|
];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Debug
|
|
|
|
|
log_message('debug', 'Workable DXCC: IOTA worked results: ' . json_encode($workedResults));
|
|
|
|
|
log_message('debug', 'Workable DXCC: IOTA confirmed results: ' . json_encode($confirmedResults));
|
|
|
|
|
|
|
|
|
|
return $out;
|
|
|
|
|
}
|
|
|
|
|
|
2025-08-11 16:08:06 +01:00
|
|
|
/**
|
|
|
|
|
* Batch query to check which entities have been worked via satellite
|
|
|
|
|
*/
|
|
|
|
|
private function batchSatelliteQuery($entities, $logbooks_locations_array)
|
|
|
|
|
{
|
|
|
|
|
// Create case-insensitive matching for DXCC entities
|
|
|
|
|
$whereConditions = array();
|
|
|
|
|
foreach ($entities as $entity) {
|
|
|
|
|
$whereConditions[] = "UPPER(COL_COUNTRY) = UPPER('" . $this->db->escape_str($entity) . "')";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (empty($whereConditions)) {
|
|
|
|
|
return array();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$whereClause = '(' . implode(' OR ', $whereConditions) . ')';
|
|
|
|
|
|
|
|
|
|
$this->db->select('COL_COUNTRY')
|
|
|
|
|
->distinct()
|
|
|
|
|
->from($this->config->item('table_name'))
|
|
|
|
|
->where('COL_PROP_MODE', 'SAT') // Only satellite contacts
|
|
|
|
|
->where_in('station_id', $logbooks_locations_array)
|
|
|
|
|
->where($whereClause);
|
|
|
|
|
|
|
|
|
|
$query = $this->db->get();
|
|
|
|
|
|
|
|
|
|
// Debug: Log the SQL query
|
|
|
|
|
log_message('debug', 'Workable DXCC satellite query: ' . $this->db->last_query());
|
|
|
|
|
|
|
|
|
|
$results = array();
|
|
|
|
|
|
|
|
|
|
foreach ($query->result() as $row) {
|
|
|
|
|
// Store with the original entity case for lookup
|
|
|
|
|
foreach ($entities as $entity) {
|
|
|
|
|
if (strtoupper($row->COL_COUNTRY) === strtoupper($entity)) {
|
|
|
|
|
$results[$entity] = true;
|
|
|
|
|
log_message('debug', 'Workable DXCC: Found satellite match: ' . $entity . ' matches ' . $row->COL_COUNTRY);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return $results;
|
|
|
|
|
}
|
|
|
|
|
|
2025-08-11 14:50:56 +01:00
|
|
|
/**
|
|
|
|
|
* Build confirmation criteria SQL based on user preferences
|
|
|
|
|
*/
|
|
|
|
|
private function buildConfirmationCriteria($user_default_confirmation)
|
|
|
|
|
{
|
|
|
|
|
$criteria = array();
|
|
|
|
|
|
|
|
|
|
if (isset($user_default_confirmation) && strpos($user_default_confirmation, 'Q') !== false) {
|
|
|
|
|
$criteria[] = "COL_QSL_RCVD='Y'";
|
|
|
|
|
}
|
|
|
|
|
if (isset($user_default_confirmation) && strpos($user_default_confirmation, 'L') !== false) {
|
|
|
|
|
$criteria[] = "COL_LOTW_QSL_RCVD='Y'";
|
|
|
|
|
}
|
|
|
|
|
if (isset($user_default_confirmation) && strpos($user_default_confirmation, 'E') !== false) {
|
|
|
|
|
$criteria[] = "COL_EQSL_QSL_RCVD='Y'";
|
|
|
|
|
}
|
|
|
|
|
if (isset($user_default_confirmation) && strpos($user_default_confirmation, 'Z') !== false) {
|
|
|
|
|
$criteria[] = "COL_QRZCOM_QSO_DOWNLOAD_STATUS='Y'";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return empty($criteria) ? '1=0' : '(' . implode(' OR ', $criteria) . ')';
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Batch query to check which entities have been worked
|
|
|
|
|
*/
|
|
|
|
|
private function batchWorkedQuery($entities, $logbooks_locations_array)
|
|
|
|
|
{
|
2025-08-11 15:08:59 +01:00
|
|
|
// Create case-insensitive matching for DXCC entities
|
|
|
|
|
$whereConditions = array();
|
|
|
|
|
foreach ($entities as $entity) {
|
|
|
|
|
$whereConditions[] = "UPPER(COL_COUNTRY) = UPPER('" . $this->db->escape_str($entity) . "')";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (empty($whereConditions)) {
|
|
|
|
|
return array();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$whereClause = '(' . implode(' OR ', $whereConditions) . ')';
|
|
|
|
|
|
2025-08-11 14:50:56 +01:00
|
|
|
$this->db->select('COL_COUNTRY')
|
|
|
|
|
->distinct()
|
|
|
|
|
->from($this->config->item('table_name'))
|
|
|
|
|
->where('COL_PROP_MODE !=', 'SAT')
|
|
|
|
|
->where_in('station_id', $logbooks_locations_array)
|
2025-08-11 15:08:59 +01:00
|
|
|
->where($whereClause);
|
2025-08-11 14:50:56 +01:00
|
|
|
|
|
|
|
|
$query = $this->db->get();
|
2025-08-11 16:08:06 +01:00
|
|
|
|
|
|
|
|
// Debug: Log the SQL query
|
|
|
|
|
log_message('debug', 'Workable DXCC worked query: ' . $this->db->last_query());
|
|
|
|
|
|
2025-08-11 14:50:56 +01:00
|
|
|
$results = array();
|
|
|
|
|
|
|
|
|
|
foreach ($query->result() as $row) {
|
2025-08-11 15:08:59 +01:00
|
|
|
// Store with the original entity case for lookup
|
|
|
|
|
foreach ($entities as $entity) {
|
|
|
|
|
if (strtoupper($row->COL_COUNTRY) === strtoupper($entity)) {
|
|
|
|
|
$results[$entity] = true;
|
2025-08-11 16:08:06 +01:00
|
|
|
log_message('debug', 'Workable DXCC: Found worked match: ' . $entity . ' matches ' . $row->COL_COUNTRY);
|
2025-08-11 15:08:59 +01:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-08-11 14:50:56 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return $results;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Batch query to check which entities have been confirmed
|
|
|
|
|
*/
|
|
|
|
|
private function batchConfirmedQuery($entities, $logbooks_locations_array, $confirmationCriteria)
|
2024-02-17 17:54:35 +00:00
|
|
|
{
|
2025-08-11 14:50:56 +01:00
|
|
|
if ($confirmationCriteria === '1=0') {
|
|
|
|
|
return array();
|
|
|
|
|
}
|
|
|
|
|
|
2025-08-11 15:08:59 +01:00
|
|
|
// Create case-insensitive matching for DXCC entities
|
|
|
|
|
$whereConditions = array();
|
|
|
|
|
foreach ($entities as $entity) {
|
|
|
|
|
$whereConditions[] = "UPPER(COL_COUNTRY) = UPPER('" . $this->db->escape_str($entity) . "')";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (empty($whereConditions)) {
|
|
|
|
|
return array();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$whereClause = '(' . implode(' OR ', $whereConditions) . ')';
|
|
|
|
|
|
2025-08-11 14:50:56 +01:00
|
|
|
$this->db->select('COL_COUNTRY')
|
|
|
|
|
->distinct()
|
|
|
|
|
->from($this->config->item('table_name'))
|
|
|
|
|
->where('COL_PROP_MODE !=', 'SAT')
|
|
|
|
|
->where($confirmationCriteria)
|
|
|
|
|
->where_in('station_id', $logbooks_locations_array)
|
2025-08-11 15:08:59 +01:00
|
|
|
->where($whereClause);
|
2025-08-11 14:50:56 +01:00
|
|
|
|
|
|
|
|
$query = $this->db->get();
|
|
|
|
|
$results = array();
|
|
|
|
|
|
|
|
|
|
foreach ($query->result() as $row) {
|
2025-08-11 15:08:59 +01:00
|
|
|
// Store with the original entity case for lookup
|
|
|
|
|
foreach ($entities as $entity) {
|
|
|
|
|
if (strtoupper($row->COL_COUNTRY) === strtoupper($entity)) {
|
|
|
|
|
$results[$entity] = true;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-08-11 14:50:56 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return $results;
|
|
|
|
|
}
|
2024-02-17 17:54:35 +00:00
|
|
|
|
2025-08-11 14:50:56 +01:00
|
|
|
public function GetThisWeek()
|
|
|
|
|
{
|
2025-11-18 13:14:41 +00:00
|
|
|
try {
|
|
|
|
|
$json = @file_get_contents($this->optionslib->get_option('dxped_url'));
|
|
|
|
|
|
|
|
|
|
// Catch any errors from opening the file
|
|
|
|
|
if ($json === false) {
|
|
|
|
|
return array('error' => 'Failed to fetch DXpedition data');
|
|
|
|
|
exit;
|
|
|
|
|
}
|
|
|
|
|
} catch (Exception $e) {
|
|
|
|
|
return array('error' => 'Error fetching DXpedition data: ' . $e->getMessage());
|
|
|
|
|
exit;
|
|
|
|
|
}
|
|
|
|
|
|
2024-02-17 17:54:35 +00:00
|
|
|
$data = json_decode($json, true);
|
|
|
|
|
|
2025-11-18 13:14:41 +00:00
|
|
|
if (empty($data) || !is_array($data)) {
|
|
|
|
|
return array('error' => 'Invalid DXpedition data received');
|
2025-08-11 14:50:56 +01:00
|
|
|
}
|
2024-02-17 17:54:35 +00:00
|
|
|
|
2025-08-11 14:50:56 +01:00
|
|
|
$thisWeekRecords = [];
|
2026-03-26 14:36:29 +00:00
|
|
|
$now = new DateTime();
|
|
|
|
|
$startOfWeek = (clone $now)
|
|
|
|
|
->setISODate((int) $now->format('o'), (int) $now->format('W'), 1)
|
|
|
|
|
->setTime(0, 0, 0);
|
|
|
|
|
$endOfWeek = (clone $startOfWeek)
|
|
|
|
|
->modify('+6 days')
|
|
|
|
|
->setTime(23, 59, 59);
|
2024-02-17 17:54:35 +00:00
|
|
|
|
2025-08-11 14:50:56 +01:00
|
|
|
// Get Date format
|
|
|
|
|
if ($this->session->userdata('user_date_format')) {
|
|
|
|
|
$custom_date_format = $this->session->userdata('user_date_format');
|
|
|
|
|
} else {
|
|
|
|
|
$custom_date_format = $this->config->item('qso_date_format');
|
|
|
|
|
}
|
2024-02-17 17:54:35 +00:00
|
|
|
|
2025-08-11 14:50:56 +01:00
|
|
|
// First pass: filter records for this week
|
|
|
|
|
$weekRecords = array();
|
|
|
|
|
foreach ($data as $record) {
|
2026-03-26 14:36:29 +00:00
|
|
|
$startDate = (new DateTime($record['0']))->setTime(0, 0, 0);
|
|
|
|
|
$endDate = (new DateTime($record['1']))->setTime(23, 59, 59);
|
2024-02-17 17:54:35 +00:00
|
|
|
|
2026-03-26 14:36:29 +00:00
|
|
|
// Include any DXpedition overlapping this calendar week.
|
|
|
|
|
if ($startDate <= $endOfWeek && $endDate >= $startOfWeek) {
|
2025-08-11 14:50:56 +01:00
|
|
|
$weekRecords[] = $record;
|
2024-02-17 17:54:35 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-08-11 14:50:56 +01:00
|
|
|
if (empty($weekRecords)) {
|
|
|
|
|
return array();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Batch process DXCC lookups
|
|
|
|
|
$callsigns = array_column($weekRecords, 'callsign');
|
|
|
|
|
$dates = array_column($weekRecords, '0');
|
|
|
|
|
$dxccEntities = $this->batchDxccLookup($callsigns, $dates);
|
|
|
|
|
|
|
|
|
|
// Get worked/confirmed status for all entities in batch
|
|
|
|
|
$uniqueEntities = array_unique(array_filter($dxccEntities));
|
|
|
|
|
$dxccStatus = $this->batchDxccWorkedStatus($uniqueEntities);
|
|
|
|
|
|
|
|
|
|
// Process results
|
|
|
|
|
foreach ($weekRecords as $index => $record) {
|
2026-03-26 14:36:29 +00:00
|
|
|
$endDate = (new DateTime($record['1']))->setTime(23, 59, 59);
|
|
|
|
|
$daysLeft = (int) $now->diff($endDate)->format('%r%a');
|
2025-08-11 14:50:56 +01:00
|
|
|
|
2026-03-26 14:36:29 +00:00
|
|
|
if ($daysLeft < 0) {
|
|
|
|
|
$record['daysLeft'] = "Ended";
|
|
|
|
|
} else {
|
|
|
|
|
$record['daysLeft'] = ($daysLeft === 0) ? "Last day" : $daysLeft . " days left";
|
|
|
|
|
}
|
2025-08-11 14:50:56 +01:00
|
|
|
|
|
|
|
|
$oldStartDate = DateTime::createFromFormat('Y-m-d', $record['0']);
|
|
|
|
|
$record['startDate'] = $oldStartDate->format($custom_date_format);
|
|
|
|
|
|
|
|
|
|
$oldEndDate = DateTime::createFromFormat('Y-m-d', $record['1']);
|
|
|
|
|
$record['endDate'] = $oldEndDate->format($custom_date_format);
|
|
|
|
|
|
|
|
|
|
// Get DXCC status for this callsign
|
|
|
|
|
$entity = $dxccEntities[$index] ?? null;
|
2025-08-11 16:08:06 +01:00
|
|
|
$worked = $entity && isset($dxccStatus[$entity]) ? $dxccStatus[$entity] : [
|
|
|
|
|
'workedBefore' => false,
|
|
|
|
|
'confirmed' => false,
|
|
|
|
|
'workedViaSatellite' => false
|
|
|
|
|
];
|
2025-08-11 14:50:56 +01:00
|
|
|
|
|
|
|
|
$record['workedBefore'] = $worked['workedBefore'];
|
|
|
|
|
$record['confirmed'] = $worked['confirmed'];
|
2025-08-11 16:08:06 +01:00
|
|
|
$record['workedViaSatellite'] = $worked['workedViaSatellite'];
|
2026-03-26 14:36:29 +00:00
|
|
|
$record['callsign'] = $this->normalizeDxpedCallsign($record['callsign'] ?? '');
|
2025-08-11 14:50:56 +01:00
|
|
|
|
|
|
|
|
$thisWeekRecords[] = $record;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return $thisWeekRecords;
|
2024-02-17 17:54:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function dxccWorked($country)
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
$return = [
|
|
|
|
|
"workedBefore" => false,
|
|
|
|
|
"confirmed" => false,
|
2025-08-11 16:08:06 +01:00
|
|
|
"workedViaSatellite" => false,
|
2024-02-17 17:54:35 +00:00
|
|
|
];
|
|
|
|
|
|
|
|
|
|
$user_default_confirmation = $this->session->userdata('user_default_confirmation');
|
|
|
|
|
$this->load->model('logbooks_model');
|
|
|
|
|
$logbooks_locations_array = $this->logbooks_model->list_logbook_relationships($this->session->userdata('active_station_logbook'));
|
|
|
|
|
$this->load->model('logbook_model');
|
|
|
|
|
|
|
|
|
|
if (!empty($logbooks_locations_array)) {
|
2025-08-11 16:08:06 +01:00
|
|
|
// Check for terrestrial contacts
|
2024-02-17 17:54:35 +00:00
|
|
|
$this->db->where('COL_PROP_MODE !=', 'SAT');
|
|
|
|
|
|
|
|
|
|
$this->db->where_in('station_id', $logbooks_locations_array);
|
2025-08-11 15:12:14 +01:00
|
|
|
// Fix case sensitivity issue for DXCC country matching
|
|
|
|
|
$this->db->where('UPPER(COL_COUNTRY) = UPPER(?)', urldecode($country));
|
2024-02-17 17:54:35 +00:00
|
|
|
|
|
|
|
|
$query = $this->db->get($this->config->item('table_name'), 1, 0);
|
|
|
|
|
foreach ($query->result() as $workedBeforeRow) {
|
|
|
|
|
$return['workedBefore'] = true;
|
|
|
|
|
}
|
|
|
|
|
|
2025-08-11 16:08:06 +01:00
|
|
|
// Check for satellite contacts
|
|
|
|
|
$this->db->where('COL_PROP_MODE', 'SAT');
|
|
|
|
|
$this->db->where_in('station_id', $logbooks_locations_array);
|
|
|
|
|
$this->db->where('UPPER(COL_COUNTRY) = UPPER(?)', urldecode($country));
|
|
|
|
|
|
|
|
|
|
$query = $this->db->get($this->config->item('table_name'), 1, 0);
|
|
|
|
|
foreach ($query->result() as $satelliteRow) {
|
|
|
|
|
$return['workedViaSatellite'] = true;
|
|
|
|
|
}
|
|
|
|
|
|
2024-02-17 17:54:35 +00:00
|
|
|
$extrawhere = '';
|
|
|
|
|
if (isset($user_default_confirmation) && strpos($user_default_confirmation, 'Q') !== false) {
|
|
|
|
|
$extrawhere = "COL_QSL_RCVD='Y'";
|
|
|
|
|
}
|
|
|
|
|
if (isset($user_default_confirmation) && strpos($user_default_confirmation, 'L') !== false) {
|
|
|
|
|
if ($extrawhere != '') {
|
|
|
|
|
$extrawhere .= " OR";
|
|
|
|
|
}
|
|
|
|
|
$extrawhere .= " COL_LOTW_QSL_RCVD='Y'";
|
|
|
|
|
}
|
|
|
|
|
if (isset($user_default_confirmation) && strpos($user_default_confirmation, 'E') !== false) {
|
|
|
|
|
if ($extrawhere != '') {
|
|
|
|
|
$extrawhere .= " OR";
|
|
|
|
|
}
|
|
|
|
|
$extrawhere .= " COL_EQSL_QSL_RCVD='Y'";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (isset($user_default_confirmation) && strpos($user_default_confirmation, 'Z') !== false) {
|
|
|
|
|
if ($extrawhere != '') {
|
|
|
|
|
$extrawhere .= " OR";
|
|
|
|
|
}
|
|
|
|
|
$extrawhere .= " COL_QRZCOM_QSO_DOWNLOAD_STATUS='Y'";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
$this->load->model('logbook_model');
|
|
|
|
|
$this->db->where('COL_PROP_MODE !=', 'SAT');
|
|
|
|
|
if ($extrawhere != '') {
|
|
|
|
|
$this->db->where('(' . $extrawhere . ')');
|
|
|
|
|
} else {
|
|
|
|
|
$this->db->where("1=0");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
$this->db->where_in('station_id', $logbooks_locations_array);
|
2025-08-11 15:12:14 +01:00
|
|
|
// Fix case sensitivity issue for DXCC country matching
|
|
|
|
|
$this->db->where('UPPER(COL_COUNTRY) = UPPER(?)', urldecode($country));
|
2024-02-17 17:54:35 +00:00
|
|
|
|
|
|
|
|
$query = $this->db->get($this->config->item('table_name'), 1, 0);
|
|
|
|
|
foreach ($query->result() as $workedBeforeRow) {
|
|
|
|
|
$return['confirmed'] = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return $return;
|
|
|
|
|
} else {
|
|
|
|
|
$return['workedBefore'] = false;
|
|
|
|
|
$return['confirmed'] = false;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return $return;;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|