diff --git a/plugins/store/StoreController.php b/plugins/store/StoreController.php index 21d3069..424ea98 100644 --- a/plugins/store/StoreController.php +++ b/plugins/store/StoreController.php @@ -19,6 +19,7 @@ class StoreController public function __construct() { + $this->applyStoreTimezone(); $this->view = new View(__DIR__ . '/views'); } @@ -171,6 +172,8 @@ class StoreController $expiryDays = max(1, (int)$expiryDaysRaw); $orderPrefixRaw = array_key_exists('store_order_prefix', $_POST) ? (string)$_POST['store_order_prefix'] : (string)($current['store_order_prefix'] ?? 'AC-ORD'); $orderPrefix = $this->sanitizeOrderPrefix($orderPrefixRaw); + $timezoneRaw = array_key_exists('store_timezone', $_POST) ? (string)$_POST['store_timezone'] : (string)($current['store_timezone'] ?? 'UTC'); + $timezone = $this->normalizeTimezone($timezoneRaw); $testMode = array_key_exists('store_test_mode', $_POST) ? ((string)$_POST['store_test_mode'] === '1' ? '1' : '0') : (string)($current['store_test_mode'] ?? '1'); $stripeEnabled = array_key_exists('store_stripe_enabled', $_POST) ? ((string)$_POST['store_stripe_enabled'] === '1' ? '1' : '0') : (string)($current['store_stripe_enabled'] ?? '0'); $stripePublic = trim((string)(array_key_exists('store_stripe_public_key', $_POST) ? $_POST['store_stripe_public_key'] : ($current['store_stripe_public_key'] ?? ''))); @@ -201,6 +204,7 @@ class StoreController Settings::set('store_download_limit', (string)$downloadLimit); Settings::set('store_download_expiry_days', (string)$expiryDays); Settings::set('store_order_prefix', $orderPrefix); + Settings::set('store_timezone', $timezone); Settings::set('store_test_mode', $testMode); Settings::set('store_stripe_enabled', $stripeEnabled); Settings::set('store_stripe_public_key', $stripePublic); @@ -2257,6 +2261,7 @@ class StoreController 'store_download_limit' => Settings::get('store_download_limit', '5'), 'store_download_expiry_days' => Settings::get('store_download_expiry_days', '30'), 'store_order_prefix' => Settings::get('store_order_prefix', 'AC-ORD'), + 'store_timezone' => Settings::get('store_timezone', 'UTC'), 'store_test_mode' => Settings::get('store_test_mode', '1'), 'store_stripe_enabled' => Settings::get('store_stripe_enabled', '0'), 'store_stripe_public_key' => Settings::get('store_stripe_public_key', ''), @@ -2276,6 +2281,39 @@ class StoreController ]; } + private function normalizeTimezone(string $timezone): string + { + $timezone = trim($timezone); + if ($timezone === '') { + return 'UTC'; + } + return in_array($timezone, \DateTimeZone::listIdentifiers(), true) ? $timezone : 'UTC'; + } + + private function applyStoreTimezone(): void + { + $timezone = $this->normalizeTimezone((string)Settings::get('store_timezone', 'UTC')); + @date_default_timezone_set($timezone); + + $db = Database::get(); + if (!($db instanceof PDO)) { + return; + } + + try { + $tz = new \DateTimeZone($timezone); + $now = new \DateTimeImmutable('now', $tz); + $offset = $tz->getOffset($now); + $sign = $offset < 0 ? '-' : '+'; + $offset = abs($offset); + $hours = str_pad((string)intdiv($offset, 3600), 2, '0', STR_PAD_LEFT); + $mins = str_pad((string)intdiv($offset % 3600, 60), 2, '0', STR_PAD_LEFT); + $dbTz = $sign . $hours . ':' . $mins; + $db->exec("SET time_zone = '" . $dbTz . "'"); + } catch (Throwable $e) { + } + } + private function ensureSalesChartSchema(): void { $db = Database::get(); diff --git a/plugins/store/views/admin/settings.php b/plugins/store/views/admin/settings.php index 7ee92c3..25b3133 100644 --- a/plugins/store/views/admin/settings.php +++ b/plugins/store/views/admin/settings.php @@ -67,9 +67,25 @@ ob_start(); -