This commit is contained in:
parent
2db2bc0860
commit
507ee16a30
@ -6,12 +6,9 @@ import (
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
tgbotapi "github.com/go-telegram-bot-api/telegram-bot-api/v5"
|
||||
"github.com/google/uuid"
|
||||
"github.com/hibiken/asynq"
|
||||
commonLogic "github.com/perfect-panel/server/internal/logic/common"
|
||||
@ -100,12 +97,10 @@ func (l *AttachTransactionLogic) Attach(req *types.AttachAppleTransactionRequest
|
||||
existingOrderNo, validateErr := l.validateOrderTradeNoBinding(orderInfo, tradeNoCandidates)
|
||||
if validateErr != nil {
|
||||
l.Errorw("Apple 交易绑定校验失败", logger.Field("orderNo", req.OrderNo), logger.Field("tradeNoCandidates", tradeNoCandidates), logger.Field("error", validateErr.Error()))
|
||||
l.sendIAPAttachTraceToTelegram("REJECT_BINDING_ERROR", orderInfo, u.Id, orderInfo.SubscribeId, "", orderInfo.Quantity, txPayload.PurchaseDate, txPayload.TransactionId, txPayload.OriginalTransactionId, validateErr.Error())
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.ERROR), "apple transaction binding error")
|
||||
}
|
||||
if existingOrderNo != "" {
|
||||
l.Errorw("Apple 交易重复绑定,返回已绑定订单", logger.Field("orderNo", req.OrderNo), logger.Field("existingOrderNo", existingOrderNo), logger.Field("tradeNoCandidates", tradeNoCandidates))
|
||||
l.sendIAPAttachTraceToTelegram("REJECT_DUPLICATE_TRANSACTION", orderInfo, u.Id, orderInfo.SubscribeId, "", orderInfo.Quantity, txPayload.PurchaseDate, txPayload.TransactionId, txPayload.OriginalTransactionId, "already used by "+existingOrderNo)
|
||||
// 关闭当前 pending 订单,避免产生孤儿订单
|
||||
if orderInfo.Status == orderStatusPending {
|
||||
if closeErr := l.svcCtx.DB.Model(&ordermodel.Order{}).
|
||||
@ -282,7 +277,6 @@ func (l *AttachTransactionLogic) Attach(req *types.AttachAppleTransactionRequest
|
||||
l.Errorw("同订单幂等同步失败", logger.Field("orderNo", req.OrderNo), logger.Field("error", syncErr.Error()))
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseUpdateError), "sync order status failed: %v", syncErr.Error())
|
||||
}
|
||||
l.sendIAPAttachTraceToTelegram("IDEMPOTENT_SAME_ORDER", orderInfo, u.Id, subscribeId, tier, duration, txPayload.PurchaseDate, txPayload.TransactionId, txPayload.OriginalTransactionId, "")
|
||||
l.Infow("事务已处理,同订单幂等返回", logger.Field("orderNo", req.OrderNo), logger.Field("expiresAt", expiresAt))
|
||||
return &types.AttachAppleTransactionResponse{ExpiresAt: expiresAt, Tier: tier}, nil
|
||||
}
|
||||
@ -296,7 +290,6 @@ func (l *AttachTransactionLogic) Attach(req *types.AttachAppleTransactionRequest
|
||||
l.Errorw("事务已处理但同步订单状态失败", logger.Field("orderNo", req.OrderNo), logger.Field("error", syncErr.Error()))
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseUpdateError), "sync order status failed: %v", syncErr.Error())
|
||||
}
|
||||
l.sendIAPAttachTraceToTelegram("SUCCESS_NEW_PURCHASE_QUEUE", orderInfo, u.Id, subscribeId, tier, duration, txPayload.PurchaseDate, txPayload.TransactionId, txPayload.OriginalTransactionId, "")
|
||||
l.Infow("事务已处理,首购订单等待激活队列发放订阅", logger.Field("orderNo", req.OrderNo), logger.Field("expiresAt", exp.Unix()))
|
||||
return &types.AttachAppleTransactionResponse{ExpiresAt: exp.Unix(), Tier: tier}, nil
|
||||
}
|
||||
@ -316,7 +309,6 @@ func (l *AttachTransactionLogic) Attach(req *types.AttachAppleTransactionRequest
|
||||
l.Errorw("同步订单状态失败(existSub)", logger.Field("orderNo", req.OrderNo), logger.Field("error", syncErr.Error()))
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseUpdateError), "sync order status failed: %v", syncErr.Error())
|
||||
}
|
||||
l.sendIAPAttachTraceToTelegram("SUCCESS_RENEW_EXIST_SUB", orderInfo, u.Id, subscribeId, tier, duration, txPayload.PurchaseDate, txPayload.TransactionId, txPayload.OriginalTransactionId, "")
|
||||
l.Infow("事务已处理,刷新订阅到期时间", logger.Field("originalTransactionId", txPayload.OriginalTransactionId), logger.Field("tier", tier), logger.Field("expiresAt", newExpire.Unix()))
|
||||
return &types.AttachAppleTransactionResponse{
|
||||
ExpiresAt: newExpire.Unix(),
|
||||
@ -337,7 +329,6 @@ func (l *AttachTransactionLogic) Attach(req *types.AttachAppleTransactionRequest
|
||||
l.Errorw("同步订单状态失败(orderLinkedSub)", logger.Field("orderNo", req.OrderNo), logger.Field("error", syncErr.Error()))
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseUpdateError), "sync order status failed: %v", syncErr.Error())
|
||||
}
|
||||
l.sendIAPAttachTraceToTelegram("SUCCESS_RENEW_ORDER_LINKED_SUB", orderInfo, u.Id, subscribeId, tier, duration, txPayload.PurchaseDate, txPayload.TransactionId, txPayload.OriginalTransactionId, "")
|
||||
l.Infow("事务已处理,刷新订单关联订阅到期时间", logger.Field("orderNo", req.OrderNo), logger.Field("userSubscribeId", orderLinkedSub.Id), logger.Field("expiresAt", newExpire.Unix()))
|
||||
return &types.AttachAppleTransactionResponse{ExpiresAt: newExpire.Unix(), Tier: tier}, nil
|
||||
}
|
||||
@ -355,7 +346,6 @@ func (l *AttachTransactionLogic) Attach(req *types.AttachAppleTransactionRequest
|
||||
l.Errorw("同步订单状态失败(singleModeAnchorSub)", logger.Field("orderNo", req.OrderNo), logger.Field("error", syncErr.Error()))
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseUpdateError), "sync order status failed: %v", syncErr.Error())
|
||||
}
|
||||
l.sendIAPAttachTraceToTelegram("SUCCESS_RENEW_SINGLE_MODE_ANCHOR", orderInfo, u.Id, subscribeId, tier, duration, txPayload.PurchaseDate, txPayload.TransactionId, txPayload.OriginalTransactionId, "")
|
||||
l.Infow("事务已处理,刷新单订阅锚点到期时间", logger.Field("userSubscribeId", singleModeAnchorSub.Id), logger.Field("expiresAt", newExpire.Unix()))
|
||||
return &types.AttachAppleTransactionResponse{ExpiresAt: newExpire.Unix(), Tier: tier}, nil
|
||||
}
|
||||
@ -394,6 +384,7 @@ func (l *AttachTransactionLogic) Attach(req *types.AttachAppleTransactionRequest
|
||||
userSub := user.Subscribe{
|
||||
UserId: entitlement.EffectiveUserID,
|
||||
SubscribeId: subscribeId,
|
||||
OrderId: orderInfo.Id,
|
||||
StartTime: time.Now(),
|
||||
ExpireTime: exp,
|
||||
Traffic: 0,
|
||||
@ -426,7 +417,6 @@ func (l *AttachTransactionLogic) Attach(req *types.AttachAppleTransactionRequest
|
||||
l.Errorw("绑定事务提交失败", logger.Field("error", err.Error()))
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseInsertError), "insert error: %v", err.Error())
|
||||
}
|
||||
l.sendIAPAttachTraceToTelegram("SUCCESS_COMMIT", orderInfo, u.Id, subscribeId, tier, duration, txPayload.PurchaseDate, txPayload.TransactionId, txPayload.OriginalTransactionId, "")
|
||||
|
||||
// 事务提交后立即清除订阅缓存,避免 App 查到旧数据(激活队列异步执行,存在竞态)
|
||||
if orderLinkedSub != nil {
|
||||
@ -600,94 +590,3 @@ func containsString(candidates []string, target string) bool {
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (l *AttachTransactionLogic) sendIAPAttachTraceToTelegram(status string, orderInfo *ordermodel.Order, userID int64, subscribeID int64, subscribeName string, quantity int64, purchaseAt time.Time, transactionID string, originalTransactionID string, note string) {
|
||||
if l.svcCtx == nil {
|
||||
return
|
||||
}
|
||||
orderNo := ""
|
||||
if orderInfo != nil {
|
||||
orderNo = orderInfo.OrderNo
|
||||
}
|
||||
if subscribeName == "" {
|
||||
subscribeName = "-"
|
||||
}
|
||||
message := fmt.Sprintf(
|
||||
"IAP Attach Log [%s]\n订单号: %s\n购买时间: %s\n购买人ID: %d\n订阅信息: %s (subscribe_id=%d, quantity=%d)\ntransaction: %s\noriginal_transaction: %s",
|
||||
status,
|
||||
orderNo,
|
||||
purchaseAt.Format("2006-01-02 15:04:05"),
|
||||
userID,
|
||||
subscribeName,
|
||||
subscribeID,
|
||||
quantity,
|
||||
transactionID,
|
||||
originalTransactionID,
|
||||
)
|
||||
if note != "" {
|
||||
message += "\n备注: " + note
|
||||
}
|
||||
|
||||
overrideBotToken := strings.TrimSpace(os.Getenv("TG_BOT_TOKEN"))
|
||||
overrideChatID := strings.TrimSpace(os.Getenv("TG_CHAT_ID"))
|
||||
if overrideBotToken != "" && overrideChatID != "" {
|
||||
if chatID, err := strconv.ParseInt(overrideChatID, 10, 64); err == nil && chatID != 0 {
|
||||
bot := l.svcCtx.TelegramBot
|
||||
if bot == nil || strings.TrimSpace(l.svcCtx.Config.Telegram.BotToken) != overrideBotToken {
|
||||
overrideBot, newErr := tgbotapi.NewBotAPI(overrideBotToken)
|
||||
if newErr == nil {
|
||||
bot = overrideBot
|
||||
} else {
|
||||
l.Errorw("初始化 TG 覆盖 Bot 失败", logger.Field("error", newErr.Error()))
|
||||
}
|
||||
}
|
||||
if bot != nil {
|
||||
msg := tgbotapi.NewMessage(chatID, message)
|
||||
if _, sendErr := bot.Send(msg); sendErr != nil {
|
||||
l.Errorw("发送 IAP TG 覆盖通道消息失败", logger.Field("error", sendErr.Error()))
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if l.svcCtx.TelegramBot == nil || !l.svcCtx.Config.Telegram.EnableNotify {
|
||||
return
|
||||
}
|
||||
|
||||
if groupChatID, err := strconv.ParseInt(strings.TrimSpace(l.svcCtx.Config.Telegram.GroupChatID), 10, 64); err == nil && groupChatID != 0 {
|
||||
msg := tgbotapi.NewMessage(groupChatID, message)
|
||||
if _, sendErr := l.svcCtx.TelegramBot.Send(msg); sendErr != nil {
|
||||
l.Errorw("发送 IAP TG 群消息失败", logger.Field("error", sendErr.Error()))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
admins, err := l.svcCtx.UserModel.QueryAdminUsers(l.ctx)
|
||||
if err != nil {
|
||||
l.Errorw("查询管理员失败(IAP TG日志)", logger.Field("error", err.Error()))
|
||||
return
|
||||
}
|
||||
for _, admin := range admins {
|
||||
if telegramID, ok := findTelegramAuth(admin); ok {
|
||||
msg := tgbotapi.NewMessage(telegramID, message)
|
||||
if _, sendErr := l.svcCtx.TelegramBot.Send(msg); sendErr != nil {
|
||||
l.Errorw("发送 IAP TG 管理员消息失败", logger.Field("error", sendErr.Error()))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func findTelegramAuth(u *user.User) (int64, bool) {
|
||||
if u == nil {
|
||||
return 0, false
|
||||
}
|
||||
for _, item := range u.AuthMethods {
|
||||
if item.AuthType == "telegram" {
|
||||
if telegramID, err := strconv.ParseInt(item.AuthIdentifier, 10, 64); err == nil {
|
||||
return telegramID, true
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0, false
|
||||
}
|
||||
|
||||
@ -111,6 +111,26 @@ func (l *PurchaseLogic) Purchase(req *types.PurchaseOrderRequest) (resp *types.P
|
||||
}
|
||||
}
|
||||
|
||||
// 单订阅模式下,若已有同套餐 pending 订单,直接返回,防止重复创建
|
||||
if l.svcCtx.Config.Subscribe.SingleModel && orderType == 1 {
|
||||
var existPending order.Order
|
||||
if e := l.svcCtx.DB.WithContext(l.ctx).
|
||||
Model(&order.Order{}).
|
||||
Where("user_id = ? AND subscribe_id = ? AND status = 1", u.Id, targetSubscribeID).
|
||||
Order("id DESC").
|
||||
First(&existPending).Error; e == nil && existPending.Id > 0 {
|
||||
l.Infow("[Purchase] single mode pending order exists, returning existing",
|
||||
logger.Field("user_id", u.Id),
|
||||
logger.Field("order_no", existPending.OrderNo),
|
||||
logger.Field("subscribe_id", targetSubscribeID),
|
||||
)
|
||||
return &types.PurchaseOrderResponse{
|
||||
OrderNo: existPending.OrderNo,
|
||||
AppAccountToken: existPending.AppAccountToken,
|
||||
}, nil
|
||||
}
|
||||
}
|
||||
|
||||
// find subscribe plan
|
||||
sub, err := l.svcCtx.SubscribeModel.FindOne(l.ctx, targetSubscribeID)
|
||||
|
||||
|
||||
@ -67,7 +67,7 @@ func (m *defaultUserModel) FindSingleModeAnchorSubscribe(ctx context.Context, us
|
||||
var data Subscribe
|
||||
err := m.QueryNoCacheCtx(ctx, &data, func(conn *gorm.DB, _ interface{}) error {
|
||||
return conn.Model(&Subscribe{}).
|
||||
Where("user_id = ? AND order_id > 0 AND token != '' AND `status` IN ?", userId, []int64{0, 1, 2, 3, 5}).
|
||||
Where("user_id = ? AND token != '' AND (order_id > 0 OR token LIKE 'iap:%') AND `status` IN ?", userId, []int64{0, 1, 2, 3, 5}).
|
||||
Order("expire_time DESC").
|
||||
Order("updated_at DESC").
|
||||
Order("id DESC").
|
||||
|
||||
@ -7,7 +7,6 @@ import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/perfect-panel/server/internal/logic/admin/group"
|
||||
@ -15,10 +14,8 @@ import (
|
||||
"github.com/perfect-panel/server/pkg/constant"
|
||||
"github.com/perfect-panel/server/pkg/logger"
|
||||
|
||||
tgbotapi "github.com/go-telegram-bot-api/telegram-bot-api/v5"
|
||||
"github.com/google/uuid"
|
||||
"github.com/hibiken/asynq"
|
||||
"github.com/perfect-panel/server/internal/logic/telegram"
|
||||
"github.com/perfect-panel/server/internal/model/order"
|
||||
internaltypes "github.com/perfect-panel/server/internal/types"
|
||||
"github.com/perfect-panel/server/internal/model/redemption"
|
||||
@ -333,9 +330,6 @@ func (l *ActivateOrderLogic) NewPurchase(ctx context.Context, orderInfo *order.O
|
||||
// Clear cache
|
||||
l.clearServerCache(ctx, sub)
|
||||
|
||||
// Send notifications
|
||||
l.sendNotifications(ctx, orderInfo, userInfo, sub, userSub, telegram.PurchaseNotify)
|
||||
|
||||
logger.WithContext(ctx).Info("Insert user subscribe success")
|
||||
return nil
|
||||
}
|
||||
@ -889,9 +883,6 @@ func (l *ActivateOrderLogic) Renewal(ctx context.Context, orderInfo *order.Order
|
||||
// Handle commission
|
||||
go l.handleCommission(context.Background(), userInfo, orderInfo)
|
||||
|
||||
// Send notifications
|
||||
l.sendNotifications(ctx, orderInfo, userInfo, sub, userSub, telegram.RenewalNotify)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -1041,9 +1032,6 @@ func (l *ActivateOrderLogic) ResetTraffic(ctx context.Context, orderInfo *order.
|
||||
logger.WithContext(ctx).Error("[Order Queue]Insert reset subscribe log failed", logger.Field("error", err.Error()))
|
||||
}
|
||||
|
||||
// Send notifications
|
||||
l.sendNotifications(ctx, orderInfo, userInfo, sub, userSub, telegram.ResetTrafficNotify)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -1108,140 +1096,9 @@ func (l *ActivateOrderLogic) Recharge(ctx context.Context, orderInfo *order.Orde
|
||||
return err
|
||||
}
|
||||
|
||||
// Send notifications
|
||||
l.sendRechargeNotifications(ctx, orderInfo, userInfo)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// sendNotifications sends both user and admin notifications for order completion
|
||||
func (l *ActivateOrderLogic) sendNotifications(ctx context.Context, orderInfo *order.Order, userInfo *user.User, sub *subscribe.Subscribe, userSub *user.Subscribe, notifyType string) {
|
||||
// Send user notification
|
||||
if telegramId, ok := findTelegram(userInfo); ok {
|
||||
templateData := l.buildUserNotificationData(orderInfo, sub, userSub)
|
||||
if text, err := tool.RenderTemplateToString(notifyType, templateData); err == nil {
|
||||
l.sendUserNotifyWithTelegram(telegramId, text)
|
||||
}
|
||||
}
|
||||
|
||||
// Send admin notification
|
||||
adminData := l.buildAdminNotificationData(orderInfo, sub)
|
||||
if text, err := tool.RenderTemplateToString(telegram.AdminOrderNotify, adminData); err == nil {
|
||||
l.sendAdminNotifyWithTelegram(ctx, text)
|
||||
}
|
||||
}
|
||||
|
||||
// sendRechargeNotifications sends specific notifications for balance recharge orders
|
||||
func (l *ActivateOrderLogic) sendRechargeNotifications(ctx context.Context, orderInfo *order.Order, userInfo *user.User) {
|
||||
// Send user notification
|
||||
if telegramId, ok := findTelegram(userInfo); ok {
|
||||
templateData := map[string]string{
|
||||
"OrderAmount": fmt.Sprintf("%.2f", float64(orderInfo.Price)/100),
|
||||
"PaymentMethod": orderInfo.Method,
|
||||
"Time": orderInfo.CreatedAt.Format("2006-01-02 15:04:05"),
|
||||
"Balance": fmt.Sprintf("%.2f", float64(userInfo.Balance)/100),
|
||||
}
|
||||
if text, err := tool.RenderTemplateToString(telegram.RechargeNotify, templateData); err == nil {
|
||||
l.sendUserNotifyWithTelegram(telegramId, text)
|
||||
}
|
||||
}
|
||||
|
||||
// Send admin notification
|
||||
adminData := map[string]string{
|
||||
"OrderNo": orderInfo.OrderNo,
|
||||
"TradeNo": orderInfo.TradeNo,
|
||||
"OrderAmount": fmt.Sprintf("%.2f", float64(orderInfo.Price)/100),
|
||||
"SubscribeName": "余额充值",
|
||||
"OrderStatus": "已支付",
|
||||
"OrderTime": orderInfo.CreatedAt.Format("2006-01-02 15:04:05"),
|
||||
"PaymentMethod": orderInfo.Method,
|
||||
}
|
||||
if text, err := tool.RenderTemplateToString(telegram.AdminOrderNotify, adminData); err == nil {
|
||||
l.sendAdminNotifyWithTelegram(ctx, text)
|
||||
}
|
||||
}
|
||||
|
||||
// buildUserNotificationData creates template data for user notifications
|
||||
func (l *ActivateOrderLogic) buildUserNotificationData(orderInfo *order.Order, sub *subscribe.Subscribe, userSub *user.Subscribe) map[string]string {
|
||||
data := map[string]string{
|
||||
"OrderNo": orderInfo.OrderNo,
|
||||
"SubscribeName": sub.Name,
|
||||
"OrderAmount": fmt.Sprintf("%.2f", float64(orderInfo.Price)/100),
|
||||
}
|
||||
|
||||
if userSub != nil {
|
||||
data["ExpireTime"] = userSub.ExpireTime.Format("2006-01-02 15:04:05")
|
||||
data["ResetTime"] = time.Now().Format("2006-01-02 15:04:05")
|
||||
}
|
||||
|
||||
return data
|
||||
}
|
||||
|
||||
// buildAdminNotificationData creates template data for admin notifications
|
||||
func (l *ActivateOrderLogic) buildAdminNotificationData(orderInfo *order.Order, sub *subscribe.Subscribe) map[string]string {
|
||||
subscribeName := sub.Name
|
||||
if orderInfo.Type == OrderTypeResetTraffic {
|
||||
subscribeName = "流量重置"
|
||||
}
|
||||
|
||||
return map[string]string{
|
||||
"OrderNo": orderInfo.OrderNo,
|
||||
"TradeNo": orderInfo.TradeNo,
|
||||
"SubscribeName": subscribeName,
|
||||
"OrderAmount": fmt.Sprintf("%.2f", float64(orderInfo.Price)/100),
|
||||
"OrderStatus": "已支付",
|
||||
"OrderTime": orderInfo.CreatedAt.Format("2006-01-02 15:04:05"),
|
||||
"PaymentMethod": orderInfo.Method,
|
||||
}
|
||||
}
|
||||
|
||||
// sendUserNotifyWithTelegram sends a notification message to a user via Telegram
|
||||
func (l *ActivateOrderLogic) sendUserNotifyWithTelegram(chatId int64, text string) {
|
||||
if l.svc.TelegramBot == nil {
|
||||
return
|
||||
}
|
||||
msg := tgbotapi.NewMessage(chatId, text)
|
||||
msg.ParseMode = "markdown"
|
||||
if _, err := l.svc.TelegramBot.Send(msg); err != nil {
|
||||
logger.Error("Send telegram user message failed", logger.Field("error", err.Error()))
|
||||
}
|
||||
}
|
||||
|
||||
// sendAdminNotifyWithTelegram sends a notification message to all admin users via Telegram
|
||||
func (l *ActivateOrderLogic) sendAdminNotifyWithTelegram(ctx context.Context, text string) {
|
||||
if l.svc.TelegramBot == nil {
|
||||
return
|
||||
}
|
||||
admins, err := l.svc.UserModel.QueryAdminUsers(ctx)
|
||||
if err != nil {
|
||||
logger.WithContext(ctx).Error("Query admin users failed", logger.Field("error", err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
for _, admin := range admins {
|
||||
if telegramId, ok := findTelegram(admin); ok {
|
||||
msg := tgbotapi.NewMessage(telegramId, text)
|
||||
msg.ParseMode = "markdown"
|
||||
if _, err := l.svc.TelegramBot.Send(msg); err != nil {
|
||||
logger.WithContext(ctx).Error("Send telegram admin message failed", logger.Field("error", err.Error()))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// findTelegram extracts Telegram chat ID from user authentication methods.
|
||||
// Returns the chat ID and a boolean indicating if Telegram auth was found.
|
||||
func findTelegram(u *user.User) (int64, bool) {
|
||||
for _, item := range u.AuthMethods {
|
||||
if item.AuthType == "telegram" {
|
||||
if telegramId, err := strconv.ParseInt(item.AuthIdentifier, 10, 64); err == nil {
|
||||
return telegramId, true
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0, false
|
||||
}
|
||||
|
||||
// RedemptionActivate handles redemption code activation including subscription creation,
|
||||
// redemption record creation, used count update, cache clearing, and notifications
|
||||
func (l *ActivateOrderLogic) RedemptionActivate(ctx context.Context, orderInfo *order.Order) error {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user