extended confirmation flow handling #538
@@ -148,14 +148,23 @@ func (s *Service) onTelegramUpdate(ctx context.Context, update *model.TelegramWe
|
||||
if replyToID == "" {
|
||||
return nil
|
||||
}
|
||||
replyFields := telegramReplyLogFields(update)
|
||||
pending, err := s.repo.PendingConfirmations().FindByMessageID(ctx, replyToID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if pending == nil {
|
||||
s.logger.Debug("Telegram reply ignored: no pending confirmation for message", zap.String("reply_to_message_id", replyToID), zap.Int64("update_id", update.UpdateID))
|
||||
s.logger.Info("Telegram confirmation reply dropped",
|
||||
append(replyFields,
|
||||
zap.String("outcome", "dropped"),
|
||||
zap.String("reason", "no_pending_confirmation"),
|
||||
)...)
|
||||
return nil
|
||||
}
|
||||
replyFields = append(replyFields,
|
||||
zap.String("request_id", strings.TrimSpace(pending.RequestID)),
|
||||
zap.String("target_chat_id", strings.TrimSpace(pending.TargetChatID)),
|
||||
)
|
||||
|
||||
if !pending.ExpiresAt.IsZero() && time.Now().After(pending.ExpiresAt) {
|
||||
result := &model.ConfirmationResult{
|
||||
@@ -165,14 +174,25 @@ func (s *Service) onTelegramUpdate(ctx context.Context, update *model.TelegramWe
|
||||
if err := s.publishPendingConfirmationResult(pending, result); err != nil {
|
||||
return err
|
||||
}
|
||||
return s.clearPendingConfirmation(ctx, pending.RequestID)
|
||||
if err := s.clearPendingConfirmation(ctx, pending.RequestID); err != nil {
|
||||
return err
|
||||
}
|
||||
s.logger.Info("Telegram confirmation reply processed",
|
||||
append(replyFields,
|
||||
zap.String("outcome", "processed"),
|
||||
zap.String("result_status", string(result.Status)),
|
||||
zap.String("reason", "expired_confirmation"),
|
||||
)...)
|
||||
return nil
|
||||
}
|
||||
|
||||
if strings.TrimSpace(message.ChatID) != strings.TrimSpace(pending.TargetChatID) {
|
||||
s.logger.Debug("Telegram reply ignored: chat mismatch",
|
||||
zap.String("request_id", pending.RequestID),
|
||||
zap.String("expected_chat_id", pending.TargetChatID),
|
||||
zap.String("chat_id", strings.TrimSpace(message.ChatID)))
|
||||
s.logger.Info("Telegram confirmation reply dropped",
|
||||
append(replyFields,
|
||||
zap.String("outcome", "dropped"),
|
||||
zap.String("reason", "chat_mismatch"),
|
||||
zap.String("expected_chat_id", strings.TrimSpace(pending.TargetChatID)),
|
||||
)...)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -192,7 +212,16 @@ func (s *Service) onTelegramUpdate(ctx context.Context, update *model.TelegramWe
|
||||
ReplyToMessageID: message.MessageID,
|
||||
Text: "Only approved users can confirm this payment.",
|
||||
})
|
||||
return s.clearPendingConfirmation(ctx, pending.RequestID)
|
||||
if err := s.clearPendingConfirmation(ctx, pending.RequestID); err != nil {
|
||||
return err
|
||||
}
|
||||
s.logger.Info("Telegram confirmation reply processed",
|
||||
append(replyFields,
|
||||
zap.String("outcome", "processed"),
|
||||
zap.String("result_status", string(result.Status)),
|
||||
zap.String("reason", "unauthorized_user"),
|
||||
)...)
|
||||
return nil
|
||||
}
|
||||
|
||||
money, reason, err := parseConfirmationReply(message.Text)
|
||||
@@ -206,6 +235,12 @@ func (s *Service) onTelegramUpdate(ctx context.Context, update *model.TelegramWe
|
||||
ReplyToMessageID: message.MessageID,
|
||||
Text: clarificationMessage(reason),
|
||||
})
|
||||
s.logger.Info("Telegram confirmation reply dropped",
|
||||
append(replyFields,
|
||||
zap.String("outcome", "dropped"),
|
||||
zap.String("reason", "invalid_reply_format"),
|
||||
zap.String("parse_reason", reason),
|
||||
)...)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -222,7 +257,29 @@ func (s *Service) onTelegramUpdate(ctx context.Context, update *model.TelegramWe
|
||||
if err := s.publishPendingConfirmationResult(pending, result); err != nil {
|
||||
return err
|
||||
}
|
||||
return s.clearPendingConfirmation(ctx, pending.RequestID)
|
||||
if err := s.clearPendingConfirmation(ctx, pending.RequestID); err != nil {
|
||||
return err
|
||||
}
|
||||
s.logger.Info("Telegram confirmation reply processed",
|
||||
append(replyFields,
|
||||
zap.String("outcome", "processed"),
|
||||
zap.String("result_status", string(result.Status)),
|
||||
)...)
|
||||
return nil
|
||||
}
|
||||
|
||||
func telegramReplyLogFields(update *model.TelegramWebhookUpdate) []zap.Field {
|
||||
if update == nil || update.Message == nil {
|
||||
return nil
|
||||
}
|
||||
message := update.Message
|
||||
return []zap.Field{
|
||||
zap.Int64("update_id", update.UpdateID),
|
||||
zap.String("message_id", strings.TrimSpace(message.MessageID)),
|
||||
zap.String("reply_to_message_id", strings.TrimSpace(message.ReplyToMessageID)),
|
||||
zap.String("chat_id", strings.TrimSpace(message.ChatID)),
|
||||
zap.String("from_user_id", strings.TrimSpace(message.FromUserID)),
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Service) publishPendingConfirmationResult(pending *storagemodel.PendingConfirmation, result *model.ConfirmationResult) error {
|
||||
|
||||
@@ -10,15 +10,15 @@ import (
|
||||
|
||||
// OrchestrationStep defines a template step for execution planning.
|
||||
type OrchestrationStep struct {
|
||||
StepID string `bson:"stepId" json:"stepId"`
|
||||
Rail Rail `bson:"rail" json:"rail"`
|
||||
Operation string `bson:"operation" json:"operation"`
|
||||
ReportVisibility ReportVisibility `bson:"reportVisibility,omitempty" json:"reportVisibility,omitempty"`
|
||||
DependsOn []string `bson:"dependsOn,omitempty" json:"dependsOn,omitempty"`
|
||||
CommitPolicy CommitPolicy `bson:"commitPolicy,omitempty" json:"commitPolicy,omitempty"`
|
||||
CommitAfter []string `bson:"commitAfter,omitempty" json:"commitAfter,omitempty"`
|
||||
FromRole *account_role.AccountRole `bson:"fromRole,omitempty" json:"fromRole,omitempty"`
|
||||
ToRole *account_role.AccountRole `bson:"toRole,omitempty" json:"toRole,omitempty"`
|
||||
StepID string `bson:"stepId" json:"stepId"`
|
||||
Rail Rail `bson:"rail" json:"rail"`
|
||||
Operation string `bson:"operation" json:"operation"`
|
||||
ReportVisibility ReportVisibility `bson:"reportVisibility,omitempty" json:"reportVisibility,omitempty"`
|
||||
DependsOn []string `bson:"dependsOn,omitempty" json:"dependsOn,omitempty"`
|
||||
CommitPolicy CommitPolicy `bson:"commitPolicy,omitempty" json:"commitPolicy,omitempty"`
|
||||
CommitAfter []string `bson:"commitAfter,omitempty" json:"commitAfter,omitempty"`
|
||||
FromRole *account_role.AccountRole `bson:"fromRole,omitempty" json:"fromRole,omitempty"`
|
||||
ToRole *account_role.AccountRole `bson:"toRole,omitempty" json:"toRole,omitempty"`
|
||||
}
|
||||
|
||||
// PaymentPlanTemplate stores reusable orchestration templates.
|
||||
|
||||
Reference in New Issue
Block a user