0202-финиш перед десктопом

пересчет поправил
редактирование с перепроведением
галка автопроведения работает
рекомендации починил
This commit is contained in:
2026-02-02 13:53:38 +03:00
parent 10882f55c8
commit 88620f3fb6
37 changed files with 1905 additions and 11162 deletions

View File

@@ -15,6 +15,7 @@ import (
"rmser/internal/domain/recipes"
"rmser/internal/domain/suppliers"
"rmser/internal/infrastructure/rms"
"rmser/pkg/crypto"
"rmser/pkg/logger"
)
@@ -24,17 +25,19 @@ const (
)
type Service struct {
rmsFactory *rms.Factory
accountRepo account.Repository
catalogRepo catalog.Repository
recipeRepo recipes.Repository
invoiceRepo invoices.Repository
opRepo operations.Repository
supplierRepo suppliers.Repository
rmsFactory *rms.Factory
cryptoManager *crypto.CryptoManager
accountRepo account.Repository
catalogRepo catalog.Repository
recipeRepo recipes.Repository
invoiceRepo invoices.Repository
opRepo operations.Repository
supplierRepo suppliers.Repository
}
func NewService(
rmsFactory *rms.Factory,
cryptoManager *crypto.CryptoManager,
accountRepo account.Repository,
catalogRepo catalog.Repository,
recipeRepo recipes.Repository,
@@ -43,16 +46,73 @@ func NewService(
supplierRepo suppliers.Repository,
) *Service {
return &Service{
rmsFactory: rmsFactory,
accountRepo: accountRepo,
catalogRepo: catalogRepo,
recipeRepo: recipeRepo,
invoiceRepo: invoiceRepo,
opRepo: opRepo,
supplierRepo: supplierRepo,
rmsFactory: rmsFactory,
cryptoManager: cryptoManager,
accountRepo: accountRepo,
catalogRepo: catalogRepo,
recipeRepo: recipeRepo,
invoiceRepo: invoiceRepo,
opRepo: opRepo,
supplierRepo: supplierRepo,
}
}
// SyncAllDataForServer запускает полную синхронизацию для конкретного сервера
func (s *Service) SyncAllDataForServer(serverID uuid.UUID, force bool) error {
logger.Log.Info("Запуск синхронизации по серверу", zap.String("server_id", serverID.String()), zap.Bool("force", force))
// 1. Получаем информацию о сервере
server, err := s.accountRepo.GetServerByID(serverID)
if err != nil || server == nil {
return fmt.Errorf("server not found: %s", serverID)
}
// 2. Получаем креды владельца сервера для подключения
baseURL, login, encryptedPass, err := s.getOwnerCredentials(serverID)
if err != nil {
return fmt.Errorf("failed to get owner credentials: %w", err)
}
// 3. Расшифровываем пароль
plainPass, err := s.cryptoManager.Decrypt(encryptedPass)
if err != nil {
return fmt.Errorf("failed to decrypt password: %w", err)
}
// 4. Создаем клиент RMS
client := s.rmsFactory.CreateClientFromRawCredentials(baseURL, login, plainPass)
return s.syncAllWithClient(client, serverID, force)
}
// getOwnerCredentials возвращает учетные данные владельца сервера
func (s *Service) getOwnerCredentials(serverID uuid.UUID) (url, login, encryptedPass string, err error) {
// Находим владельца сервера
users, err := s.accountRepo.GetServerUsers(serverID)
if err != nil {
return "", "", "", err
}
var ownerLink *account.ServerUser
for i := range users {
if users[i].Role == account.RoleOwner {
ownerLink = &users[i]
break
}
}
if ownerLink == nil {
return "", "", "", fmt.Errorf("owner not found for server %s", serverID)
}
// Если у владельца есть личные креды - используем их
if ownerLink.Login != "" && ownerLink.EncryptedPassword != "" {
return ownerLink.Server.BaseURL, ownerLink.Login, ownerLink.EncryptedPassword, nil
}
return "", "", "", fmt.Errorf("owner has no credentials for server %s", serverID)
}
// SyncAllData запускает полную синхронизацию для конкретного пользователя
func (s *Service) SyncAllData(userID uuid.UUID, force bool) error {
logger.Log.Info("Запуск синхронизации", zap.String("user_id", userID.String()), zap.Bool("force", force))
@@ -68,6 +128,12 @@ func (s *Service) SyncAllData(userID uuid.UUID, force bool) error {
}
serverID := server.ID
return s.syncAllWithClient(client, serverID, force)
}
// syncAllWithClient выполняет синхронизацию с готовым клиентом
func (s *Service) syncAllWithClient(client rms.ClientI, serverID uuid.UUID, force bool) error {
// 2. Справочники
if err := s.syncStores(client, serverID); err != nil {
logger.Log.Error("Sync Stores failed", zap.Error(err))
@@ -96,13 +162,12 @@ func (s *Service) SyncAllData(userID uuid.UUID, force bool) error {
logger.Log.Error("Sync Invoices failed", zap.Error(err))
}
// 7. Складские операции (тяжелый запрос)
// Для MVP можно отключить, если долго грузится
// if err := s.SyncStoreOperations(client, serverID); err != nil {
// logger.Log.Error("Sync Operations failed", zap.Error(err))
// }
// 7. Складские операции
if err := s.SyncStoreOperations(client, serverID); err != nil {
logger.Log.Error("Sync Operations failed", zap.Error(err))
}
logger.Log.Info("Синхронизация завершена", zap.String("user_id", userID.String()))
logger.Log.Info("Синхронизация завершена", zap.String("server_id", serverID.String()))
return nil
}
@@ -236,7 +301,7 @@ func (s *Service) syncInvoices(c rms.ClientI, serverID uuid.UUID, force bool) er
// SyncStoreOperations публичный, если нужно вызывать отдельно
func (s *Service) SyncStoreOperations(c rms.ClientI, serverID uuid.UUID) error {
dateTo := time.Now()
dateFrom := dateTo.AddDate(0, 0, -30)
dateFrom := dateTo.AddDate(0, 0, -90) // 90 дней — соответствует периоду анализа рекомендаций
if err := s.syncReport(c, serverID, PresetPurchases, operations.OpTypePurchase, dateFrom, dateTo); err != nil {
return fmt.Errorf("purchases sync error: %w", err)