(order orders.Order, plan plans.Plan, now time.Time)
| 194 | } |
| 195 | |
| 196 | func (d *WebhookDeps) renewExistingUser(order orders.Order, plan plans.Plan, now time.Time) error { |
| 197 | user, err := d.UserStore.GetUser(order.UserID) |
| 198 | if err != nil { |
| 199 | return fmt.Errorf("get user %s: %w", order.UserID, err) |
| 200 | } |
| 201 | |
| 202 | // 到期时间:未过期则从当前到期时间延长,已过期则从现在起算 |
| 203 | notExpired := user.ExpireAt != nil && user.ExpireAt.After(now) |
| 204 | base := now |
| 205 | if notExpired { |
| 206 | base = *user.ExpireAt |
| 207 | } |
| 208 | expireAt := base.Add(time.Duration(plan.DurationDays) * 24 * time.Hour) |
| 209 | user.ExpireAt = &expireAt |
| 210 | |
| 211 | // 流量:剩余量叠加到新套餐额度,清零计数器以保证 SyncUsage delta 正确 |
| 212 | user.PlanTrafficLimit = plan.TrafficLimit |
| 213 | if plan.TrafficLimit == 0 { |
| 214 | user.TrafficLimit = 0 // 新套餐无限流量 |
| 215 | } else { |
| 216 | remaining := user.TrafficLimit - user.UsedBytes |
| 217 | if remaining < 0 { |
| 218 | remaining = 0 |
| 219 | } |
| 220 | user.TrafficLimit = remaining + plan.TrafficLimit |
| 221 | } |
| 222 | user.UploadBytes = 0 |
| 223 | user.DownloadBytes = 0 |
| 224 | user.UsedBytes = 0 |
| 225 | user.RawUploadBytes = 0 |
| 226 | user.RawDownloadBytes = 0 |
| 227 | // 未过期续费时以旧 ExpireAt 为锚点,确保下次定时重置与套餐周期对齐 |
| 228 | if notExpired { |
| 229 | user.LastTrafficResetAt = user.ExpireAt |
| 230 | } else { |
| 231 | user.LastTrafficResetAt = &now |
| 232 | } |
| 233 | user.DataLimitResetStrategy = plan.DataLimitResetStrategy |
| 234 | user.CurrentPlanID = plan.ID |
| 235 | user.Status = users.StatusActive |
| 236 | |
| 237 | if _, err := d.UserStore.UpsertUser(user); err != nil { |
| 238 | return fmt.Errorf("update user %s: %w", user.ID, err) |
| 239 | } |
| 240 | if err := d.UserStore.ClearUserNodeDailyUsage(user.ID); err != nil { |
| 241 | log.Printf("payment: renew clear daily usage user %s: %v", user.ID, err) |
| 242 | } |
| 243 | |
| 244 | // 加入套餐绑定的用户组 |
| 245 | if plan.UserGroupIDs != "" { |
| 246 | gIDs := strings.Split(plan.UserGroupIDs, ",") |
| 247 | for i := range gIDs { |
| 248 | gIDs[i] = strings.TrimSpace(gIDs[i]) |
| 249 | } |
| 250 | if err := d.AddUserToGroups(user.ID, gIDs); err != nil { |
| 251 | log.Printf("payment: renew add user to groups: %v", err) |
| 252 | } |
| 253 | } |
no test coverage detected