diff --git a/.gitignore b/.gitignore
index af3d87c..06f335c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -4,5 +4,5 @@ _tables.php
_globals.php
_cfg.php
/logs
-.agents/*
+.agents
skills-lock.json
diff --git a/_SQL/zmeny.sql.php b/_SQL/zmeny.sql.php
index 35dd03d..89a4d19 100644
--- a/_SQL/zmeny.sql.php
+++ b/_SQL/zmeny.sql.php
@@ -29,6 +29,7 @@ function AddZmenyFile($version)
AddZmenyFile('3.4.5.652');
AddZmenyFile('3.4.5.655');
AddZmenyFile('3.4.6.656');
+AddZmenyFile('3.4.5.658');
//#############################################################################
require_once ('connect.inc.php');
diff --git a/_SQL/zmeny_3.4.5.658.sql.php b/_SQL/zmeny_3.4.5.658.sql.php
new file mode 100644
index 0000000..3dbf46a
--- /dev/null
+++ b/_SQL/zmeny_3.4.5.658.sql.php
@@ -0,0 +1,24 @@
+
+// zmeny pro verzi 3.4.9.658 - ORIS API integration
+
+$version_upd = '3.4.5.658';
+
+//#############################################################################
+
+require_once ('prepare.inc.php');
+
+//#############################################################################
+// SQL dotazy pro zmenu db. na novejsi verzi
+//############################################################################
+$sql[0] = "ALTER TABLE `".TBL_ZAVXUS."`
+ ADD COLUMN `oris_entry_id` INT UNSIGNED NULL,
+ ADD COLUMN `sync_status` ENUM('LOCAL_ONLY', 'SYNCED', 'PENDING_CREATE', 'PENDING_UPDATE', 'PENDING_DELETE', 'FAILED_CREATE', 'FAILED_UPDATE', 'FAILED_DELETE') NOT NULL DEFAULT 'LOCAL_ONLY',
+ ADD COLUMN `sync_timestamp` DATETIME NULL,
+ ADD COLUMN `sync_error_payload` TEXT NULL,
+ ADD INDEX `sync_status` (`sync_status`)";
+
+$sql[1] = "ALTER TABLE `".TBL_RACE."`
+ ADD COLUMN `oris_entry_start` DATETIME NULL";
+
+require_once ('action.inc.php');
+?>
\ No newline at end of file
diff --git a/adm_oris_sync.php b/adm_oris_sync.php
new file mode 100644
index 0000000..7cbf612
--- /dev/null
+++ b/adm_oris_sync.php
@@ -0,0 +1,44 @@
+
+
+
+
+ ORIS Sync Daemon Manual Trigger
+
+
+
+ Manual ORIS Sync Execution
+ Executing daemon...
+
+getMessage() . "\n";
+}
+$output = ob_get_clean();
+
+// Display standard output
+echo htmlspecialchars($output);
+?>
+
+
+ Return to System
+
+
\ No newline at end of file
diff --git a/ads_oris.inc.php b/ads_oris.inc.php
index 3fcd481..bc73598 100644
--- a/ads_oris.inc.php
+++ b/ads_oris.inc.php
@@ -46,21 +46,24 @@ function startsWith( $haystack, $needle ) {
return substr( $haystack, 0, $length ) === $needle;
}
-$json = file_get_contents('https://oris.orientacnisporty.cz/API/?format=json&method=getRegistration&sport=1&year='.$ORIS_year);
-$obj = json_decode($json);
+require_once './lib/OrisIntegrationService.php';
+$service = new OrisIntegrationService(null);
+$obj = $service->getRegistration(1, $ORIS_year);
$arr_oris = array();
-foreach ($obj->Data as $key=>$value)
-{
- $user = new User();
- $user->create($value->UserID, $value->FirstName, $value->LastName, $value->RegNo, $value->SI, $value->ClubID);
-
- $reg = $value->RegNo;
- if (startsWith($reg, $g_shortcut))
+if (is_array($obj) || is_object($obj)) {
+ foreach ($obj as $key=>$value)
{
- $arr_oris["user"] [$reg]= $user;
- $arr_oris["members"][$reg] = 0;
+ $user = new User();
+ $user->create($value['UserID'], $value['FirstName'], $value['LastName'], $value['RegNo'], $value['SI'], $value['ClubID']);
+
+ $reg = $value['RegNo'];
+ if (startsWith($reg, $g_shortcut))
+ {
+ $arr_oris["user"] [$reg]= $user;
+ $arr_oris["members"][$reg] = 0;
+ }
}
}
//konec nahrani dat z orisu
diff --git a/ads_oris_si_sync.php b/ads_oris_si_sync.php
index c8e94aa..37f0b9b 100644
--- a/ads_oris_si_sync.php
+++ b/ads_oris_si_sync.php
@@ -29,7 +29,6 @@
'format' => 'json',
'method' => 'editPerson',
'userid' => $oris_id,
- 'si' => $zaznam['si_chip'],
'clubkey' => $g_oris_club_key,
'firstname' => $zaznam['jmeno'],
'lastname' => $zaznam['prijmeni'],
@@ -39,6 +38,9 @@
'zip' => $zaznam['psc'],
'country' => (!empty($zaznam['narodnost']) ? $zaznam['narodnost'] : 'CZ')
);
+ if (!empty($zaznam['si_chip']) && $zaznam['si_chip'] != 0 && $zaznam['si_chip'] !== '0') {
+ $params['si'] = $zaznam['si_chip'];
+ }
$url = "https://oris.ceskyorientak.cz/API/?" . http_build_query($params);
diff --git a/connectors.php b/connectors.php
index 69f2456..f91ab7f 100644
--- a/connectors.php
+++ b/connectors.php
@@ -1,398 +1,153 @@
-ext_id = $data['ext_id'] ?? null;
- $this->datum = $data['datum'] ?? null;
- $this->datum2 = $data['datum2'] ?? null;
- $this->nazev = $data['nazev'] ?? null;
- $this->misto = $data['misto'] ?? null;
- $this->oblasti = $data['oblasti'] ?? null;
- $this->typ = $data['typ'] ?? null;
- $this->zebricek2 = $data['zebricek2'] ?? null;
- $this->ranking = $data['ranking'] ?? null;
- $this->odkaz = $data['odkaz'] ?? null;
- $this->prihlasky = $data['prihlasky'] ?? null;
- $this->prihlasky1 = $data['prihlasky1'] ?? null;
- $this->prihlasky2 = $data['prihlasky2'] ?? null;
- $this->prihlasky3 = $data['prihlasky3'] ?? null;
- $this->prihlasky4 = $data['prihlasky4'] ?? null;
- $this->prihlasky5 = $data['prihlasky5'] ?? null;
- $this->koeficient1 = $data['koeficient1'] ?? null;
- $this->koeficient2 = $data['koeficient2'] ?? null;
- $this->etap = $data['etap'] ?? null;
- $this->poznamka = $data['poznamka'] ?? null;
- $this->vicedenni = $data['vicedenni'] ?? null;
- $this->oddil = $data['oddil'] ?? null;
- $this->modify_flag = $data['modify_flag'] ?? null;
- $this->kategorie = $data['kategorie'] ?? null;
- $this->startovne = $data['startovne'] ?? null;
- }
-}
-
-class RacePayement {
- public int $raceId;
- public RaceOverview $overview;
- /** @var array RegNo => User */
- public array $participants = [];
-
- public function __construct(int $raceId) {
- $this->raceId = $raceId;
- $this->overview = new RaceOverview();
- }
-
- public function addPatricipant(RaceParticipant $user): void {
- $this->participants[$user->regNo] = $user;
- }
-
- public function addCategory(string $name, int $feeTier, int $fee ): void {
- $this->overview->addCategory($name,$feeTier,$fee);
- }
-
- public function addService(string $name, int $fee, int $count ): void {
- $this->overview->addService( $name, $fee, $count );
- }
-}
-
-class RaceOverview {
- /** @var array> Category => [EntryStop => Fee] */
- public array $categories = [];
-
- /** @var array> ServiceName => [ Fee => Count ] */
- public array $services = [];
-
- /** @var array feeTier => exist */
- public array $feeTiers = [];
-
- public function addCategory(string $name, int $feeTier, int $fee ): void {
-
- if (!isset($this->categories[$name])) {
- $this->categories[$name] = [];
- }
- $this->categories[$name][$feeTier] = $fee;
-
- // Store only unique sorted feeTier values
- $this->feeTiers[$feeTier] = true;
- }
-
- public function addService(string $name, int $fee, int $count ): void {
- if ( isset ( $this->services[$name][$fee] ) ) {
- $this->services[$name][$fee] += $count;
- } else {
- $this->services[$name][$fee] = $count;
- }
- }
-}
-
-class RaceParticipant {
- public string $regNo;
- public string $classDesc;
- public string $name;
- public bool $rentSI;
- public string $licence;
- public $fee;
- public int $feeTier;
-
- public function __construct(string $regNo, string $classDesc, string $name, bool $rentSI, string|null $licence, int $fee, int $feeTier) {
- $this->regNo = $regNo;
- $this->classDesc = $classDesc;
- $this->name = $name;
- $this->rentSI = $rentSI;
- $this->licence = $licence ?? '';
- $this->fee = $fee;
- $this->feeTier = $feeTier;
- }
-}
-
-interface ConnectorInterface {
- public function getSystemName(): string;
- public function getRaceURL(string $id): string;
- public function getRaceInfo(string $id) : ?RaceInfo;
- public function getRacesList($fromDate, $toDate);
- public function getRacePayement(string $id) : ?RacePayement;
-}
-
-class OrisCZConnector implements ConnectorInterface {
- private $sourceUrl = 'https://oris.orientacnisporty.cz/';
- private $apiUrl;
-
- public function __construct() {
- $this->apiUrl = $this->sourceUrl . 'API/';
- }
-
- // Method to get the system name
- public function getSystemName(): string {
- return "Oris";
- }
-
- // RaceInfo URL
- public function getRaceURL($raceId) : string {
- return $this->sourceUrl . 'Zavod?id=' . $raceId;
- }
-
- private function mapLevelToZebricek2($levelId) {
- $map = [
- 1 => 17, // MCR
- 3 => 6, // ZB
- 4 => 8, // OZ
- 7 => 33, // CPS
- 8 => 1, // CP
- 11 => 24, // OM
- 17 => 17 // VET
- ];
- return $map[$levelId] ?? 0x0080; // Default to 0x80 if not found
- }
-
- private function mapSport($sportId) {
- //sport ID from ORIS : 1=OB, 2=LOB, 3=MTBO, 4=TRAIL
- $map = [
- 1 => 1, // OB
- 2 => 4, // LOB
- 3 => 2, // MTBO
- 4 => 8, // TRAIL
- ];
- return $map[$sportId] ?? 1; // Default is OB
- }
-
- private function getClubs(&$raceData) {
-
- $oddily = [];
- if (isset($raceData['Org1']['Abbr'])) {
- $oddily[] = $raceData['Org1']['Abbr'];
- }
- if (isset($raceData['Org2']['Abbr'])) {
- $oddily[] = $raceData['Org2']['Abbr'];
- }
- return implode('+', $oddily);
- }
-
- // Method to get race date based on race ID or provided response
- public function getRaceDate($raceId, $response = null) {
- // If no response provided, fetch it from API
- if ($response === null) {
- $url = $this->apiUrl . '?format=json&method=getEvent&id=' . $raceId;
- $response = $this->makeRequest($url);
- }
-
- if ($response && isset($response['Status']) && $response['Status'] === "OK") {
- $raceData = $response['Data'];
- return String2DateDMY(formatDate($raceData['Date']));
- }
-
- return ''; // Return empty string if race not found or error
- }
-
- // Method to get detailed race information based on race ID
- public function getRaceInfo($raceId) : RaceInfo {
- $url = $this->apiUrl . '?format=json&method=getEvent&id=' . $raceId;
-
- $response = $this->makeRequest($url);
-
- if ($response && $response['Status'] == "OK") {
- $raceData = $response['Data'];
-
- $classFees = [];
- if (isset($raceData['Classes'])) {
- foreach ($raceData['Classes'] as $class) {
- if (isset($class['Name'])) {
- $name = $class['Name'];
- $fee = $class['Fee'] ?? null; // default to null if missing
- $classFees[$name] = $fee;
- }
- }
- }
-
- ksort ( $classFees );
-
- $oddily = $this->getClubs($raceData);
- $oblasti = [];
- if (isset($raceData['Regions'])) {
- foreach ($raceData['Regions'] as $tag => $region) {
- $oblasti[] = $region['ID'];
- }
- }
-
- // Get last Stage date if multistage event
- $date2 = ($raceData['Stages'] > 1) ? $this->getRaceDate($raceData['Stage'.$raceData['Stages']], $response) : 0;
- // Use associative array to pass data to constructor
- return new RaceInfo([
- 'ext_id' => $raceData['ID'],
- 'datum' => String2DateDMY(formatDate($raceData['Date'])),
- 'datum2' => $date2,
- 'nazev' => $raceData['Name'],
- 'misto' => $raceData['Place'],
-// 'category' => $raceData['Category'],
- //typ0 => Typ akce
- 'oblasti' => $oblasti,
- 'typ0' => 'Z',
- 'typ' => $this->mapSport($raceData['Sport']['ID']),
- 'zebricek2' => $this->mapLevelToZebricek2($raceData['Level']['ID']),
- 'ranking' => $raceData['Ranking'],
- 'odkaz' => $this->getRaceURL($raceData['ID']),
- 'prihlasky' => strtotime($raceData['EntryDate1']),
- 'prihlasky1' => strtotime($raceData['EntryDate2']),
- 'prihlasky2' => strtotime($raceData['EntryDate3']),
-// 'prihlasky3' => '',
-// 'prihlasky4' => '',
-// 'prihlasky5' => '',
- 'koeficient1' => $raceData['EntryKoef2'],
- 'koeficient2' => $raceData['EntryKoef3'],
- 'etap' => $raceData['Stages'],
-// 'poznamka' => $poznamka,
- 'vicedenni' => ($raceData['Stages']>1?1:0),
- 'oddil' => $oddily,
- 'modify_flag' => 0,
- 'kategorie' => implode(';', array_keys ( $classFees ) ),
- 'startovne' => $classFees
- ]);
- } else {
- return null; // Return null if race not found or error
- }
- }
-
- // Helper method to make HTTP requests
- private function makeRequest($url) {
- $response = file_get_contents($url);
-
- // Decode JSON response
- return json_decode($response, true);
- }
-
- private function makeRequestCurl($url) {
- $ch = curl_init($url);
-
- // Set curl options
- curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
- $response = curl_exec($ch);
-
- // Check for errors
- if (curl_errno($ch)) {
- echo 'Curl error: ' . curl_error($ch);
- return null;
- }
-
- curl_close($ch);
-
- // Decode JSON response
- return json_decode($response, true);
- }
-
- function getRacesList($fromDate, $toDate) {
- $url = $this->apiUrl.'?format=json&method=getEventList&all=1&datefrom='.$fromDate.'&dateto='.$toDate;
-// echo($url.'
');
- $response = $this->makeRequest($url);
-
- if ($response && $response['Status'] == "OK") {
- $racesData = $response['Data'];
- $rows = array();
- foreach($racesData as $oneRace) {
- $oddily = $this->getClubs($oneRace);
-
- $row = array();
- $row[] = $oneRace['ID'];
- $row[] = $oneRace['Date'];
- $row[] = $oneRace['Name'];
- $row[] = $oddily;
- $rows[] = $row;
- }
- return $rows;
- } else {
- return null; // Return null if race not found or error
- }
- }
-
- // Method to get detailed race information based on race ID
- public function getRacePayement($raceId) : ?RacePayement {
-
- global $g_external_is_club_id;
-
- if ( !IsSet ($g_external_is_club_id) || $g_external_is_club_id === '' ) return null;
-
- $url = $this->apiUrl . '?format=json&method=getEventEntries&clubid=' . $g_external_is_club_id . '&eventid=' . $raceId;
-
- $response = $this->makeRequest($url);
- $racePayement = null;
-
- if ($response && $response['Status'] == "OK") {
- $racePayement = new RacePayement($raceId);
-
- foreach ($response['Data'] as $entry) {
- if (isset($entry['Fee'])) {
- if (isset($entry['RegNo']) ) {
- $racePayement->addPatricipant(
- new RaceParticipant($entry['RegNo'], $entry['ClassDesc'], $entry['Name'],
- $entry['RentSI'], $entry['Licence'], (int)$entry['Fee'], $entry['EntryStop']));
- }
- if (isset($entry['ClassDesc'])&&isset($entry['ClassDesc'])) {
- $racePayement->addCategory($entry['ClassDesc'], $entry['EntryStop'], (int)$entry['Fee']);
- }
- }
- }
- }
-
- $url = $this->apiUrl . '?format=json&method=getEventServiceEntries&clubid=' . $g_external_is_club_id . '&eventid=' . $raceId;
-
- $response = $this->makeRequest($url);
-
- if ($response && $response['Status'] == "OK") {
- if ( $racePayement === null ) $racePayement = new RacePayement($raceId);
- foreach ($response['Data'] as $entry) {
- if ( isset ( $entry['Service'] ) ) {
- $racePayement->addService($entry['Service']['NameCZ'] ?? 'Name?', $entry['Service']['UnitPrice'] , $entry['Quantity'] );
- } else {
- if ( isset ( $entry['Quantity'] ) && isset ( $entry['TotalFee'] ) ) {
- $racePayement->addService('Name?', $entry['TotalFee'] / $entry['Quantity'], $entry['Quantity'] );
- }
- }
- }
- }
-
- //print_r ($racePayement);
-
- return $racePayement;
- }
-}
-
-class ConnectorFactory {
- public static function create(): ?ConnectorInterface {
- global $g_external_is_connector;
-
- if ( $g_external_is_connector && class_exists( $g_external_is_connector)) {
- return new $g_external_is_connector();
- }
-
- return null; // Return null explicitly if no valid connector is found
- }
-}
+service = new OrisIntegrationService(null);
+ }
+
+ public function getSystemName(): string {
+ return "Oris";
+ }
+
+ public function getRaceURL($raceId) : string {
+ return $this->sourceUrl . 'Zavod?id=' . $raceId;
+ }
+
+ private function mapLevelToZebricek2($levelId) {
+ $map = [
+ 1 => 17, // MCR
+ 3 => 6, // ZB
+ 4 => 8, // OZ
+ 7 => 33, // CPS
+ 8 => 1, // CP
+ 11 => 24, // OM
+ 17 => 17 // VET
+ ];
+ return $map[$levelId] ?? 0x0080; // Default to 0x80 if not found
+ }
+
+ private function mapSport($sportId) {
+ $map = [
+ 1 => 1, // OB
+ 2 => 4, // LOB
+ 3 => 2, // MTBO
+ 4 => 8, // TRAIL
+ ];
+ return $map[$sportId] ?? 1; // Default is OB
+ }
+
+ private function getClubs(&$raceData) {
+ $oddily = [];
+ if (isset($raceData['Org1']['Abbr'])) {
+ $oddily[] = $raceData['Org1']['Abbr'];
+ }
+ if (isset($raceData['Org2']['Abbr'])) {
+ $oddily[] = $raceData['Org2']['Abbr'];
+ }
+ return implode('+', $oddily);
+ }
+
+ public function getRaceDate($raceId) {
+ try {
+ $raceData = $this->service->getEvent($raceId);
+ if (isset($raceData['Date'])) {
+ return String2DateDMY(formatDate($raceData['Date']));
+ }
+ } catch (OrisException $e) {
+ // fallback
+ }
+ return '';
+ }
+
+ public function getRaceInfo($raceId) {
+ try {
+ $raceData = $this->service->getEvent($raceId);
+
+ $classNames = [];
+ if (isset($raceData['Classes'])) {
+ foreach ($raceData['Classes'] as $class) {
+ if (isset($class['Name'])) {
+ $classNames[] = $class['Name'];
+ }
+ }
+ }
+
+ sort($classNames);
+ $oddily = $this->getClubs($raceData);
+
+ $date2 = ($raceData['Stages'] > 1) ? $this->getRaceDate($raceData['Stage'.$raceData['Stages']]) : 0;
+
+ return new RaceDTO([
+ 'ext_id' => $raceData['ID'],
+ 'datum' => String2DateDMY(formatDate($raceData['Date'])),
+ 'datum2' => $date2,
+ 'nazev' => $raceData['Name'],
+ 'misto' => $raceData['Place'],
+ 'typ0' => 'Z',
+ 'typ' => $this->mapSport($raceData['Sport']['ID']),
+ 'zebricek2' => $this->mapLevelToZebricek2($raceData['Level']['ID']),
+ 'ranking' => $raceData['Ranking'],
+ 'odkaz' => $this->getRaceURL($raceData['ID']),
+ 'prihlasky' => strtotime($raceData['EntryDate1']),
+ 'prihlasky1' => strtotime($raceData['EntryDate2']),
+ 'prihlasky2' => strtotime($raceData['EntryDate3']),
+ 'etap' => $raceData['Stages'],
+ 'vicedenni' => ($raceData['Stages']>1?1:0),
+ 'oddil' => $oddily,
+ 'modify_flag' => 0,
+ 'kategorie' => implode(';', $classNames ),
+ 'oris_entry_start' => !empty($raceData['EntryStart']) ? $raceData['EntryStart'] : null
+ ]);
+ } catch (OrisException $e) {
+ return null;
+ }
+ }
+
+ function getRacesList($fromDate, $toDate) {
+ try {
+ $racesData = $this->service->getEventList($fromDate, $toDate, 1);
+ $rows = array();
+ foreach($racesData as $oneRace) {
+ $oddily = $this->getClubs($oneRace);
+
+ $row = array();
+ $row[] = $oneRace['ID'];
+ $row[] = $oneRace['Date'];
+ $row[] = $oneRace['Name'];
+ $row[] = $oddily;
+ $rows[] = $row;
+ }
+ return $rows;
+ } catch (OrisException $e) {
+ return null;
+ }
+ }
+}
+
+class ConnectorFactory {
+ public static function create(): ?ConnectorInterface {
+ global $g_external_is_connector;
+
+ if ( $g_external_is_connector && class_exists( $g_external_is_connector)) {
+ return new $g_external_is_connector();
+ }
+
+ return null;
+ }
+}
diff --git a/lib/OrisDTOs.php b/lib/OrisDTOs.php
new file mode 100644
index 0000000..d57f018
--- /dev/null
+++ b/lib/OrisDTOs.php
@@ -0,0 +1,91 @@
+ext_id = $data['ext_id'] ?? null;
+ $this->datum = $data['datum'] ?? null;
+ $this->datum2 = $data['datum2'] ?? null;
+ $this->nazev = $data['nazev'] ?? null;
+ $this->misto = $data['misto'] ?? null;
+ $this->typ = $data['typ'] ?? null;
+ $this->zebricek2 = $data['zebricek2'] ?? null;
+ $this->ranking = $data['ranking'] ?? null;
+ $this->odkaz = $data['odkaz'] ?? null;
+ $this->prihlasky = $data['prihlasky'] ?? null;
+ $this->prihlasky1 = $data['prihlasky1'] ?? null;
+ $this->prihlasky2 = $data['prihlasky2'] ?? null;
+ $this->prihlasky3 = $data['prihlasky3'] ?? null;
+ $this->prihlasky4 = $data['prihlasky4'] ?? null;
+ $this->prihlasky5 = $data['prihlasky5'] ?? null;
+ $this->etap = $data['etap'] ?? null;
+ $this->poznamka = $data['poznamka'] ?? null;
+ $this->vicedenni = $data['vicedenni'] ?? null;
+ $this->oddil = $data['oddil'] ?? null;
+ $this->modify_flag = $data['modify_flag'] ?? null;
+ $this->kategorie = $data['kategorie'] ?? null;
+ $this->oris_entry_start = $data['oris_entry_start'] ?? null;
+ $this->typ0 = $data['typ0'] ?? null;
+ }
+}
+
+class OrisEntryRequestDTO {
+ public ?string $clubuser;
+ public ?string $classId;
+ public ?string $si;
+ public int $rentSi;
+ public ?string $note;
+ public ?string $entryId;
+
+ public function __construct(
+ ?string $clubuser,
+ ?string $classId,
+ ?string $si,
+ bool $rentSi = false,
+ ?string $note = null,
+ ?string $entryId = null
+ ) {
+ $this->clubuser = $clubuser;
+ $this->classId = $classId;
+ $this->si = $si;
+ $this->rentSi = $rentSi ? 1 : 0;
+ $this->note = $note;
+ $this->entryId = $entryId;
+ }
+
+ public function toArray(): array {
+ $data = [];
+ if ($this->clubuser !== null) $data['clubuser'] = $this->clubuser;
+ if ($this->classId !== null) $data['class'] = $this->classId;
+ if ($this->si !== null && $this->si !== '' && $this->si !== '0' && $this->si !== 0) {
+ $data['si'] = $this->si;
+ }
+ $data['rent_si'] = $this->rentSi ? 1 : 0;
+ if ($this->note !== null && $this->note !== '') $data['note'] = $this->note;
+ if ($this->entryId !== null) $data['entryid'] = $this->entryId;
+ return $data;
+ }
+}
diff --git a/lib/OrisExceptions.php b/lib/OrisExceptions.php
new file mode 100644
index 0000000..4cda17f
--- /dev/null
+++ b/lib/OrisExceptions.php
@@ -0,0 +1,26 @@
+apiStatus = $apiStatus;
+ $this->apiData = $apiData;
+ }
+
+ public function getApiStatus() {
+ return $this->apiStatus;
+ }
+
+ public function getApiData() {
+ return $this->apiData;
+ }
+}
+
+class OrisValidationException extends OrisException {}
diff --git a/lib/OrisIntegrationService.php b/lib/OrisIntegrationService.php
new file mode 100644
index 0000000..9e379c3
--- /dev/null
+++ b/lib/OrisIntegrationService.php
@@ -0,0 +1,120 @@
+clubKey = $clubKey;
+ }
+
+ /**
+ * Internal generic HTTP request method.
+ */
+ private function makeRequest($method, $params = [], $isPost = false) {
+ $params['method'] = $method;
+ $params['format'] = 'json';
+ if ($this->clubKey) {
+ $params['clubkey'] = $this->clubKey;
+ }
+
+ $ch = curl_init();
+
+ if ($isPost) {
+ $postData = http_build_query($params);
+ curl_setopt($ch, CURLOPT_URL, $this->apiUrl);
+ curl_setopt($ch, CURLOPT_POST, 1);
+ curl_setopt($ch, CURLOPT_POSTFIELDS, $postData);
+ } else {
+ $url = $this->apiUrl . '?' . http_build_query($params);
+ curl_setopt($ch, CURLOPT_URL, $url);
+ }
+
+ curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
+ curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);
+ curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);
+
+ $response = curl_exec($ch);
+
+ if(curl_errno($ch)){
+ $error = curl_error($ch);
+ curl_close($ch);
+ throw new OrisNetworkException('cURL Error: ' . $error);
+ }
+
+ $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
+ curl_close($ch);
+
+ $decoded = json_decode($response, true);
+
+ if ($httpCode >= 200 && $httpCode < 300 && isset($decoded['Status']) && $decoded['Status'] === 'OK') {
+ return $decoded['Data'] ?? $decoded;
+ } else {
+ $apiStatus = $decoded['Status'] ?? 'Unknown';
+ $apiData = $decoded['Data'] ?? null;
+ $msg = "API Error or HTTP {$httpCode}. Status: {$apiStatus}";
+ if ($isPost) {
+ $msg .= "\nPOST Data sent: " . print_r($params, true);
+ }
+ if (is_string($apiData)) {
+ $msg .= " - " . $apiData;
+ }
+ throw new OrisApiException($msg, $apiStatus, $apiData);
+ }
+ }
+
+ // --- Write/Mutating Operations (Phase C) ---
+
+ public function createEntry(OrisEntryRequestDTO $dto) {
+ return $this->makeRequest('createEntry', $dto->toArray(), true);
+ }
+
+ public function updateEntry(OrisEntryRequestDTO $dto) {
+ return $this->makeRequest('updateEntry', $dto->toArray(), true);
+ }
+
+ public function deleteEntry($entryId) {
+ return $this->makeRequest('deleteEntry', ['entryid' => $entryId], true);
+ }
+
+ // --- Read-Only and Protected Read Endpoints (Phase A & B) ---
+
+ public function getUser($rgnum) {
+ return $this->makeRequest('getUser', ['rgnum' => $rgnum]);
+ }
+
+ public function getClubUsers($userId) {
+ return $this->makeRequest('getClubUsers', ['user' => $userId]);
+ }
+
+ public function getEventEntries($eventId) {
+ return $this->makeRequest('getEventEntries', ['eventid' => $eventId]);
+ }
+
+ public function getEvent($eventId) {
+ return $this->makeRequest('getEvent', ['id' => $eventId]);
+ }
+
+ public function getEventList($fromDate, $toDate, $all = 1) {
+ return $this->makeRequest('getEventList', [
+ 'all' => $all,
+ 'datefrom' => $fromDate,
+ 'dateto' => $toDate
+ ]);
+ }
+
+ public function getRegistration($sport, $year) {
+ return $this->makeRequest('getRegistration', [
+ 'sport' => $sport,
+ 'year' => $year
+ ]);
+ }
+}
diff --git a/lib/oris_sync.inc.php b/lib/oris_sync.inc.php
new file mode 100644
index 0000000..44a64d5
--- /dev/null
+++ b/lib/oris_sync.inc.php
@@ -0,0 +1,370 @@
+getUser($rgnum);
+ if (is_array($userApiRes) && isset($userApiRes['ID'])) {
+ $globalUserId = $userApiRes['ID'];
+
+ // Now get the club user ID
+ try {
+ $clubUsersRes = $service->getClubUsers($globalUserId);
+ if (is_array($clubUsersRes)) {
+ $clubUsers = $clubUsersRes;
+ // Check if it's associative array representing a single user directly
+ if (isset($clubUsers['ID'])) {
+ $clubUsers = [$clubUsers];
+ }
+
+ // We must find the correct clubuser entry for the current club
+ // First, try to fetch current club key from config
+ global $g_external_is_club_id;
+ $clubId = $g_external_is_club_id ?? null;
+
+ foreach ($clubUsers as $cu) {
+ if (isset($cu['ID'])) {
+ // If club ID is known, prefer that match
+ if ($clubId && isset($cu['ClubID']) && $cu['ClubID'] == $clubId) {
+ $clubuser = $cu['ID'];
+ break;
+ }
+ // Otherwise, just take the first one or valid one
+ if (empty($clubuser)) {
+ $clubuser = $cu['ID'];
+ }
+ }
+ }
+ }
+ } catch (Exception $e) {
+ $errMsg = $e->getMessage();
+ logMessage(" - Warning: getClubUsers failed for user ID $globalUserId: $errMsg");
+ if ($e instanceof OrisNetworkException || ($e instanceof OrisApiException && strpos($errMsg, 'API Error or HTTP 5') !== false)) {
+ logMessage(" - Network error getting club users. Skipping to keep PENDING.");
+ return 'queued';
+ }
+ }
+
+ if (empty($clubuser)) {
+ logMessage(" - Warning: Could not resolve ORIS Club User ID for user ID $globalUserId");
+ }
+ } else {
+ logMessage(" - Warning: Could not resolve ORIS User ID for rgnum $rgnum");
+ }
+ } catch (Exception $e) {
+ $errMsg = $e->getMessage();
+ logMessage(" - Warning: getUser failed for rgnum $rgnum: $errMsg");
+ if ($e instanceof OrisNetworkException || ($e instanceof OrisApiException && strpos($errMsg, 'API Error or HTTP 5') !== false)) {
+ logMessage(" - Network error getting user. Skipping to keep PENDING.");
+ return 'queued';
+ }
+ }
+ }
+ }
+ }
+
+ // Get Race ORIS ID
+ $raceQuery = "SELECT * FROM `" . TBL_RACE . "` WHERE `id` = " . (int)$raceId;
+ $raceRes = query_db($raceQuery);
+ $raceRow = mysqli_fetch_assoc($raceRes);
+
+ // Ensure the race was imported from ORIS
+ $comp = $raceRow['ext_id'] ?? null;
+ if (empty($comp)) {
+ logMessage(" - Skipped: Race $raceId is not imported from ORIS (no ext_id). Marking LOCAL_ONLY.");
+ $updateQuery = "UPDATE `" . TBL_ZAVXUS . "` SET `sync_status` = 'LOCAL_ONLY' WHERE `id` = " . (int)$id;
+ query_db($updateQuery);
+ return;
+ }
+
+ // Ignore relays and sprint relays
+ // S is typically for štafety (relays) in local DB
+ if ($raceRow && isset($raceRow['typ0']) && $raceRow['typ0'] === 'S') {
+ logMessage(" - Skipped: Race $raceId is a relay (typ0 = S). Marking LOCAL_ONLY.");
+ $updateQuery = "UPDATE `" . TBL_ZAVXUS . "` SET `sync_status` = 'LOCAL_ONLY' WHERE `id` = " . (int)$id;
+ query_db($updateQuery);
+ return;
+ }
+
+ // Fetch Classes from ORIS Event to map the string category (e.g. H21) to the ORIS class ID
+ $classId = null;
+ $katName = $row['kat'];
+ if (!empty($comp)) {
+ try {
+ $eventRes = $service->getEvent($comp);
+ if (is_array($eventRes) && isset($eventRes['Classes'])) {
+ $classes = is_array($eventRes['Classes']) ? $eventRes['Classes'] : [];
+
+ foreach ($classes as $cls) {
+ if (!is_array($cls)) continue;
+ $clsName = $cls['Name'] ?? '';
+ // Some categories might have different spacing or case
+ if (trim($clsName) === trim($katName)) {
+ $classId = $cls['ID'] ?? null;
+ break;
+ }
+ }
+ }
+ } catch (Exception $e) {
+ $errMsg = $e->getMessage();
+ logMessage(" - Warning: getEvent failed for event $comp: $errMsg");
+ if ($e instanceof OrisNetworkException || ($e instanceof OrisApiException && strpos($errMsg, 'API Error or HTTP 5') !== false)) {
+ logMessage(" - Network error getting event. Skipping to keep PENDING.");
+ return 'queued';
+ }
+ }
+ }
+
+ if (empty($classId)) {
+ logMessage(" - Warning: Could not resolve ORIS Class ID for category '$katName'");
+ $errorPayload = correct_sql_string(json_encode(['status' => 'error', 'message' => "Nelze spárovat kategorii '$katName' s ORISem."]));
+ $failedStatus = 'FAILED_' . strtoupper($action);
+ $updateQuery = "UPDATE `" . TBL_ZAVXUS . "`
+ SET `sync_status` = '$failedStatus',
+ `sync_error_payload` = '$errorPayload'
+ WHERE `id` = " . (int)$id;
+ query_db($updateQuery);
+ return false;
+ }
+
+ $si = $row['si_chip'];
+ if (empty($si) && !empty($userRow['si_chip'])) {
+ $si = $userRow['si_chip'];
+ }
+ $rentSi = $row['rent_si'] ?? 0; // assuming rent_si is added or mapped
+ $note = $row['pozn'] ?? '';
+
+ $response = [];
+ logMessage(" - Sending $action request to ORIS API. clubuser: $clubuser, class: $classId (mapped from $katName), si: $si");
+
+ if (empty($clubuser)) {
+ logMessage(" - Failed: Cannot perform action '$action' because ORIS Club User ID (clubuser) could not be resolved.");
+ $errorPayload = correct_sql_string(json_encode(['status' => 'error', 'message' => 'Chybí ORIS ID uživatele v klubu (clubuser).']));
+ $failedStatus = 'FAILED_' . strtoupper($action);
+ $updateQuery = "UPDATE `" . TBL_ZAVXUS . "`
+ SET `sync_status` = '$failedStatus',
+ `sync_error_payload` = '$errorPayload'
+ WHERE `id` = " . (int)$id;
+ query_db($updateQuery);
+ return false;
+ }
+
+ try {
+ if ($action === 'create') {
+ // Check if it already exists before creating to avoid "Již přihlášen"
+ $existingEntryId = null;
+ if (!empty($comp) && !empty($clubuser)) {
+ try {
+ $entriesRes = $service->getEventEntries($comp);
+ if (is_array($entriesRes)) {
+ $entries = $entriesRes;
+ foreach ($entries as $entry) {
+ if (isset($entry['ClubUserID']) && $entry['ClubUserID'] == $clubuser) {
+ $existingEntryId = $entry['ID'];
+ logMessage(" - Found existing ORIS Entry ID $existingEntryId for clubuser $clubuser during create. Switching to update.");
+ break;
+ }
+ }
+ }
+ } catch (Exception $e) {
+ logMessage(" - Warning: getEventEntries failed: " . $e->getMessage());
+ }
+ }
+
+ if (!empty($existingEntryId)) {
+ $updateDto = new OrisEntryRequestDTO($clubuser, $classId, $si, (bool)$rentSi, $note, $existingEntryId);
+ $response = $service->updateEntry($updateDto);
+ // Also update the action string so log messages below make sense
+ $action = 'update';
+ } else {
+ $createDto = new OrisEntryRequestDTO($clubuser, $classId, $si, (bool)$rentSi, $note);
+ $response = $service->createEntry($createDto);
+ }
+ } elseif ($action === 'update') {
+ $entryIdToUpdate = $row['oris_entry_id'] ?? null;
+
+ if (empty($entryIdToUpdate) && !empty($comp) && !empty($clubuser)) {
+ logMessage(" - Warning: Missing ORIS Entry ID for update. Attempting to fetch from ORIS.");
+ try {
+ $entriesRes = $service->getEventEntries($comp);
+ if (is_array($entriesRes)) {
+ $entries = $entriesRes;
+ foreach ($entries as $entry) {
+ if (isset($entry['ClubUserID']) && $entry['ClubUserID'] == $clubuser) {
+ $entryIdToUpdate = $entry['ID'];
+ logMessage(" - Found ORIS Entry ID $entryIdToUpdate for clubuser $clubuser");
+ break;
+ }
+ }
+ }
+ } catch (Exception $e) {
+ logMessage(" - Warning: getEventEntries failed: " . $e->getMessage());
+ }
+ }
+
+ if (empty($entryIdToUpdate)) {
+ // It was never created on ORIS side successfully, so let's fall back to create instead of failing
+ logMessage(" - Warning: Missing ORIS Entry ID for update. Falling back to create.");
+ $createDto = new OrisEntryRequestDTO($clubuser, $classId, $si, (bool)$rentSi, $note);
+ $response = $service->createEntry($createDto);
+ } else {
+ $updateDto = new OrisEntryRequestDTO($clubuser, $classId, $si, (bool)$rentSi, $note, $entryIdToUpdate);
+ $response = $service->updateEntry($updateDto);
+ }
+ } elseif ($action === 'delete') {
+ $entryIdToDelete = $row['oris_entry_id'] ?? null;
+
+ // If we don't have the entry ID locally, we must fetch it from ORIS first
+ if (empty($entryIdToDelete) && !empty($comp) && !empty($clubuser)) {
+ logMessage(" - Warning: Missing ORIS Entry ID for delete. Attempting to fetch from ORIS.");
+ try {
+ $entriesRes = $service->getEventEntries($comp);
+ if (is_array($entriesRes)) {
+ $entries = $entriesRes;
+ foreach ($entries as $entry) {
+ if (isset($entry['ClubUserID']) && $entry['ClubUserID'] == $clubuser) {
+ $entryIdToDelete = $entry['ID'];
+ logMessage(" - Found ORIS Entry ID $entryIdToDelete for clubuser $clubuser");
+ break;
+ }
+ }
+ }
+ } catch (Exception $e) {
+ logMessage(" - Warning: getEventEntries failed: " . $e->getMessage());
+ }
+ }
+
+ if (empty($entryIdToDelete)) {
+ // Already doesn't exist remotely or could not be found
+ logMessage(" - Warning: Could not find ORIS Entry ID to delete. Assuming already deleted.");
+ $response = ['ID' => null];
+ } else {
+ $response = $service->deleteEntry($entryIdToDelete);
+ }
+ }
+
+ // Log the exact raw payload sent to ORIS if available (custom debug info)
+ if (isset($response['request'])) {
+ logMessage(" - Raw POST Data: " . $response['request']);
+ }
+
+ // Action succeeded since no exception was thrown
+ // 'create' usually returns ID in $response['ID']
+ // 'update' might not return the ID, so we use the one we just found/used
+ $entryId = $response['ID'] ?? null;
+ if (empty($entryId)) {
+ if ($action === 'update' && !empty($entryIdToUpdate)) {
+ $entryId = $entryIdToUpdate;
+ } elseif ($action === 'update' && !empty($existingEntryId)) { // from the create fallback block
+ $entryId = $existingEntryId;
+ } else {
+ $entryId = $row['oris_entry_id'];
+ }
+ }
+
+ logMessage(" - Success: Action $action completed. ORIS Entry ID: " . ($entryId ?: "N/A"));
+
+ if ($action === 'delete') {
+ // Remove the row locally after successful delete
+ $updateQuery = "DELETE FROM `" . TBL_ZAVXUS . "` WHERE `id` = " . (int)$id;
+ query_db($updateQuery);
+ } else {
+ // Update the row
+ $updateQuery = "UPDATE `" . TBL_ZAVXUS . "`
+ SET `sync_status` = 'SYNCED',
+ `oris_entry_id` = " . ($entryId ? (int)$entryId : "NULL") . ",
+ `sync_timestamp` = NOW(),
+ `sync_error_payload` = NULL
+ WHERE `id` = " . (int)$id;
+ query_db($updateQuery);
+ }
+ return true;
+
+ } catch (Exception $e) {
+ $errMsg = $e->getMessage();
+ logMessage(" - Failed: Action $action encountered an error: $errMsg");
+
+ if ($e instanceof OrisNetworkException || ($e instanceof OrisApiException && strpos($errMsg, 'API Error or HTTP 5') !== false)) {
+ // It's a temporary network error or 5xx server error, keep it as PENDING and retry later
+ logMessage(" - Will keep entry in PENDING status for retry later because it is a network error.");
+ return 'queued';
+ }
+
+ $errorData = [
+ 'status' => 'error',
+ 'message' => $errMsg,
+ 'api_status' => ($e instanceof OrisApiException) ? $e->getApiStatus() : 'Exception'
+ ];
+ $errorPayload = correct_sql_string(json_encode($errorData));
+ $failedStatus = 'FAILED_' . strtoupper($action);
+ $updateQuery = "UPDATE `" . TBL_ZAVXUS . "`
+ SET `sync_status` = '$failedStatus',
+ `sync_error_payload` = '$errorPayload'
+ WHERE `id` = " . (int)$id;
+ query_db($updateQuery);
+ return false;
+ }
+}
+
+function getOrisSyncError($id) {
+ $q = query_db("SELECT sync_error_payload FROM `" . TBL_ZAVXUS . "` WHERE `id` = " . (int)$id);
+ if ($q && $r = mysqli_fetch_assoc($q)) {
+ if (!empty($r['sync_error_payload'])) {
+ $err = json_decode($r['sync_error_payload'], true);
+ return $err['message'] ?? 'Neznámá chyba';
+ }
+ }
+ return 'Neznámá chyba';
+}
+?>
diff --git a/nav.inc.php b/nav.inc.php
index 218bcde..df810fa 100644
--- a/nav.inc.php
+++ b/nav.inc.php
@@ -100,6 +100,8 @@ function DrawMenuGroupHeader($name)
DrawMenuGroupHeader('Menu přihlašovatele');
DrawMenuItem('Přihlášky na závody',_REGISTRATOR_GROUP_ID_,1);
DrawMenuItem('Editace závodů',_REGISTRATOR_GROUP_ID_,4);
+ DrawMenuItemStatic('Synchronizuj přihlášky s ORISem', 'adm_oris_sync.php');
+ DrawMenuItemStatic('ORIS Sync Log', 'rg_oris_sync_log.php');
}
if(IsLoggedManager())
{
diff --git a/oris_sync_daemon.php b/oris_sync_daemon.php
new file mode 100644
index 0000000..1552854
--- /dev/null
+++ b/oris_sync_daemon.php
@@ -0,0 +1,70 @@
+= DATE_SUB(CURDATE(), INTERVAL 1 DAY) OR r.datum IS NULL)
+ ORDER BY ISNULL(r.oris_entry_start), r.oris_entry_start ASC
+ ";
+$res = query_db($query);
+
+while ($row = mysqli_fetch_assoc($res)) {
+ $entryStartStr = $row['oris_entry_start'];
+ if (!empty($entryStartStr)) {
+ $entryStartTime = strtotime($entryStartStr);
+ $now = time();
+ if ($entryStartTime > $now) {
+ $diff = $entryStartTime - $now;
+ if ($diff <= 65) { // 65 seconds buffer for cron running every minute
+ logMessage("Prihlasky se oteviraji za $diff seconds (at $entryStartStr). Jdu sapt pred pokracovanim...");
+ sleep($diff);
+ } else {
+ // Race is not open yet and more than a minute away, skip for now
+ logMessage("Preskakuju prihlasku ID {$row['id']} - Zavod otevira prihlasky v $entryStartStr (za $diff s).");
+ continue;
+ }
+ }
+ }
+
+ $action = '';
+ if ($row['sync_status'] === 'PENDING_CREATE' || $row['sync_status'] === 'FAILED_CREATE') {
+ $action = 'create';
+ } elseif ($row['sync_status'] === 'PENDING_UPDATE' || $row['sync_status'] === 'FAILED_UPDATE') {
+ $action = 'update';
+ } elseif ($row['sync_status'] === 'PENDING_DELETE' || $row['sync_status'] === 'FAILED_DELETE') {
+ $action = 'delete';
+ }
+
+ if (!empty($action)) {
+ processEntry($row, $action, $service);
+ }
+}
+?>
diff --git a/race_edit.php b/race_edit.php
index 4fe2f4d..02e36fa 100644
--- a/race_edit.php
+++ b/race_edit.php
@@ -372,6 +372,11 @@ function toggleButtonState() {
|
+
+if ($raceInfo->oris_entry_start !== null) {
+ echo '';
+}
+?>
echo(insertDocuOnLoad());
diff --git a/race_edit_exc.php b/race_edit_exc.php
index 4714392..bca6b7a 100644
--- a/race_edit_exc.php
+++ b/race_edit_exc.php
@@ -120,17 +120,20 @@ function gen_modify_flag_v2b($val_last,$val_new)
$transport=0;
if (!isset($accommodation))
$accommodation=0;
+ if (isset($cancelled) && $cancelled=='on')
+ $cancelled=1;
+ else
+ $cancelled=0;
- $transport=(int)$transport;
- $accommodation=(int)$accommodation;
+ $kapacitaSql = isset($kapacita) && $kapacita !== '' && is_numeric($kapacita) ? (int)$kapacita : 'NULL';
- $kapacitaSql = (!isset($kapacita) || $kapacita === '')
- ? 'NULL'
- : (int)$kapacita;
-
- $cancelled = !isset($cancelled)? 0: 1;
+ $oris_entry_start_sql = "";
+ if (isset($oris_entry_start)) {
+ $oris_entry_start_val = (!empty($oris_entry_start)) ? "'".correct_sql_string($oris_entry_start)."'" : "NULL";
+ $oris_entry_start_sql = ", oris_entry_start=$oris_entry_start_val";
+ }
- $result=query_db("UPDATE ".TBL_RACE." SET ext_id='$ext_id', datum='$datum', datum2='$datum2', nazev='$nazev', misto='$misto', typ0='$typ0', typ='$typ', zebricek='$zebricek2', ranking='$ranking', prihlasky='$prihlasky', odkaz='$odkaz', prihlasky1='$prihlasky1', prihlasky2='$prihlasky2', prihlasky3='$prihlasky3', prihlasky4='$prihlasky4', prihlasky5='$prihlasky5', etap='$etap', poznamka='$poznamka', oddil='$oddil', modify_flag='$modify_flag', transport='$transport', ubytovani='$accommodation', kapacita=$kapacitaSql, cancelled='$cancelled' WHERE id='$id'")
+ $result=query_db("UPDATE ".TBL_RACE." SET ext_id='$ext_id', datum='$datum', datum2='$datum2', nazev='$nazev', misto='$misto', typ0='$typ0', typ='$typ', zebricek='$zebricek2', ranking='$ranking', prihlasky='$prihlasky', odkaz='$odkaz', prihlasky1='$prihlasky1', prihlasky2='$prihlasky2', prihlasky3='$prihlasky3', prihlasky4='$prihlasky4', prihlasky5='$prihlasky5', etap='$etap', poznamka='$poznamka', oddil='$oddil', modify_flag='$modify_flag', transport='$transport', ubytovani='$accommodation', kapacita=$kapacitaSql, cancelled='$cancelled' $oris_entry_start_sql WHERE id='$id'")
or die("Chyba při provádění dotazu do databáze.");
if ($result == FALSE)
die ("Nepodařilo se změnit údaje o závodě.");
diff --git a/race_new.php b/race_new.php
index d3197b0..b822a45 100644
--- a/race_new.php
+++ b/race_new.php
@@ -270,6 +270,7 @@
+
diff --git a/race_new_exc.php b/race_new_exc.php
index 4af3405..de9cda9 100644
--- a/race_new_exc.php
+++ b/race_new_exc.php
@@ -88,9 +88,10 @@
$accommodation=(int)$accommodation;
$kapacita= (IsSet($kapacita) && is_numeric($kapacita)) ? (int)$kapacita: 0;
+ $oris_entry_start_val = (!empty($oris_entry_start)) ? "'".correct_sql_string($oris_entry_start)."'" : "NULL";
- $result=query_db("INSERT INTO ".TBL_RACE." (ext_id, datum, datum2, nazev, misto, typ0, typ, zebricek, ranking, odkaz, prihlasky, prihlasky1, prihlasky2, prihlasky3, prihlasky4, prihlasky5, etap, poznamka, vicedenni, oddil, modify_flag, transport, ubytovani, kapacita, kategorie, vedouci, poslano) VALUES ( '$ext_id', '$datum', '$datum2', '$nazev', '$misto', '$typ0', '$typ', '$zebricek2', '$ranking', '$odkaz', '$prihlasky', '$prihlasky1', '$prihlasky2', '$prihlasky3', '$prihlasky4', '$prihlasky5', '$etap', '$poznamka', '$vicedenni', '$oddil', '$modify_flag', '$transport', '$accommodation', $kapacita,'$kategorie', 0, 0)")
+ $result=query_db("INSERT INTO ".TBL_RACE." (ext_id, datum, datum2, nazev, misto, typ0, typ, zebricek, ranking, odkaz, prihlasky, prihlasky1, prihlasky2, prihlasky3, prihlasky4, prihlasky5, etap, poznamka, vicedenni, oddil, modify_flag, transport, ubytovani, kapacita, kategorie, oris_entry_start, vedouci, poslano) VALUES ( '$ext_id', '$datum', '$datum2', '$nazev', '$misto', '$typ0', '$typ', '$zebricek2', '$ranking', '$odkaz', '$prihlasky', '$prihlasky1', '$prihlasky2', '$prihlasky3', '$prihlasky4', '$prihlasky5', '$etap', '$poznamka', '$vicedenni', '$oddil', '$modify_flag', '$transport', '$accommodation', $kapacita,'$kategorie', $oris_entry_start_val, 0, 0)")
or die("Chyba při provádění dotazu do databáze.");
if ($result == FALSE)
die ("Nepodařilo se vložit údaje o závodě.");
diff --git a/race_reg_chip_exc.php b/race_reg_chip_exc.php
index 5f4fc3b..eb8ad0d 100644
--- a/race_reg_chip_exc.php
+++ b/race_reg_chip_exc.php
@@ -4,6 +4,9 @@
require_once ("./connect.inc.php");
require_once ("./sess.inc.php");
+require_once ("./lib/oris_sync.inc.php");
+require_once ("./common.inc.php");
+require_once ("./common_race.inc.php");
if (!IsLoggedRegistrator())
{
@@ -15,7 +18,12 @@
db_Connect();
-$query = 'SELECT z.id_user, u.si_chip FROM '.TBL_ZAVXUS.' as z, '.TBL_USER.' as u WHERE z.id_user = u.id AND z.id_zavod='.$id_zav.' AND u.hidden = 0';
+@$vysledek_z=query_db("SELECT ext_id FROM ".TBL_RACE." WHERE id=$id_zav");
+$zaznam_z = mysqli_fetch_array($vysledek_z);
+$has_ext_id = !empty($zaznam_z['ext_id']);
+$sync_queue = [];
+
+$query = 'SELECT z.id as z_id, z.id_user, z.sync_status, z.si_chip as z_chip, u.si_chip FROM '.TBL_ZAVXUS.' as z, '.TBL_USER.' as u WHERE z.id_user = u.id AND z.id_zavod='.$id_zav.' AND u.hidden = 0';
@$vysledek=query_db($query);
@@ -27,12 +35,39 @@
if (IsSet($chip[$user]))
{
$si_chip = (int)$chip[$user];
- if ($si_chip != $zaznam['si_chip'])
+ $old_chip = (int)($zaznam['z_chip'] ? $zaznam['z_chip'] : $zaznam['si_chip']);
+ if ($si_chip != $old_chip)
{
- $result=query_db('UPDATE '.TBL_ZAVXUS.' SET `si_chip`= '.$si_chip.' WHERE `id_zavod` = '.$id_zav.' AND `id_user` = '.$user)
+ $sync_status_update = "";
+ if ($has_ext_id && $zaznam['sync_status'] !== 'PENDING_CREATE') {
+ $sync_status_update = ", `sync_status`='PENDING_UPDATE'";
+ }
+ $result=query_db('UPDATE '.TBL_ZAVXUS.' SET `si_chip`= '.$si_chip.$sync_status_update.' WHERE `id_zavod` = '.$id_zav.' AND `id_user` = '.$user)
or die("Chyba při provádění dotazu do databáze.");
if ($result == FALSE)
die ("Nepodařilo se změnit přihlášku člena.");
+
+ if ($has_ext_id) {
+ $action = ($zaznam['sync_status'] === 'PENDING_CREATE') ? 'create' : 'update';
+ $sync_queue[] = ['id' => $zaznam['z_id'], 'action' => $action];
+ }
+ }
+ }
+ }
+}
+
+$sync_errors = [];
+if ($has_ext_id && count($sync_queue) > 0) {
+ global $g_oris_club_key;
+ if (!empty($g_oris_club_key)) {
+ $service = new OrisIntegrationService($g_oris_club_key);
+ foreach ($sync_queue as $sq) {
+ $rowQuery = query_db("SELECT * FROM `" . TBL_ZAVXUS . "` WHERE `id` = " . (int)$sq['id']);
+ if ($rowQuery && $syncRow = mysqli_fetch_assoc($rowQuery)) {
+ $syncRes = processEntry($syncRow, $sq['action'], $service);
+ if ($syncRes !== true && $syncRes !== 'queued') {
+ $sync_errors[] = "Záznam " . $sq['id'] . ": " . getOrisSyncError($sq['id']);
+ }
}
}
}
@@ -40,6 +75,11 @@
?>
+
+
+ Chyby při synchronizaci s ORIS:
+ ', array_map('htmlspecialchars', $sync_errors)); ?>
+
+
Zpět na přehled
+
+
diff --git a/rg_oris_sync_log.php b/rg_oris_sync_log.php
new file mode 100644
index 0000000..56e9189
--- /dev/null
+++ b/rg_oris_sync_log.php
@@ -0,0 +1,33 @@
+';
+if (file_exists($logFile)) {
+ $content = file_get_contents($logFile);
+ if ($content !== false) {
+ echo nl2br(htmlspecialchars($content));
+ } else {
+ echo "Error reading log file.";
+ }
+} else {
+ echo "Log file does not exist yet.";
+}
+echo '';
+
+echo '';
+
+HTML_Footer();
+?>
\ No newline at end of file
diff --git a/us_race_regoff_exc.php b/us_race_regoff_exc.php
index 4b72cd9..a0554f4 100644
--- a/us_race_regoff_exc.php
+++ b/us_race_regoff_exc.php
@@ -4,6 +4,7 @@
require_once ("./connect.inc.php");
require_once ("./sess.inc.php");
+require_once ("./lib/oris_sync.inc.php");
if (!IsLogged())
{
@@ -25,18 +26,53 @@
if (!$entry_lock)
{
- @$vysledek=query_db("DELETE FROM ".TBL_ZAVXUS." WHERE id_zavod = '$id_zav' AND id_user = '$id_us'");
- if ($vysledek !== false && mysqli_affected_rows($db_conn) > 0) {
- query_db("UPDATE ".TBL_RACE." SET prihlasenych = GREATEST(0, prihlasenych - 1) WHERE id = '$id_zav'");
+ $vysledek_z=query_db("SELECT ext_id FROM ".TBL_RACE." WHERE id='$id_zav'");
+ $zaznam_z = mysqli_fetch_array($vysledek_z);
+ $has_ext_id = !empty($zaznam_z['ext_id']);
+
+ $vysledek_zx=query_db("SELECT id, sync_status FROM ".TBL_ZAVXUS." WHERE id_zavod='$id_zav' AND id_user='$id_us'");
+ $zaznam_zx = mysqli_fetch_array($vysledek_zx);
+
+ $sync_error_msg = null;
+ if ($zaznam_zx) {
+ $zx_id = $zaznam_zx['id'];
+ $sync_status = $zaznam_zx['sync_status'];
+
+ if ($has_ext_id && $sync_status !== 'PENDING_CREATE') {
+ $vysledek = query_db("UPDATE ".TBL_ZAVXUS." SET sync_status='PENDING_DELETE' WHERE id = '$zx_id'");
+ if ($vysledek !== false) {
+ global $g_oris_club_key;
+ if (!empty($g_oris_club_key)) {
+ $service = new OrisIntegrationService($g_oris_club_key);
+ $rowQuery = query_db("SELECT * FROM `" . TBL_ZAVXUS . "` WHERE `id` = '$zx_id'");
+ if ($rowQuery && $syncRow = mysqli_fetch_assoc($rowQuery)) {
+ $syncRes = processEntry($syncRow, 'delete', $service);
+ if ($syncRes === true || $syncRes === 'queued') {
+ query_db("UPDATE ".TBL_RACE." SET prihlasenych = GREATEST(0, prihlasenych - 1) WHERE id = '$id_zav'");
+ } else {
+ $sync_error_msg = getOrisSyncError($zx_id);
+ }
+ }
+ }
+ }
+ } else {
+ @$vysledek=query_db("DELETE FROM ".TBL_ZAVXUS." WHERE id = '$zx_id'");
+ if ($vysledek !== false && mysqli_affected_rows($db_conn) > 0) {
+ query_db("UPDATE ".TBL_RACE." SET prihlasenych = GREATEST(0, prihlasenych - 1) WHERE id = '$id_zav'");
+ }
+ }
}
}
?>
\ No newline at end of file
+
diff --git a/us_race_regon_exc.php b/us_race_regon_exc.php
index 795bf99..0fa2fdc 100644
--- a/us_race_regon_exc.php
+++ b/us_race_regon_exc.php
@@ -6,6 +6,7 @@
require_once ("./sess.inc.php");
require_once ("./common.inc.php");
require_once ("./common_race.inc.php");
+require_once ("./lib/oris_sync.inc.php");
if (!IsLogged())
{
@@ -34,7 +35,7 @@
$pozn=correct_sql_string($pozn);
$pozn2=correct_sql_string($pozn2);
- @$vysledek_z=query_db("SELECT datum, vicedenni, prihlasky, prihlasky1, prihlasky2, prihlasky3, prihlasky4, prihlasky5, transport FROM ".TBL_RACE." WHERE id=$id_zav");
+ @$vysledek_z=query_db("SELECT datum, vicedenni, prihlasky, prihlasky1, prihlasky2, prihlasky3, prihlasky4, prihlasky5, transport, ext_id FROM ".TBL_RACE." WHERE id=$id_zav");
$zaznam_z = mysqli_fetch_array($vysledek_z);
$termin = raceterms::GetCurr4RegTerm($zaznam_z);
@@ -59,32 +60,99 @@
$ubytovani = !isset($ubytovani)? 'null': 1;
$novy = !isset($novy)? 0: (int)$novy;
+ $has_ext_id = !empty($zaznam_z['ext_id']);
+ $inserted_or_updated_id = 0;
+ $sync_action = '';
+ $is_new_insert = false;
+ $previous_state = null;
+
if ($novy)
{
$vysledek=query_db("SELECT * FROM ".TBL_ZAVXUS." WHERE id_zavod='$id_zav' and id_user='$id_us'");
if ($vysledek != FALSE && ($zaznam = mysqli_fetch_array($vysledek)) != FALSE )
{ // latest new == update
- query_db("UPDATE ".TBL_ZAVXUS." SET kat='$kat', pozn='$pozn', pozn_in='$pozn2', termin='$termin', transport=$transport, sedadel=$sedadel, ubytovani=$ubytovani WHERE id='".$zaznam['id']."'");
+ $previous_state = $zaznam;
+ $sync_status_update = ($has_ext_id && $zaznam['sync_status'] !== 'PENDING_CREATE') ? ", sync_status='PENDING_UPDATE'" : "";
+ $sync_action = ($has_ext_id && $zaznam['sync_status'] === 'PENDING_CREATE') ? 'create' : 'update';
+ query_db("UPDATE ".TBL_ZAVXUS." SET kat='$kat', pozn='$pozn', pozn_in='$pozn2', termin='$termin', transport=$transport, sedadel=$sedadel, ubytovani=$ubytovani".$sync_status_update." WHERE id='".$zaznam['id']."'");
+ $inserted_or_updated_id = $zaznam['id'];
}
else
{ // really new
- $vysledek = query_db("INSERT INTO ".TBL_ZAVXUS." (id_user, id_zavod, kat, pozn, pozn_in, termin, transport, sedadel, ubytovani) VALUES ('$id_us','$id_zav','$kat','$pozn','$pozn2','$termin',$transport, $sedadel, $ubytovani)");
+ $is_new_insert = true;
+ $sync_status = $has_ext_id ? 'PENDING_CREATE' : 'LOCAL_ONLY';
+ $sync_action = $has_ext_id ? 'create' : '';
+ $vysledek = query_db("INSERT INTO ".TBL_ZAVXUS." (id_user, id_zavod, kat, pozn, pozn_in, termin, transport, sedadel, ubytovani, sync_status) VALUES ('$id_us','$id_zav','$kat','$pozn','$pozn2','$termin',$transport, $sedadel, $ubytovani, '$sync_status')");
if ($vysledek !== false && mysqli_affected_rows($db_conn) > 0) {
+ $inserted_or_updated_id = mysqli_insert_id($db_conn);
query_db("UPDATE ".TBL_RACE." SET prihlasenych = prihlasenych + 1 WHERE id = '$id_zav'");
}
}
}
else
{ // update
- query_db("UPDATE ".TBL_ZAVXUS." SET kat='$kat', pozn='$pozn', pozn_in='$pozn2', transport=$transport, sedadel=$sedadel, ubytovani=$ubytovani WHERE id='".$id_z."'");
+ $vysledek=query_db("SELECT * FROM ".TBL_ZAVXUS." WHERE id='".$id_z."'");
+ if ($vysledek != FALSE && ($zaznam = mysqli_fetch_array($vysledek)) != FALSE )
+ {
+ $previous_state = $zaznam;
+ $sync_status_update = ($has_ext_id && $zaznam['sync_status'] !== 'PENDING_CREATE') ? ", sync_status='PENDING_UPDATE'" : "";
+ $sync_action = ($has_ext_id && $zaznam['sync_status'] === 'PENDING_CREATE') ? 'create' : 'update';
+ query_db("UPDATE ".TBL_ZAVXUS." SET kat='$kat', pozn='$pozn', pozn_in='$pozn2', transport=$transport, sedadel=$sedadel, ubytovani=$ubytovani".$sync_status_update." WHERE id='".$id_z."'");
+ $inserted_or_updated_id = $id_z;
+ }
+ }
+
+ $sync_error_msg = null;
+ if ($has_ext_id && $inserted_or_updated_id > 0 && $sync_action !== '') {
+ global $g_oris_club_key;
+ if (!empty($g_oris_club_key)) {
+ $service = new OrisIntegrationService($g_oris_club_key);
+ $rowQuery = query_db("SELECT * FROM `" . TBL_ZAVXUS . "` WHERE `id` = " . (int)$inserted_or_updated_id);
+ if ($rowQuery && $syncRow = mysqli_fetch_assoc($rowQuery)) {
+ $syncRes = processEntry($syncRow, $sync_action, $service);
+ if ($syncRes !== true && $syncRes !== 'queued') {
+ $sync_error_msg = getOrisSyncError($inserted_or_updated_id);
+ // Rollback changes
+ if ($is_new_insert) {
+ query_db("DELETE FROM ".TBL_ZAVXUS." WHERE id = '$inserted_or_updated_id'");
+ query_db("UPDATE ".TBL_RACE." SET prihlasenych = prihlasenych - 1 WHERE id = '$id_zav'");
+ } else if ($previous_state) {
+ $prev_kat = correct_sql_string($previous_state['kat']);
+ $prev_pozn = correct_sql_string($previous_state['pozn']);
+ $prev_pozn_in = correct_sql_string($previous_state['pozn_in']);
+ $prev_termin = (int)$previous_state['termin'];
+ $prev_transport = (int)$previous_state['transport'];
+ $prev_sedadel = (!isset($previous_state['sedadel']) || $previous_state['sedadel'] === null) ? 'null' : (int)$previous_state['sedadel'];
+ $prev_ubytovani = (!isset($previous_state['ubytovani']) || $previous_state['ubytovani'] === null) ? 'null' : (int)$previous_state['ubytovani'];
+ $prev_sync_status = correct_sql_string($previous_state['sync_status']);
+
+ query_db("UPDATE ".TBL_ZAVXUS." SET kat='$prev_kat', pozn='$prev_pozn', pozn_in='$prev_pozn_in', termin='$prev_termin', transport=$prev_transport, sedadel=$prev_sedadel, ubytovani=$prev_ubytovani, sync_status='$prev_sync_status' WHERE id='$inserted_or_updated_id'");
+ }
+ }
+ }
+ }
}
}
}
}
?>
+
+
+
+
\ No newline at end of file
+