mirror of
https://github.com/serty2005/rmser.git
synced 2026-02-04 19:02:33 -06:00
start rmser
This commit is contained in:
34
internal/domain/catalog/entity.go
Normal file
34
internal/domain/catalog/entity.go
Normal file
@@ -0,0 +1,34 @@
|
||||
package catalog
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/shopspring/decimal"
|
||||
)
|
||||
|
||||
// Product - Номенклатура
|
||||
type Product struct {
|
||||
ID uuid.UUID `gorm:"type:uuid;primary_key;"`
|
||||
ParentID *uuid.UUID `gorm:"type:uuid;index"`
|
||||
Name string `gorm:"type:varchar(255);not null"`
|
||||
Type string `gorm:"type:varchar(50);index"` // GOODS, DISH, PREPARED, etc.
|
||||
Num string `gorm:"type:varchar(50)"`
|
||||
Code string `gorm:"type:varchar(50)"`
|
||||
UnitWeight decimal.Decimal `gorm:"type:numeric(19,4)"`
|
||||
UnitCapacity decimal.Decimal `gorm:"type:numeric(19,4)"`
|
||||
IsDeleted bool `gorm:"default:false"`
|
||||
|
||||
Parent *Product `gorm:"foreignKey:ParentID"`
|
||||
Children []*Product `gorm:"foreignKey:ParentID"`
|
||||
|
||||
CreatedAt time.Time
|
||||
UpdatedAt time.Time
|
||||
}
|
||||
|
||||
// Repository интерфейс для каталога
|
||||
type Repository interface {
|
||||
SaveProducts(products []Product) error
|
||||
GetAll() ([]Product, error)
|
||||
GetActiveGoods() ([]Product, error)
|
||||
}
|
||||
20
internal/domain/interfaces.go
Normal file
20
internal/domain/interfaces.go
Normal file
@@ -0,0 +1,20 @@
|
||||
package domain
|
||||
|
||||
import (
|
||||
"rmser/internal/domain/catalog"
|
||||
"rmser/internal/domain/invoices"
|
||||
"rmser/internal/domain/recipes"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Repository interface {
|
||||
// Catalog
|
||||
SaveProducts(products []catalog.Product) error
|
||||
|
||||
// Recipes
|
||||
SaveRecipes(recipes []recipes.Recipe) error
|
||||
|
||||
// Invoices
|
||||
GetLastInvoiceDate() (*time.Time, error)
|
||||
SaveInvoices(invoices []invoices.Invoice) error
|
||||
}
|
||||
43
internal/domain/invoices/entity.go
Normal file
43
internal/domain/invoices/entity.go
Normal file
@@ -0,0 +1,43 @@
|
||||
package invoices
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"rmser/internal/domain/catalog"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/shopspring/decimal"
|
||||
)
|
||||
|
||||
// Invoice - Приходная накладная
|
||||
type Invoice struct {
|
||||
ID uuid.UUID `gorm:"type:uuid;primary_key;"`
|
||||
DocumentNumber string `gorm:"type:varchar(100);index"`
|
||||
DateIncoming time.Time `gorm:"index"`
|
||||
SupplierID uuid.UUID `gorm:"type:uuid;index"`
|
||||
DefaultStoreID uuid.UUID `gorm:"type:uuid;index"`
|
||||
Status string `gorm:"type:varchar(50)"`
|
||||
|
||||
Items []InvoiceItem `gorm:"foreignKey:InvoiceID;constraint:OnDelete:CASCADE"`
|
||||
|
||||
CreatedAt time.Time
|
||||
UpdatedAt time.Time
|
||||
}
|
||||
|
||||
// InvoiceItem - Позиция накладной
|
||||
type InvoiceItem struct {
|
||||
ID uuid.UUID `gorm:"type:uuid;primary_key;default:gen_random_uuid()"`
|
||||
InvoiceID uuid.UUID `gorm:"type:uuid;not null;index"`
|
||||
ProductID uuid.UUID `gorm:"type:uuid;not null"`
|
||||
Amount decimal.Decimal `gorm:"type:numeric(19,4);not null"`
|
||||
Price decimal.Decimal `gorm:"type:numeric(19,4);not null"`
|
||||
Sum decimal.Decimal `gorm:"type:numeric(19,4);not null"`
|
||||
VatSum decimal.Decimal `gorm:"type:numeric(19,4)"`
|
||||
|
||||
Product catalog.Product `gorm:"foreignKey:ProductID"`
|
||||
}
|
||||
|
||||
type Repository interface {
|
||||
GetLastInvoiceDate() (*time.Time, error)
|
||||
SaveInvoices(invoices []Invoice) error
|
||||
}
|
||||
31
internal/domain/ocr/entity.go
Normal file
31
internal/domain/ocr/entity.go
Normal file
@@ -0,0 +1,31 @@
|
||||
package ocr
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"rmser/internal/domain/catalog"
|
||||
)
|
||||
|
||||
// ProductMatch связывает текст из чека с конкретным товаром в iiko
|
||||
type ProductMatch struct {
|
||||
// RawName - распознанный текст (ключ).
|
||||
// Лучше хранить в нижнем регистре и без лишних пробелов.
|
||||
RawName string `gorm:"type:varchar(255);primary_key"`
|
||||
|
||||
ProductID uuid.UUID `gorm:"type:uuid;not null;index"`
|
||||
|
||||
// Product - связь для GORM
|
||||
Product catalog.Product `gorm:"foreignKey:ProductID"`
|
||||
|
||||
UpdatedAt time.Time
|
||||
CreatedAt time.Time
|
||||
}
|
||||
|
||||
type Repository interface {
|
||||
// SaveMatch сохраняет или обновляет привязку
|
||||
SaveMatch(rawName string, productID uuid.UUID) error
|
||||
|
||||
// FindMatch ищет товар по точному совпадению названия
|
||||
FindMatch(rawName string) (*uuid.UUID, error)
|
||||
}
|
||||
48
internal/domain/operations/entity.go
Normal file
48
internal/domain/operations/entity.go
Normal file
@@ -0,0 +1,48 @@
|
||||
package operations
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"rmser/internal/domain/catalog"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/shopspring/decimal"
|
||||
)
|
||||
|
||||
type OperationType string
|
||||
|
||||
const (
|
||||
OpTypePurchase OperationType = "PURCHASE" // Закупка (Приход)
|
||||
OpTypeUsage OperationType = "USAGE" // Расход (Реализация + Списание)
|
||||
OpTypeUnknown OperationType = "UNKNOWN" // Прочее (Инвентаризация, Перемещения - игнорируем пока)
|
||||
)
|
||||
|
||||
// StoreOperation - запись из складского отчета
|
||||
type StoreOperation struct {
|
||||
ID uuid.UUID `gorm:"type:uuid;primary_key;default:gen_random_uuid()"`
|
||||
ProductID uuid.UUID `gorm:"type:uuid;not null;index"`
|
||||
|
||||
// Наш внутренний, "очищенный" тип операции
|
||||
OpType OperationType `gorm:"type:varchar(50);index"`
|
||||
|
||||
// Raw данные из iiko для отладки и детализации
|
||||
DocumentType string `gorm:"type:varchar(100);index"` // INCOMING_INVOICE, etc.
|
||||
TransactionType string `gorm:"type:varchar(100)"` // INVOICE, WRITEOFF, etc.
|
||||
DocumentNumber string `gorm:"type:varchar(100)"`
|
||||
|
||||
Amount decimal.Decimal `gorm:"type:numeric(19,4)"`
|
||||
Sum decimal.Decimal `gorm:"type:numeric(19,4)"`
|
||||
Cost decimal.Decimal `gorm:"type:numeric(19,4)"`
|
||||
|
||||
// Период синхронизации (для перезаписи данных)
|
||||
PeriodFrom time.Time `gorm:"index"`
|
||||
PeriodTo time.Time `gorm:"index"`
|
||||
|
||||
Product catalog.Product `gorm:"foreignKey:ProductID"`
|
||||
|
||||
CreatedAt time.Time
|
||||
}
|
||||
|
||||
type Repository interface {
|
||||
SaveOperations(ops []StoreOperation, opType OperationType, dateFrom, dateTo time.Time) error
|
||||
}
|
||||
36
internal/domain/recipes/entity.go
Normal file
36
internal/domain/recipes/entity.go
Normal file
@@ -0,0 +1,36 @@
|
||||
package recipes
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"rmser/internal/domain/catalog"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/shopspring/decimal"
|
||||
)
|
||||
|
||||
// Recipe - Технологическая карта
|
||||
type Recipe struct {
|
||||
ID uuid.UUID `gorm:"type:uuid;primary_key;"`
|
||||
ProductID uuid.UUID `gorm:"type:uuid;not null;index"`
|
||||
DateFrom time.Time `gorm:"index"`
|
||||
DateTo *time.Time
|
||||
|
||||
Product catalog.Product `gorm:"foreignKey:ProductID"`
|
||||
Items []RecipeItem `gorm:"foreignKey:RecipeID;constraint:OnDelete:CASCADE"`
|
||||
}
|
||||
|
||||
// RecipeItem - Ингредиент
|
||||
type RecipeItem struct {
|
||||
ID uuid.UUID `gorm:"type:uuid;primary_key;default:gen_random_uuid()"`
|
||||
RecipeID uuid.UUID `gorm:"type:uuid;not null;index"`
|
||||
ProductID uuid.UUID `gorm:"type:uuid;not null;index"`
|
||||
AmountIn decimal.Decimal `gorm:"type:numeric(19,4);not null"`
|
||||
AmountOut decimal.Decimal `gorm:"type:numeric(19,4);not null"`
|
||||
|
||||
Product catalog.Product `gorm:"foreignKey:ProductID"`
|
||||
}
|
||||
|
||||
type Repository interface {
|
||||
SaveRecipes(recipes []Recipe) error
|
||||
}
|
||||
43
internal/domain/recommendations/entity.go
Normal file
43
internal/domain/recommendations/entity.go
Normal file
@@ -0,0 +1,43 @@
|
||||
package recommendations
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
// Типы проблем
|
||||
const (
|
||||
TypeUnused = "UNUSED_IN_RECIPES" // Товар не используется в техкартах
|
||||
TypeNoIncoming = "NO_INCOMING" // Ингредиент (GOODS) в техкарте, но нет приходов
|
||||
TypeStale = "STALE_GOODS" // Есть приходы, но нет продаж
|
||||
TypeDishInRecipe = "DISH_IN_RECIPE" // Блюдо (DISH) в составе другого блюда
|
||||
TypePurchasedButUnused = "PURCHASED_BUT_UNUSED" // Активно закупается, но нет в техкартах
|
||||
TypeUsageNoIncoming = "USAGE_NO_INCOMING" // Есть расходы, но нет приходов
|
||||
)
|
||||
|
||||
// Recommendation - Результат анализа
|
||||
type Recommendation struct {
|
||||
ID uuid.UUID `gorm:"type:uuid;primary_key;default:gen_random_uuid()"`
|
||||
Type string `gorm:"type:varchar(50);index"`
|
||||
ProductID uuid.UUID `gorm:"type:uuid;index"`
|
||||
ProductName string `gorm:"type:varchar(255)"`
|
||||
Reason string `gorm:"type:text"`
|
||||
|
||||
CreatedAt time.Time
|
||||
}
|
||||
|
||||
// Repository отвечает за аналитические выборки и хранение результатов
|
||||
type Repository interface {
|
||||
// Методы анализа (возвращают список структур, но не пишут в БД)
|
||||
FindUnusedGoods() ([]Recommendation, error)
|
||||
FindNoIncomingIngredients(days int) ([]Recommendation, error)
|
||||
FindStaleGoods(days int) ([]Recommendation, error)
|
||||
FindDishesInRecipes() ([]Recommendation, error)
|
||||
FindPurchasedButUnused(days int) ([]Recommendation, error)
|
||||
FindUsageWithoutPurchase(days int) ([]Recommendation, error)
|
||||
|
||||
// Методы "Кэша" в БД
|
||||
SaveAll(items []Recommendation) error // Удаляет старые и пишет новые
|
||||
GetAll() ([]Recommendation, error)
|
||||
}
|
||||
Reference in New Issue
Block a user