package treasury import ( "context" "strings" "time" "github.com/tech/sendico/gateway/tgsettle/internal/service/treasury/bot" "github.com/tech/sendico/gateway/tgsettle/internal/service/treasury/ledger" "github.com/tech/sendico/gateway/tgsettle/storage" storagemodel "github.com/tech/sendico/gateway/tgsettle/storage/model" "github.com/tech/sendico/pkg/merrors" "github.com/tech/sendico/pkg/mlogger" "github.com/tech/sendico/pkg/model" ) type Module struct { logger mlogger.Logger service *Service router *bot.Router scheduler *Scheduler ledger ledger.Client } func NewModule( logger mlogger.Logger, repo storage.TreasuryRequestsStore, ledgerClient ledger.Client, cfg Config, send bot.SendTextFunc, ) (*Module, error) { if logger != nil { logger = logger.Named("treasury") } service, err := NewService( logger, repo, ledgerClient, cfg.ExecutionDelay, cfg.MaxAmountPerOperation, cfg.MaxDailyAmount, ) if err != nil { return nil, err } users := map[string]string{} for _, binding := range cfg.Users { userID := strings.TrimSpace(binding.TelegramUserID) accountID := strings.TrimSpace(binding.LedgerAccount) if userID == "" || accountID == "" { continue } users[userID] = accountID } module := &Module{ logger: logger, service: service, ledger: ledgerClient, } module.scheduler = NewScheduler(logger, service, NotifyFunc(send), cfg.PollInterval) module.router = bot.NewRouter(logger, &botServiceAdapter{svc: service}, send, module.scheduler, cfg.AllowedChats, users) return module, nil } func (m *Module) Enabled() bool { return m != nil && m.router != nil && m.router.Enabled() && m.scheduler != nil } func (m *Module) Start() { if m == nil || m.scheduler == nil { return } m.scheduler.Start() } func (m *Module) Shutdown() { if m == nil { return } if m.scheduler != nil { m.scheduler.Shutdown() } if m.ledger != nil { _ = m.ledger.Close() } } func (m *Module) HandleUpdate(ctx context.Context, update *model.TelegramWebhookUpdate) bool { if m == nil || m.router == nil { return false } return m.router.HandleUpdate(ctx, update) } type botServiceAdapter struct { svc *Service } func (a *botServiceAdapter) ExecutionDelay() (delay time.Duration) { if a == nil || a.svc == nil { return 0 } return a.svc.ExecutionDelay() } func (a *botServiceAdapter) MaxPerOperationLimit() string { if a == nil || a.svc == nil { return "" } return a.svc.MaxPerOperationLimit() } func (a *botServiceAdapter) GetActiveRequestForAccount(ctx context.Context, ledgerAccountID string) (*storagemodel.TreasuryRequest, error) { if a == nil || a.svc == nil { return nil, merrors.Internal("treasury service unavailable") } return a.svc.GetActiveRequestForAccount(ctx, ledgerAccountID) } func (a *botServiceAdapter) GetAccountProfile(ctx context.Context, ledgerAccountID string) (*bot.AccountProfile, error) { if a == nil || a.svc == nil { return nil, merrors.Internal("treasury service unavailable") } profile, err := a.svc.GetAccountProfile(ctx, ledgerAccountID) if err != nil { return nil, err } if profile == nil { return nil, nil } return &bot.AccountProfile{ AccountID: strings.TrimSpace(profile.AccountID), AccountCode: strings.TrimSpace(profile.AccountCode), Currency: strings.TrimSpace(profile.Currency), }, nil } func (a *botServiceAdapter) CreateRequest(ctx context.Context, input bot.CreateRequestInput) (*storagemodel.TreasuryRequest, error) { if a == nil || a.svc == nil { return nil, merrors.Internal("treasury service unavailable") } return a.svc.CreateRequest(ctx, CreateRequestInput{ OperationType: input.OperationType, TelegramUserID: input.TelegramUserID, LedgerAccountID: input.LedgerAccountID, ChatID: input.ChatID, Amount: input.Amount, }) } func (a *botServiceAdapter) ConfirmRequest(ctx context.Context, requestID string, telegramUserID string) (*storagemodel.TreasuryRequest, error) { if a == nil || a.svc == nil { return nil, merrors.Internal("treasury service unavailable") } return a.svc.ConfirmRequest(ctx, requestID, telegramUserID) } func (a *botServiceAdapter) CancelRequest(ctx context.Context, requestID string, telegramUserID string) (*storagemodel.TreasuryRequest, error) { if a == nil || a.svc == nil { return nil, merrors.Internal("treasury service unavailable") } return a.svc.CancelRequest(ctx, requestID, telegramUserID) }