2701-есть флоу для оператора и красивый список накладных

This commit is contained in:
2026-01-27 06:31:38 +03:00
parent 8332b6ecda
commit 38a5143902
11 changed files with 1508 additions and 158 deletions

View File

@@ -20,12 +20,24 @@ import (
"rmser/internal/domain/account"
"rmser/internal/infrastructure/rms"
"rmser/internal/services/billing"
draftsService "rmser/internal/services/drafts"
"rmser/internal/services/ocr"
"rmser/internal/services/sync"
"rmser/pkg/crypto"
"rmser/pkg/logger"
)
const DraftEditorPageSize = 10
// shortUUID возвращает первые 8 символов UUID для callback data
func shortUUID(id uuid.UUID) string {
s := id.String()
if len(s) >= 8 {
return s[:8]
}
return s
}
type Bot struct {
b *tele.Bot
ocrService *ocr.Service
@@ -34,6 +46,8 @@ type Bot struct {
accountRepo account.Repository
rmsFactory *rms.Factory
cryptoManager *crypto.CryptoManager
draftsService *draftsService.Service
draftEditor *DraftEditor
fsm *StateManager
adminIDs map[int64]struct{}
@@ -54,6 +68,7 @@ func NewBot(
accountRepo account.Repository,
rmsFactory *rms.Factory,
cryptoManager *crypto.CryptoManager,
draftsService *draftsService.Service,
maintenanceMode bool,
devIDs []int64,
) (*Bot, error) {
@@ -89,6 +104,7 @@ func NewBot(
accountRepo: accountRepo,
rmsFactory: rmsFactory,
cryptoManager: cryptoManager,
draftsService: draftsService,
fsm: NewStateManager(),
adminIDs: admins,
devIDs: devs,
@@ -100,6 +116,8 @@ func NewBot(
bot.webAppURL = "http://example.com"
}
bot.draftEditor = NewDraftEditor(bot.b, bot.draftsService, bot.accountRepo, bot.fsm)
bot.initMenus()
bot.initHandlers()
return bot, nil
@@ -133,6 +151,8 @@ func (bot *Bot) initHandlers() {
bot.b.Handle("/start", bot.handleStartCommand)
bot.b.Handle("/admin", bot.handleAdminCommand)
bot.b.Handle("/draft", bot.draftEditor.handleDraftCommand)
bot.b.Handle("/newdraft", bot.draftEditor.handleNewDraftCommand)
bot.b.Handle(&tele.Btn{Unique: "nav_main"}, bot.renderMainMenu)
bot.b.Handle(&tele.Btn{Unique: "nav_servers"}, bot.renderServersMenu)
@@ -152,6 +172,10 @@ func (bot *Bot) initHandlers() {
bot.b.Handle(tele.OnText, bot.handleText)
bot.b.Handle(tele.OnPhoto, bot.handlePhoto)
bot.b.Handle(tele.OnDocument, bot.handleDocument)
bot.b.Handle(&tele.Btn{Unique: "noop"}, func(c tele.Context) error {
return c.Respond()
})
}
func (bot *Bot) Start() {
@@ -471,6 +495,15 @@ func (bot *Bot) handleCallback(c tele.Context) error {
return c.Respond(&tele.CallbackResponse{Text: "Сервис на обслуживании"})
}
// === DRAFT EDITOR CALLBACKS ===
// Проверяем префиксы редактора черновиков
draftPrefixes := []string{"di:", "dp:", "da:", "dc:", "dx:", "den:", "deq:", "dep:", "did:", "dib:"}
for _, prefix := range draftPrefixes {
if strings.HasPrefix(data, prefix) {
return bot.draftEditor.handleDraftEditorCallback(c, data)
}
}
// --- INTEGRATION: Billing Callbacks ---
if strings.HasPrefix(data, "bill_") || strings.HasPrefix(data, "buy_id_") || strings.HasPrefix(data, "pay_") {
return bot.handleBillingCallbacks(c, data, userDB)
@@ -749,6 +782,14 @@ func (bot *Bot) handleText(c tele.Context) error {
return bot.renderMainMenu(c)
}
// === DRAFT EDITOR TEXT HANDLERS ===
// Проверяем, находимся ли мы в одном из состояний редактирования черновика
if state == StateDraftEditItemName ||
state == StateDraftEditItemQty ||
state == StateDraftEditItemPrice {
return bot.draftEditor.handleDraftEditorText(c)
}
if state == StateNone {
return c.Send("Используйте меню для навигации 👇")
}
@@ -864,6 +905,7 @@ func (bot *Bot) handlePhoto(c tele.Context) error {
matchedCount++
}
}
// Для разработчиков отправляем debug-информацию
if bot.isDev(userID) {
baseURL := strings.TrimRight(bot.webAppURL, "/")
fullURL := fmt.Sprintf("%s/invoice/%s", baseURL, draft.ID.String())
@@ -881,10 +923,12 @@ func (bot *Bot) handlePhoto(c tele.Context) error {
} else {
msgText += "\n\n<i>(Редактирование доступно Администратору)</i>"
}
return c.Send(msgText, menu, tele.ModeHTML)
} else {
return c.Send("✅ **Фото принято!** Мы получили ваш документ и передали его оператору. Спасибо!", tele.ModeHTML)
c.Send(msgText, menu, tele.ModeHTML)
}
// Инициализируем FSM редактора для всех пользователей
bot.fsm.InitDraftEditor(userID, draft.ID)
// Показываем меню редактора
return bot.draftEditor.renderDraftEditorMenu(c, draft, 0)
}
func (bot *Bot) handleDocument(c tele.Context) error {
@@ -942,6 +986,7 @@ func (bot *Bot) handleDocument(c tele.Context) error {
matchedCount++
}
}
// Для разработчиков отправляем debug-информацию
if bot.isDev(userID) {
baseURL := strings.TrimRight(bot.webAppURL, "/")
fullURL := fmt.Sprintf("%s/invoice/%s", baseURL, draft.ID.String())
@@ -959,10 +1004,12 @@ func (bot *Bot) handleDocument(c tele.Context) error {
} else {
msgText += "\n\n<i>(Редактирование доступно Администратору)</i>"
}
return c.Send(msgText, menu, tele.ModeHTML)
} else {
return c.Send("✅ **Документ принят!** Мы получили ваш документ и передали его оператору. Спасибо!", tele.ModeHTML)
c.Send(msgText, menu, tele.ModeHTML)
}
// Инициализируем FSM редактора для всех пользователей
bot.fsm.InitDraftEditor(userID, draft.ID)
// Показываем меню редактора
return bot.draftEditor.renderDraftEditorMenu(c, draft, 0)
}
func (bot *Bot) handleConfirmNameYes(c tele.Context) error {