Перевел на multi-tenant

Добавил поставщиков
Накладные успешно создаются из фронта
This commit is contained in:
2025-12-18 03:56:21 +03:00
parent 47ec8094e5
commit 542beafe0e
38 changed files with 1942 additions and 977 deletions

View File

@@ -16,12 +16,17 @@ 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"}},
Columns: []clause.Column{{Name: "id"}}, // ID глобально уникален (UUID), конфликтов между серверами не будет
UpdateAll: true,
}).CreateInBatches(units, 100).Error
}
@@ -29,7 +34,7 @@ func (r *pgRepository) SaveMeasureUnits(units []catalog.MeasureUnit) error {
func (r *pgRepository) SaveProducts(products []catalog.Product) error {
sorted := sortProductsByHierarchy(products)
return r.db.Transaction(func(tx *gorm.DB) error {
// 1. Сохраняем продукты (без контейнеров, чтобы ускорить и не дублировать)
// 1. Продукты
if err := tx.Omit("Containers").Clauses(clause.OnConflict{
Columns: []clause.Column{{Name: "id"}},
UpdateAll: true,
@@ -37,13 +42,12 @@ func (r *pgRepository) SaveProducts(products []catalog.Product) error {
return err
}
// 2. Собираем все контейнеры в один слайс
// 2. Контейнеры
var allContainers []catalog.ProductContainer
for _, p := range products {
allContainers = append(allContainers, p.Containers...)
}
// 3. Сохраняем контейнеры
if len(allContainers) > 0 {
if err := tx.Clauses(clause.OnConflict{
Columns: []clause.Column{{Name: "id"}},
@@ -56,13 +60,66 @@ func (r *pgRepository) SaveProducts(products []catalog.Product) error {
})
}
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").Find(&products).Error
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
@@ -104,58 +161,18 @@ func sortProductsByHierarchy(products []catalog.Product) []catalog.Product {
return result
}
// GetActiveGoods возвращает только активные товары c подгруженной единицей измерения
// GetActiveGoods оптимизирован: подгружаем Units и Containers
func (r *pgRepository) GetActiveGoods() ([]catalog.Product, error) {
var products []catalog.Product
err := r.db.
Preload("MainUnit").
Preload("Containers"). // <-- Подгружаем фасовки
Where("is_deleted = ? AND type IN ?", false, []string{"GOODS"}).
Order("name ASC").
Find(&products).Error
return products, err
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) 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
}
func (r *pgRepository) GetActiveStores() ([]catalog.Store, error) {
var stores []catalog.Store
err := r.db.Where("is_deleted = ?", false).Order("name ASC").Find(&stores).Error
return stores, err
}
// SaveContainer сохраняет или обновляет одну фасовку
func (r *pgRepository) SaveContainer(container catalog.ProductContainer) error {
return r.db.Clauses(clause.OnConflict{
Columns: []clause.Column{{Name: "id"}},
UpdateAll: true,
}).Create(&container).Error
}
// Search ищет товары по названию, артикулу или коду (ILIKE)
func (r *pgRepository) Search(query string) ([]catalog.Product, error) {
var products []catalog.Product
// Оборачиваем в проценты для поиска подстроки
q := "%" + query + "%"
err := r.db.
Preload("MainUnit").
Preload("Containers"). // Обязательно грузим фасовки, они нужны для выбора
Where("is_deleted = ? AND type = ?", 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
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
}