From 5d5af07fc500506da59c2f0ba46e5f4cddbd574c Mon Sep 17 00:00:00 2001 From: Michael Chus Date: Tue, 2 Jun 2026 14:06:18 +0300 Subject: [PATCH] =?UTF-8?q?fix:=20NeedSync=20=D0=BF=D1=80=D0=BE=D0=B2?= =?UTF-8?q?=D0=B5=D1=80=D1=8F=D0=B5=D1=82=20=D0=B2=D0=B5=D1=80=D1=81=D0=B8?= =?UTF-8?q?=D0=B8=20=D1=81=D0=B5=D1=80=D0=B2=D0=B5=D1=80=D0=B0=20=D0=BA?= =?UTF-8?q?=D0=BE=D0=B3=D0=B4=D0=B0=20=D0=BE=D0=BD=D0=BB=D0=B0=D0=B9=D0=BD?= =?UTF-8?q?,=20=D0=B8=D0=B3=D0=BD=D0=BE=D1=80=D0=B8=D1=80=D1=83=D1=8F=201-?= =?UTF-8?q?=D1=87=D0=B0=D1=81=D0=BE=D0=B2=D0=BE=D0=B9=20=D0=BF=D0=BE=D1=80?= =?UTF-8?q?=D0=BE=D0=B3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Раньше NeedSync возвращал true сразу если last_sync > 1 часа назад — до сравнения версий дело не доходило. Это приводило к бесконечным повторным попыткам синка когда все прайслисты уже скачаны, но last_pricelist_status застрял в "failed" из-за предыдущего сбоя. Теперь когда онлайн — всегда сравниваем реальные версии с сервером. Если все источники совпадают — возвращаем false независимо от времени последнего синка. Фолбэк на 1-часовой порог только в офлайн-режиме. Co-Authored-By: Claude Sonnet 4.6 --- internal/services/sync/service.go | 75 +++++++++++++++---------------- 1 file changed, 35 insertions(+), 40 deletions(-) diff --git a/internal/services/sync/service.go b/internal/services/sync/service.go index 9c9d3cf..194db80 100644 --- a/internal/services/sync/service.go +++ b/internal/services/sync/service.go @@ -274,54 +274,49 @@ func (s *Service) GetStatus() (*SyncStatus, error) { func (s *Service) NeedSync() (bool, error) { lastSync := s.localDB.GetLastSyncTime() - // If never synced, need sync + // If never synced, always need sync. if lastSync == nil { return true, nil } - // If last sync was more than 1 hour ago, suggest sync + // When online, compare actual server versions regardless of elapsed time. + // This prevents a stale "failed" status from the past from triggering + // endless sync retries when all pricelists are already up to date. + connStatus := s.getConnectionStatus() + if connStatus.IsConnected { + mariaDB, err := s.getDB() + if err == nil { + pricelistRepo := repository.NewPricelistRepository(mariaDB) + sources := []models.PricelistSource{ + models.PricelistSourceEstimate, + models.PricelistSourceWarehouse, + models.PricelistSourceCompetitor, + } + allMatch := true + for _, source := range sources { + latestServer, err := pricelistRepo.GetLatestActiveBySource(string(source)) + if err != nil { + continue + } + latestLocal, err := s.localDB.GetLatestLocalPricelistBySource(string(source)) + if err != nil { + return true, nil + } + if latestServer.ID != latestLocal.ServerID { + return true, nil + } + } + if allMatch { + return false, nil + } + } + } + + // Offline fallback: suggest sync if last successful sync was more than 1 hour ago. if time.Since(*lastSync) > time.Hour { return true, nil } - // Check if there are new pricelists on server (only if already connected) - connStatus := s.getConnectionStatus() - if !connStatus.IsConnected { - // If offline, can't check server, no need to sync - return false, nil - } - - mariaDB, err := s.getDB() - if err != nil { - // If offline, can't check server, no need to sync - return false, nil - } - - pricelistRepo := repository.NewPricelistRepository(mariaDB) - sources := []models.PricelistSource{ - models.PricelistSourceEstimate, - models.PricelistSourceWarehouse, - models.PricelistSourceCompetitor, - } - for _, source := range sources { - latestServer, err := pricelistRepo.GetLatestActiveBySource(string(source)) - if err != nil { - // No active pricelist for this source yet. - continue - } - - latestLocal, err := s.localDB.GetLatestLocalPricelistBySource(string(source)) - if err != nil { - // No local pricelist for an existing source on server. - return true, nil - } - - // If server has newer pricelist for this source, need sync. - if latestServer.ID != latestLocal.ServerID { - return true, nil - } - } - return false, nil }