Some checks failed
Build docker and publish / build (20.15.1) (push) Has been cancelled
96 lines
2.6 KiB
Go
96 lines
2.6 KiB
Go
package user
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"strings"
|
|
"time"
|
|
|
|
"gorm.io/gorm"
|
|
)
|
|
|
|
// FindActiveSubscribesByUserIds Find active subscriptions for multiple users
|
|
func (m *customUserModel) FindActiveSubscribesByUserIds(ctx context.Context, userIds []int64) (map[int64]*UserStatusInfo, error) {
|
|
if len(userIds) == 0 {
|
|
return map[int64]*UserStatusInfo{}, nil
|
|
}
|
|
|
|
type Result struct {
|
|
UserId int64
|
|
Name string
|
|
Quantity int64
|
|
UpdatedAt *time.Time
|
|
}
|
|
var results []Result
|
|
|
|
// Query latest active subscription for each user
|
|
err := m.QueryNoCacheCtx(ctx, &results, func(conn *gorm.DB, v interface{}) error {
|
|
return conn.Table("user_subscribe us").
|
|
Select("us.user_id, subscribe.name, COALESCE(o.quantity, 1) AS quantity, us.updated_at").
|
|
Joins("LEFT JOIN subscribe ON us.subscribe_id = subscribe.id").
|
|
Joins("LEFT JOIN `order` o ON o.id = (SELECT MAX(o2.id) FROM `order` o2 WHERE o2.user_id = us.user_id AND o2.subscribe_id = us.subscribe_id AND o2.status IN (2, 5))").
|
|
Where("us.user_id IN ? AND us.status IN (0, 1) AND us.expire_time > ?", userIds, time.Now()).
|
|
Order("us.created_at ASC, us.id ASC"). // Ascending so we can overwrite in map to get the latest
|
|
Scan(v).Error
|
|
})
|
|
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
userMap := make(map[int64]*UserStatusInfo)
|
|
packageTotals := make(map[int64]map[string]int64)
|
|
packageOrder := make(map[int64][]string)
|
|
for _, r := range results {
|
|
name := strings.TrimSpace(r.Name)
|
|
if name == "" {
|
|
name = "Unknown"
|
|
}
|
|
|
|
quantity := r.Quantity
|
|
if quantity <= 0 {
|
|
quantity = 1
|
|
}
|
|
|
|
if _, ok := packageTotals[r.UserId]; !ok {
|
|
packageTotals[r.UserId] = make(map[string]int64)
|
|
}
|
|
if _, exists := packageTotals[r.UserId][name]; !exists {
|
|
packageOrder[r.UserId] = append(packageOrder[r.UserId], name)
|
|
}
|
|
packageTotals[r.UserId][name] += quantity
|
|
|
|
info, ok := userMap[r.UserId]
|
|
if !ok {
|
|
info = &UserStatusInfo{}
|
|
userMap[r.UserId] = info
|
|
}
|
|
info.MemberStatus = formatPackageDisplay(name, quantity)
|
|
if r.UpdatedAt != nil && (info.LastTrafficAt == nil || r.UpdatedAt.After(*info.LastTrafficAt)) {
|
|
info.LastTrafficAt = r.UpdatedAt
|
|
}
|
|
}
|
|
|
|
for userID, info := range userMap {
|
|
orderedNames := packageOrder[userID]
|
|
if len(orderedNames) == 0 {
|
|
continue
|
|
}
|
|
|
|
parts := make([]string, 0, len(orderedNames))
|
|
for _, name := range orderedNames {
|
|
parts = append(parts, formatPackageDisplay(name, packageTotals[userID][name]))
|
|
}
|
|
info.PurchasedPackage = strings.Join(parts, ", ")
|
|
}
|
|
|
|
return userMap, nil
|
|
}
|
|
|
|
func formatPackageDisplay(name string, quantity int64) string {
|
|
if quantity <= 1 {
|
|
return name
|
|
}
|
|
return fmt.Sprintf("%s*%d", name, quantity)
|
|
}
|