diff --git a/internal/web/service/client_bulk.go b/internal/web/service/client_bulk.go index 6a18dbf19..c0cc32eec 100644 --- a/internal/web/service/client_bulk.go +++ b/internal/web/service/client_bulk.go @@ -409,6 +409,7 @@ func (s *ClientService) BulkAdjust(inboundSvc *InboundService, emails []string, needRestart := false flowHonored := map[string]bool{} flowIneligible := map[string]bool{} + execFailed := map[string]bool{} for inboundId, ibEmails := range emailsByInbound { ibRes := s.bulkAdjustInboundClients(inboundSvc, inboundId, ibEmails, plan, flow) if ibRes.needRestart { @@ -421,6 +422,7 @@ func (s *ClientService) BulkAdjust(inboundSvc *InboundService, emails []string, flowIneligible[email] = true } for email, reason := range ibRes.perEmailSkipped { + execFailed[email] = true if _, already := skippedReasons[email]; !already { skippedReasons[email] = reason } @@ -450,7 +452,7 @@ func (s *ClientService) BulkAdjust(inboundSvc *InboundService, emails []string, adjusted := map[string]struct{}{} for email, entry := range plan { - if _, skipped := skippedReasons[email]; skipped { + if execFailed[email] { continue } updates := map[string]any{} diff --git a/internal/web/service/client_bulk_reenable_test.go b/internal/web/service/client_bulk_reenable_test.go index 693bc0f4f..e753616dd 100644 --- a/internal/web/service/client_bulk_reenable_test.go +++ b/internal/web/service/client_bulk_reenable_test.go @@ -189,6 +189,27 @@ func TestBulkAdjust_QuotaReductionBelowZeroSkipsInsteadOfUnlimited(t *testing.T) } } +func TestBulkAdjust_AppliedFieldReachesTrafficRowDespiteOtherFieldSkip(t *testing.T) { + setupBulkDB(t) + svc := &ClientService{} + inboundSvc := &InboundService{} + + email := "mix2@x" + c := model.Client{Email: email, ID: "11111111-1111-1111-1111-111111111111", SubID: email, Enable: true, TotalGB: 100, ExpiryTime: 0} + ib := mkInbound(t, 52021, model.VLESS, clientsSettings(t, []model.Client{c})) + if err := svc.SyncInbound(nil, ib.Id, []model.Client{c}); err != nil { + t.Fatalf("seed linkage: %v", err) + } + mkTraffic(t, ib.Id, email, 0, 0, 100, 0, true) + + if _, _, err := svc.BulkAdjust(inboundSvc, []string{email}, 30, 50, ""); err != nil { + t.Fatalf("BulkAdjust: %v", err) + } + if got := trafficOf(t, email).Total; got != 150 { + t.Fatalf("client_traffics.total = %d, want 150: the applied quota adjustment must reach the enforcement row even though the unlimited-expiry field was skipped", got) + } +} + func TestBulkAdjust_OverQuota_DaysOnly_StaysDisabled(t *testing.T) { setupBulkDB(t) svc := &ClientService{}