mirror of
https://github.com/serty2005/rmser.git
synced 2026-02-05 03:12:34 -06:00
114 lines
3.2 KiB
Go
114 lines
3.2 KiB
Go
package ocr
|
|
|
|
import (
|
|
"strings"
|
|
"time"
|
|
|
|
"gorm.io/gorm"
|
|
"gorm.io/gorm/clause"
|
|
|
|
"rmser/internal/domain/ocr"
|
|
|
|
"github.com/google/uuid"
|
|
"github.com/shopspring/decimal"
|
|
)
|
|
|
|
type pgRepository struct {
|
|
db *gorm.DB
|
|
}
|
|
|
|
func NewRepository(db *gorm.DB) ocr.Repository {
|
|
return &pgRepository{db: db}
|
|
}
|
|
|
|
func (r *pgRepository) SaveMatch(rawName string, productID uuid.UUID, quantity decimal.Decimal, containerID *uuid.UUID) error {
|
|
normalized := strings.ToLower(strings.TrimSpace(rawName))
|
|
match := ocr.ProductMatch{
|
|
RawName: normalized,
|
|
ProductID: productID,
|
|
Quantity: quantity,
|
|
ContainerID: containerID,
|
|
}
|
|
|
|
return r.db.Transaction(func(tx *gorm.DB) error {
|
|
if err := tx.Clauses(clause.OnConflict{
|
|
Columns: []clause.Column{{Name: "raw_name"}},
|
|
DoUpdates: clause.AssignmentColumns([]string{"product_id", "quantity", "container_id", "updated_at"}),
|
|
}).Create(&match).Error; err != nil {
|
|
return err
|
|
}
|
|
|
|
if err := tx.Where("raw_name = ?", normalized).Delete(&ocr.UnmatchedItem{}).Error; err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
})
|
|
}
|
|
|
|
func (r *pgRepository) DeleteMatch(rawName string) error {
|
|
normalized := strings.ToLower(strings.TrimSpace(rawName))
|
|
return r.db.Where("raw_name = ?", normalized).Delete(&ocr.ProductMatch{}).Error
|
|
}
|
|
|
|
func (r *pgRepository) FindMatch(rawName string) (*ocr.ProductMatch, error) {
|
|
normalized := strings.ToLower(strings.TrimSpace(rawName))
|
|
var match ocr.ProductMatch
|
|
|
|
// Preload Container на случай, если нам сразу нужна инфа
|
|
err := r.db.Preload("Container").Where("raw_name = ?", normalized).First(&match).Error
|
|
if err != nil {
|
|
if err == gorm.ErrRecordNotFound {
|
|
return nil, nil
|
|
}
|
|
return nil, err
|
|
}
|
|
return &match, nil
|
|
}
|
|
|
|
func (r *pgRepository) GetAllMatches() ([]ocr.ProductMatch, error) {
|
|
var matches []ocr.ProductMatch
|
|
// Подгружаем Товар, Единицу и Фасовку
|
|
err := r.db.
|
|
Preload("Product").
|
|
Preload("Product.MainUnit").
|
|
Preload("Container").
|
|
Order("updated_at DESC").
|
|
Find(&matches).Error
|
|
return matches, err
|
|
}
|
|
|
|
// UpsertUnmatched увеличивает счетчик встречаемости
|
|
func (r *pgRepository) UpsertUnmatched(rawName string) error {
|
|
normalized := strings.ToLower(strings.TrimSpace(rawName))
|
|
if normalized == "" {
|
|
return nil
|
|
}
|
|
|
|
// Используем сырой SQL или GORM upsert expression
|
|
// PostgreSQL: INSERT ... ON CONFLICT DO UPDATE SET count = count + 1
|
|
item := ocr.UnmatchedItem{
|
|
RawName: normalized,
|
|
Count: 1,
|
|
LastSeen: time.Now(),
|
|
}
|
|
|
|
return r.db.Clauses(clause.OnConflict{
|
|
Columns: []clause.Column{{Name: "raw_name"}},
|
|
DoUpdates: clause.Assignments(map[string]interface{}{
|
|
"count": gorm.Expr("unmatched_items.count + 1"),
|
|
"last_seen": time.Now(),
|
|
}),
|
|
}).Create(&item).Error
|
|
}
|
|
|
|
func (r *pgRepository) GetTopUnmatched(limit int) ([]ocr.UnmatchedItem, error) {
|
|
var items []ocr.UnmatchedItem
|
|
err := r.db.Order("count DESC, last_seen DESC").Limit(limit).Find(&items).Error
|
|
return items, err
|
|
}
|
|
|
|
func (r *pgRepository) DeleteUnmatched(rawName string) error {
|
|
normalized := strings.ToLower(strings.TrimSpace(rawName))
|
|
return r.db.Where("raw_name = ?", normalized).Delete(&ocr.UnmatchedItem{}).Error
|
|
}
|