option('dry-run'); $today = today()->toDateString(); $updated = 0; $skipped = 0; $failed = 0; Client::query() ->whereHas('invoices.payments.items', fn (Builder $query) => $this->eligibleItems($query, $today)) ->orderBy('id') ->chunkById(50, function ($clients) use ( $spendService, $dryRun, $today, &$updated, &$skipped, &$failed, ) { foreach ($clients as $client) { if (empty($client->customer_id)) { $skipped++; $this->warn("Skipping client {$client->id}: missing customer ID."); continue; } ClientInvoicePaymentItem::query() ->whereHas( 'payment.invoice', fn (Builder $query) => $query->where('client_id', $client->id), ) ->where(fn (Builder $query) => $this->eligibleItems($query, $today)) ->orderBy('id') ->chunkById(50, function ($items) use ( $client, $spendService, $dryRun, $today, &$updated, &$skipped, &$failed, ) { foreach ($items as $item) { $startDate = $item->start_date->format('Y-m-d'); $endDate = $today; if ($endDate < $startDate) { $skipped++; $this->warn("Skipping item {$item->id}: today is before start date."); continue; } try { $spending = $spendService->forDateRange( $client->customer_id, $startDate, $endDate, ); if (! $dryRun) { $item->forceFill(['spending' => $spending])->save(); } $updated++; $this->line(sprintf( '%s client %d item %d: RM %.2f (%s to %s)', $dryRun ? 'Calculated' : 'Updated', $client->id, $item->id, $spending, $startDate, $endDate, )); } catch (\Throwable $exception) { $failed++; Log::error('Unable to update current invoice payment item spending.', [ 'client_id' => $client->id, 'client_invoice_payment_item_id' => $item->id, 'customer_id' => $client->customer_id, 'start_date' => $startDate, 'end_date' => $endDate, 'message' => $exception->getMessage(), ]); $this->error("Failed item {$item->id}: {$exception->getMessage()}"); } } }); } }); $this->info("Done. {$updated} calculated, {$skipped} skipped, {$failed} failed."); return $failed > 0 ? self::FAILURE : self::SUCCESS; } private function eligibleItems(Builder $query, string $today): Builder { return $query ->where('billing_item_types_id', 1) ->whereNotNull('start_date') ->whereDate('end_date', '>=', $today); } }