From 95592aa510bb87973cff677fbcf8efadcfc45112 Mon Sep 17 00:00:00 2001 From: SajjadMahmoody <117562560+SajjadMahmoody@users.noreply.github.com> Date: Sun, 19 Apr 2026 11:29:57 +0330 Subject: [PATCH] fix : sync issu --- app/Filament/Pages/SyncPage.php | 2 +- app/Http/Controllers/SyncController.php | 5 ++- app/Models/SyncLog.php | 20 ++++++++--- app/Services/SyncService.php | 45 ++++++++++++++++++------- database/seeders/DatabaseSeeder.php | 1 + database/seeders/OsurgInitialSeeder.php | 12 ++++++- 6 files changed, 63 insertions(+), 22 deletions(-) diff --git a/app/Filament/Pages/SyncPage.php b/app/Filament/Pages/SyncPage.php index c3ceb03..c45a29e 100644 --- a/app/Filament/Pages/SyncPage.php +++ b/app/Filament/Pages/SyncPage.php @@ -59,7 +59,7 @@ public function getTitle(): string public function getPendingCount(): int { - return SyncLog::changesSince((int) OsurgInitial::val('our_sync_cursor', 0))->count(); + return SyncLog::changesSince(OsurgInitial::val('our_sync_cursor') ?: null)->count(); } public function getLastSyncTime(): string diff --git a/app/Http/Controllers/SyncController.php b/app/Http/Controllers/SyncController.php index 002eac9..98434d5 100644 --- a/app/Http/Controllers/SyncController.php +++ b/app/Http/Controllers/SyncController.php @@ -25,11 +25,10 @@ public function export(Request $request): JsonResponse return response()->json(['error' => 'Unauthorized'], 401); } - $since = (int) $request->query('since', 0); + $since = $request->query('since') ?: null; return response()->json([ - 'last_sync_id' => SyncLog::lastSyncId(), - 'changes' => SyncLog::changesSince($since), + 'changes' => SyncLog::changesSince($since), ]); } diff --git a/app/Models/SyncLog.php b/app/Models/SyncLog.php index 36b9369..bbad70e 100644 --- a/app/Models/SyncLog.php +++ b/app/Models/SyncLog.php @@ -32,12 +32,22 @@ public static function lastSyncId(): int return (int) static::where('action', 'synced')->max('id') ?: 0; } - public static function changesSince(int $since): \Illuminate\Database\Eloquent\Collection + public static function changesSince(?string $since): \Illuminate\Database\Eloquent\Collection { - return static::where('id', '>', $since) - ->whereIn('action', ['created', 'updated', 'deleted']) - ->orderBy('id') - ->get(); + $query = static::whereIn('action', ['created', 'updated', 'deleted']) + ->orderBy('datetime') + ->orderBy('id'); + + if ($since !== null && $since !== '') { + $query->where('datetime', '>', $since); + } + + return $query->get(); + } + + protected function serializeDate(\DateTimeInterface $date): string + { + return $date->format('Y-m-d H:i:s'); } public static function markSynced(string $ip): static diff --git a/app/Services/SyncService.php b/app/Services/SyncService.php index afc0056..1b8a6e8 100644 --- a/app/Services/SyncService.php +++ b/app/Services/SyncService.php @@ -51,8 +51,8 @@ public function sync(): array $report = []; $baseUrl = "http://{$this->peerIp}:{$this->peerPort}"; - $peerCursor = (int) \App\Models\OsurgInitial::val('sync_peer_cursor', 0); - $ourLastSync = (int) \App\Models\OsurgInitial::val('our_sync_cursor', 0); + $peerCursor = \App\Models\OsurgInitial::val('sync_peer_cursor') ?: null; + $ourLastSync = \App\Models\OsurgInitial::val('our_sync_cursor') ?: null; try { $pullResponse = Http::timeout(30) @@ -65,14 +65,27 @@ public function sync(): array if (! empty($peerChanges)) { app()->instance('sync.applying', true); - DB::transaction(function () use ($peerChanges, &$report) { + $pullReport = []; + DB::transaction(function () use ($peerChanges, &$pullReport) { foreach ($peerChanges as $change) { - $this->applyChange($change, 'دریافت', $report); + $this->applyChange($change, 'دریافت', $pullReport); } }); + foreach ($pullReport as $line) { + $report[] = $line; + } - $maxPeerChangeId = max(array_column($peerChanges, 'id')); - $this->savePeerCursor(max($peerCursor, $maxPeerChangeId)); + $pullHasErrors = ! empty(array_filter($pullReport, fn ($l) => str_contains((string) $l, '✗'))); + + if (! $pullHasErrors) { + $datetimes = array_filter(array_column($peerChanges, 'datetime')); + $maxPeerDatetime = \Carbon\Carbon::parse(max($datetimes))->format('Y-m-d H:i:s'); + if ($peerCursor === null || $maxPeerDatetime > $peerCursor) { + $this->savePeerCursor($maxPeerDatetime); + } + } else { + $report[] = 'هشدار: peer_cursor پیش نرفت — برخی تغییرات دریافتی اعمال نشد و دفعه بعد retry می‌شه.'; + } if ($this->isFtpConfigured()) { $this->transferFilesViaFtp($peerChanges, 's2c', $report); @@ -98,14 +111,22 @@ public function sync(): array ->post("{$baseUrl}/api/sync/apply", ['changes' => $ourChanges]); if ($pushResponse->successful()) { - foreach ($pushResponse->json('report', []) as $line) { + $pushReport = $pushResponse->json('report', []); + foreach ($pushReport as $line) { $report[] = 'ارسال: ' . $line; } $report[] = count($ourChanges) . ' تغییر به سیستم مقابل ارسال شد.'; - if (! empty($ourChanges)) { - $maxOurId = max(array_column($ourChanges, 'id')); - $this->saveOurCursor($maxOurId); + $hasErrors = ! empty(array_filter($pushReport, fn ($l) => str_contains((string) $l, '✗'))); + + if (! empty($ourChanges) && ! $hasErrors) { + $ourDatetimes = array_filter(array_column($ourChanges, 'datetime')); + $maxOurDatetime = \Carbon\Carbon::parse(max($ourDatetimes))->format('Y-m-d H:i:s'); + if ($ourLastSync === null || $maxOurDatetime > $ourLastSync) { + $this->saveOurCursor($maxOurDatetime); + } + } elseif ($hasErrors) { + $report[] = 'هشدار: cursor پیش نرفت — برخی تغییرات روی سیستم مقابل اعمال نشد و دفعه بعد retry می‌شه.'; } if ($this->isFtpConfigured()) { @@ -431,7 +452,7 @@ private function applyChange(array $change, string $prefix, array &$report): voi } } - private function saveOurCursor(int $cursor): void + private function saveOurCursor(string $cursor): void { \App\Models\OsurgInitial::updateOrCreate( ['init_parameter' => 'our_sync_cursor'], @@ -440,7 +461,7 @@ private function saveOurCursor(int $cursor): void cache()->forget('osurg_initial.our_sync_cursor'); } - private function savePeerCursor(int $cursor): void + private function savePeerCursor(string $cursor): void { \App\Models\OsurgInitial::updateOrCreate( ['init_parameter' => 'sync_peer_cursor'], diff --git a/database/seeders/DatabaseSeeder.php b/database/seeders/DatabaseSeeder.php index c723efa..dabc14c 100644 --- a/database/seeders/DatabaseSeeder.php +++ b/database/seeders/DatabaseSeeder.php @@ -19,6 +19,7 @@ public function run(): void TreatmentSeeder::class, SurgeryCenterSeeder::class, MedicationSeeder::class, + LabTestSeeder::class, OsurgInitialSeeder::class, RolePermissionSeeder::class, ]); diff --git a/database/seeders/OsurgInitialSeeder.php b/database/seeders/OsurgInitialSeeder.php index aeb83db..0e42616 100644 --- a/database/seeders/OsurgInitialSeeder.php +++ b/database/seeders/OsurgInitialSeeder.php @@ -82,7 +82,17 @@ public function run(): void ], [ 'init_parameter' => 'ftp_remote_path', - 'init_value' => 'C:/wamp64/www/matab-panel/storage/app/public', + 'init_value' => '/', + 'attachment' => null, + ], + [ + 'init_parameter' => 'sync_peer_cursor', + 'init_value' => null, + 'attachment' => null, + ], + [ + 'init_parameter' => 'our_sync_cursor', + 'init_value' => null, 'attachment' => null, ], ];