mirror of
https://github.com/serty2005/rmser.git
synced 2026-02-04 19:02:33 -06:00
добавил пользователей для сервера и роли
добавил инвайт-ссылки с ролью оператор для сервера добавил супер-админку для смены владельцев добавил уведомления о смене ролей на серверах добавил модалку для фото прям в черновике добавил UI для редактирования прав
This commit is contained in:
@@ -2,7 +2,10 @@ package ocr
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/shopspring/decimal"
|
||||
@@ -18,16 +21,18 @@ type Service struct {
|
||||
ocrRepo ocr.Repository
|
||||
catalogRepo catalog.Repository
|
||||
draftRepo drafts.Repository
|
||||
accountRepo account.Repository // <-- NEW
|
||||
accountRepo account.Repository
|
||||
pyClient *ocr_client.Client
|
||||
storagePath string
|
||||
}
|
||||
|
||||
func NewService(
|
||||
ocrRepo ocr.Repository,
|
||||
catalogRepo catalog.Repository,
|
||||
draftRepo drafts.Repository,
|
||||
accountRepo account.Repository, // <-- NEW
|
||||
accountRepo account.Repository,
|
||||
pyClient *ocr_client.Client,
|
||||
storagePath string,
|
||||
) *Service {
|
||||
return &Service{
|
||||
ocrRepo: ocrRepo,
|
||||
@@ -35,10 +40,23 @@ func NewService(
|
||||
draftRepo: draftRepo,
|
||||
accountRepo: accountRepo,
|
||||
pyClient: pyClient,
|
||||
storagePath: storagePath,
|
||||
}
|
||||
}
|
||||
|
||||
// ProcessReceiptImage
|
||||
// checkWriteAccess - вспомогательный метод проверки прав
|
||||
func (s *Service) checkWriteAccess(userID, serverID uuid.UUID) error {
|
||||
role, err := s.accountRepo.GetUserRole(userID, serverID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if role == account.RoleOperator {
|
||||
return errors.New("access denied: operators cannot modify data")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ProcessReceiptImage - Доступно всем (включая Операторов)
|
||||
func (s *Service) ProcessReceiptImage(ctx context.Context, userID uuid.UUID, imgData []byte) (*drafts.DraftInvoice, error) {
|
||||
// 1. Получаем активный сервер для UserID
|
||||
server, err := s.accountRepo.GetActiveServer(userID)
|
||||
@@ -54,6 +72,18 @@ func (s *Service) ProcessReceiptImage(ctx context.Context, userID uuid.UUID, img
|
||||
Status: drafts.StatusProcessing,
|
||||
StoreID: server.DefaultStoreID,
|
||||
}
|
||||
|
||||
draft.ID = uuid.New()
|
||||
|
||||
fileName := fmt.Sprintf("receipt_%s.jpg", draft.ID.String())
|
||||
filePath := filepath.Join(s.storagePath, fileName)
|
||||
|
||||
if err := os.WriteFile(filePath, imgData, 0644); err != nil {
|
||||
return nil, fmt.Errorf("failed to save image: %w", err)
|
||||
}
|
||||
|
||||
draft.SenderPhotoURL = "/uploads/" + fileName
|
||||
|
||||
if err := s.draftRepo.Create(draft); err != nil {
|
||||
return nil, fmt.Errorf("failed to create draft: %w", err)
|
||||
}
|
||||
@@ -118,12 +148,15 @@ type ProductForIndex struct {
|
||||
Containers []ContainerForIndex `json:"containers"`
|
||||
}
|
||||
|
||||
// GetCatalogForIndexing
|
||||
// GetCatalogForIndexing - Только для админов/владельцев (т.к. используется для ручного матчинга)
|
||||
func (s *Service) GetCatalogForIndexing(userID uuid.UUID) ([]ProductForIndex, error) {
|
||||
server, err := s.accountRepo.GetActiveServer(userID)
|
||||
if err != nil || server == nil {
|
||||
return nil, fmt.Errorf("no server")
|
||||
}
|
||||
if err := s.checkWriteAccess(userID, server.ID); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
products, err := s.catalogRepo.GetActiveGoods(server.ID, server.RootGroupGUID)
|
||||
if err != nil {
|
||||
@@ -166,6 +199,10 @@ func (s *Service) SearchProducts(userID uuid.UUID, query string) ([]catalog.Prod
|
||||
if err != nil || server == nil {
|
||||
return nil, fmt.Errorf("no server")
|
||||
}
|
||||
// Поиск нужен для матчинга, значит тоже защищаем
|
||||
if err := s.checkWriteAccess(userID, server.ID); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return s.catalogRepo.Search(server.ID, query, server.RootGroupGUID)
|
||||
}
|
||||
|
||||
@@ -174,6 +211,9 @@ func (s *Service) SaveMapping(userID uuid.UUID, rawName string, productID uuid.U
|
||||
if err != nil || server == nil {
|
||||
return fmt.Errorf("no server")
|
||||
}
|
||||
if err := s.checkWriteAccess(userID, server.ID); err != nil {
|
||||
return err
|
||||
}
|
||||
return s.ocrRepo.SaveMatch(server.ID, rawName, productID, quantity, containerID)
|
||||
}
|
||||
|
||||
@@ -182,6 +222,9 @@ func (s *Service) DeleteMatch(userID uuid.UUID, rawName string) error {
|
||||
if err != nil || server == nil {
|
||||
return fmt.Errorf("no server")
|
||||
}
|
||||
if err := s.checkWriteAccess(userID, server.ID); err != nil {
|
||||
return err
|
||||
}
|
||||
return s.ocrRepo.DeleteMatch(server.ID, rawName)
|
||||
}
|
||||
|
||||
@@ -190,6 +233,9 @@ func (s *Service) GetKnownMatches(userID uuid.UUID) ([]ocr.ProductMatch, error)
|
||||
if err != nil || server == nil {
|
||||
return nil, fmt.Errorf("no server")
|
||||
}
|
||||
if err := s.checkWriteAccess(userID, server.ID); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return s.ocrRepo.GetAllMatches(server.ID)
|
||||
}
|
||||
|
||||
@@ -198,5 +244,8 @@ func (s *Service) GetUnmatchedItems(userID uuid.UUID) ([]ocr.UnmatchedItem, erro
|
||||
if err != nil || server == nil {
|
||||
return nil, fmt.Errorf("no server")
|
||||
}
|
||||
if err := s.checkWriteAccess(userID, server.ID); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return s.ocrRepo.GetTopUnmatched(server.ID, 50)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user