Files
rmser/internal/infrastructure/repository/catalog/postgres.go
SERTY 542beafe0e Перевел на multi-tenant
Добавил поставщиков
Накладные успешно создаются из фронта
2025-12-18 03:56:21 +03:00

179 lines
5.5 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package catalog
import (
"rmser/internal/domain/catalog"
"github.com/google/uuid"
"gorm.io/gorm"
"gorm.io/gorm/clause"
)
type pgRepository struct {
db *gorm.DB
}
func NewRepository(db *gorm.DB) catalog.Repository {
return &pgRepository{db: db}
}
// --- Запись (Save) ---
// При сохранении мы предполагаем, что serverID уже проставлен в Entity в слое Service.
// Но для надежности можно передавать serverID в метод Save, однако Service должен это контролировать.
// Оставим контракт Save(products []Product), где внутри products уже заполнен RMSServerID.
func (r *pgRepository) SaveMeasureUnits(units []catalog.MeasureUnit) error {
if len(units) == 0 {
return nil
}
return r.db.Clauses(clause.OnConflict{
Columns: []clause.Column{{Name: "id"}}, // ID глобально уникален (UUID), конфликтов между серверами не будет
UpdateAll: true,
}).CreateInBatches(units, 100).Error
}
func (r *pgRepository) SaveProducts(products []catalog.Product) error {
sorted := sortProductsByHierarchy(products)
return r.db.Transaction(func(tx *gorm.DB) error {
// 1. Продукты
if err := tx.Omit("Containers").Clauses(clause.OnConflict{
Columns: []clause.Column{{Name: "id"}},
UpdateAll: true,
}).CreateInBatches(sorted, 100).Error; err != nil {
return err
}
// 2. Контейнеры
var allContainers []catalog.ProductContainer
for _, p := range products {
allContainers = append(allContainers, p.Containers...)
}
if len(allContainers) > 0 {
if err := tx.Clauses(clause.OnConflict{
Columns: []clause.Column{{Name: "id"}},
UpdateAll: true,
}).CreateInBatches(allContainers, 100).Error; err != nil {
return err
}
}
return nil
})
}
func (r *pgRepository) SaveContainer(container catalog.ProductContainer) error {
return r.db.Clauses(clause.OnConflict{
Columns: []clause.Column{{Name: "id"}},
UpdateAll: true,
}).Create(&container).Error
}
func (r *pgRepository) SaveStores(stores []catalog.Store) error {
if len(stores) == 0 {
return nil
}
return r.db.Clauses(clause.OnConflict{
Columns: []clause.Column{{Name: "id"}},
UpdateAll: true,
}).CreateInBatches(stores, 100).Error
}
// --- Чтение (Read) с фильтрацией по ServerID ---
func (r *pgRepository) GetAll() ([]catalog.Product, error) {
// Этот метод был legacy и грузил всё. Теперь он опасен без serverID.
// Оставляем заглушку или удаляем. Лучше удалить из интерфейса, но пока вернем пустой список
// чтобы не ломать сборку, пока не почистим вызовы.
return nil, nil
}
func (r *pgRepository) GetActiveGoods(serverID uuid.UUID) ([]catalog.Product, error) {
var products []catalog.Product
err := r.db.
Preload("MainUnit").
Preload("Containers").
Where("rms_server_id = ? AND is_deleted = ? AND type IN ?", serverID, false, []string{"GOODS"}).
Order("name ASC").
Find(&products).Error
return products, err
}
func (r *pgRepository) GetActiveStores(serverID uuid.UUID) ([]catalog.Store, error) {
var stores []catalog.Store
err := r.db.Where("rms_server_id = ? AND is_deleted = ?", serverID, false).Order("name ASC").Find(&stores).Error
return stores, err
}
func (r *pgRepository) Search(serverID uuid.UUID, query string) ([]catalog.Product, error) {
var products []catalog.Product
q := "%" + query + "%"
err := r.db.
Preload("MainUnit").
Preload("Containers").
Where("rms_server_id = ? AND is_deleted = ? AND type = ?", serverID, false, "GOODS").
Where("name ILIKE ? OR code ILIKE ? OR num ILIKE ?", q, q, q).
Order("name ASC").
Limit(20).
Find(&products).Error
return products, err
}
// sortProductsByHierarchy - вспомогательная функция, оставляем как есть (копипаст из старого файла)
func sortProductsByHierarchy(products []catalog.Product) []catalog.Product {
if len(products) == 0 {
return products
}
childrenMap := make(map[uuid.UUID][]catalog.Product)
var roots []catalog.Product
allIDs := make(map[uuid.UUID]struct{}, len(products))
for _, p := range products {
allIDs[p.ID] = struct{}{}
}
for _, p := range products {
if p.ParentID == nil {
roots = append(roots, p)
} else {
if _, exists := allIDs[*p.ParentID]; exists {
childrenMap[*p.ParentID] = append(childrenMap[*p.ParentID], p)
} else {
roots = append(roots, p)
}
}
}
result := make([]catalog.Product, 0, len(products))
queue := roots
for len(queue) > 0 {
current := queue[0]
queue = queue[1:]
result = append(result, current)
if children, ok := childrenMap[current.ID]; ok {
queue = append(queue, children...)
delete(childrenMap, current.ID)
}
}
for _, remaining := range childrenMap {
result = append(result, remaining...)
}
return result
}
func (r *pgRepository) CountGoods(serverID uuid.UUID) (int64, error) {
var count int64
err := r.db.Model(&catalog.Product{}).
Where("rms_server_id = ? AND type IN ? AND is_deleted = ?", serverID, []string{"GOODS"}, false).
Count(&count).Error
return count, err
}
func (r *pgRepository) CountStores(serverID uuid.UUID) (int64, error) {
var count int64
err := r.db.Model(&catalog.Store{}).
Where("rms_server_id = ? AND is_deleted = ?", serverID, false).
Count(&count).Error
return count, err
}