validate([ 'action' => 'required|in:cancel,retry-failed', 'uuids' => 'required|array|min:1|max:200', 'uuids.*' => 'string', ]); $campaigns = MailCampaign::whereIn('uuid', $data['uuids'])->get(); $message = $data['action'] === 'cancel' ? $this->cancelCampaigns($campaigns) : $this->retryFailedRecipients($campaigns); return response()->json(['error' => false, 'message' => $message]); } public function bulkDelete(Request $request): JsonResponse { $data = $request->validate([ 'uuids' => 'required|array|min:1|max:200', 'uuids.*' => 'string', ]); $deleted = MailCampaign::whereIn('uuid', $data['uuids']) ->whereIn('status', MailCampaign::FINISHED_STATUSES) ->delete(); $skipped = count($data['uuids']) - $deleted; return response()->json([ 'error' => false, 'message' => "Đã xoá {$deleted} chiến dịch." . ($skipped > 0 ? " Bỏ qua {$skipped} chiến dịch đang gửi (huỷ gửi trước khi xoá)." : ''), ]); } /** * @param Collection $campaigns */ private function cancelCampaigns(Collection $campaigns): string { $cancelled = MailCampaign::whereKey($campaigns->modelKeys()) ->whereIn('status', MailCampaign::ACTIVE_STATUSES) ->update(['status' => MailCampaign::STATUS_CANCELLED, 'completed_at' => now()]); return "Đã huỷ gửi {$cancelled} chiến dịch. Email đã gửi trước đó không bị thu hồi."; } /** * @param Collection $campaigns */ private function retryFailedRecipients(Collection $campaigns): string { $retried = 0; foreach ($campaigns->whereIn('status', ['completed', 'failed']) as $campaign) { DB::transaction(function () use ($campaign, &$retried) { $failedLogs = Mail::where('campaign_id', $campaign->id) ->where('status', array_search('failed', Mail::STATUS_MAP, true)) ->lockForUpdate() ->get(['id', 'to', 'customer_id', 'service_id']); if ($failedLogs->isEmpty()) { return; } Mail::whereKey($failedLogs->modelKeys())->delete(); $campaign->forceFill([ 'failed_count' => max(0, $campaign->failed_count - $failedLogs->count()), 'status' => 'sending', 'completed_at' => null, ])->save(); foreach ($failedLogs as $log) { SendMailCampaignRecipient::dispatch($campaign->id, $log->customer_id, $log->to, $log->service_id)->afterCommit(); } $retried += $failedLogs->count(); }); } return $retried > 0 ? "Đã đưa {$retried} email lỗi vào hàng đợi gửi lại." : 'Không có email lỗi nào để gửi lại (chỉ gửi lại chiến dịch đã kết thúc).'; } }