125 lines
5.0 KiB
PHP
125 lines
5.0 KiB
PHP
<?php
|
|
|
|
namespace App\Console\Commands;
|
|
|
|
use App\Models\Client;
|
|
use App\Models\ClientInvoicePaymentItem;
|
|
use App\Services\GoogleAdsSpendService;
|
|
use Illuminate\Console\Command;
|
|
use Illuminate\Database\Eloquent\Builder;
|
|
use Illuminate\Support\Facades\Log;
|
|
|
|
class UpdateCurrentClientInvoicePaymentItemSpending extends Command
|
|
{
|
|
protected $signature = 'customer:update-current-invoice-item-spending
|
|
{--dry-run : Calculate without saving changes}';
|
|
|
|
protected $description = 'Update spending on billing type 1 invoice payment items ending today or later.';
|
|
|
|
public function handle(GoogleAdsSpendService $spendService): int
|
|
{
|
|
$dryRun = (bool) $this->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);
|
|
}
|
|
}
|