start rmser

This commit is contained in:
2025-11-29 08:40:24 +03:00
commit 5aa2238eea
2117 changed files with 375169 additions and 0 deletions

View 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)
}

View 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
}

View 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
}

View 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)
}

View 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
}

View 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
}

View 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)
}