validate([ 'uuids' => 'required|array|min:1|max:200', 'uuids.*' => 'string|exists:customers,uuid', 'days' => 'nullable|integer|min:1|max:365', ]); $customerIds = Customer::whereIn('uuid', $data['uuids'])->pluck('id')->all(); $today = now()->startOfDay(); $rows = RenewalQuote::dueServices($customerIds, (int) ($data['days'] ?? 30)) ->map(function (Service $service) use ($today) { $quote = RenewalQuote::forService($service); return $quote ? [ ...$quote, 'customer_uuid' => $service->customer->uuid, 'customer_name' => $service->customer->fullname, 'customer_email' => $service->customer->email, 'days_left' => (int) $today->diffInDays($service->expires_at->copy()->startOfDay(), false), ] : null; }) ->filter() ->values(); return response()->json(['error' => false, 'data' => $rows]); } /** * @param array $selected * @return array */ private function renewalJobs(MailCampaign $campaign, array $selected): array { if (! RenewalCampaign::isRenewalTemplate($campaign)) { throw ValidationException::withMessages(['renewal_services' => 'Template đã chọn không phải mẫu nhắc gia hạn.']); } $services = Service::with('customer:id,email') ->whereIn('id', array_column($selected, 'service_id')) ->get(); return $services ->filter(fn (Service $service) => $service->customer && trim((string) $service->customer->email) !== '') ->map(fn (Service $service) => [ 'customer_id' => $service->customer->id, 'email' => trim($service->customer->email), 'service_id' => $service->id, ]) ->values() ->all(); } }