option('dry-run'); $invoiceIds = collect($this->option('invoice-id')) ->filter(fn ($id) => is_numeric($id)) ->map(fn ($id) => (int) $id) ->values() ->all(); $merged = 0; $removed = 0; $skipped = 0; ClientInvoicePayment::query() ->with([ 'invoice:id,invoice_no,linked_invoice_id', 'items' => fn ($query) => $query->orderBy('id'), ]) ->whereIn('client_invoice_id', function ($query) use ($invoiceIds) { $query ->select('linked_invoice_id') ->distinct() ->from('client_invoices') ->whereNotNull('linked_invoice_id'); if ($invoiceIds !== []) { $query->whereIn('linked_invoice_id', $invoiceIds); } }) ->whereHas('items', fn (Builder $query) => $query->where('billing_item_types_id', 1)) ->orderBy('id') ->chunkById(100, function ($payments) use ($dryRun, &$merged, &$removed, &$skipped) { foreach ($payments as $payment) { $mediaItems = $payment->items->where('billing_item_types_id', 1)->values(); $managementItems = $payment->items->where('billing_item_types_id', 2)->values(); if ($managementItems->count() !== 1) { $skipped += $mediaItems->count(); $this->warn(sprintf( 'Skipping payment %d on invoice %s: expected 1 management item, found %d.', $payment->id, $payment->invoice?->invoice_no ?? $payment->client_invoice_id, $managementItems->count(), )); continue; } $managementItem = $managementItems->first(); $startDate = $mediaItems ->map(fn ($item) => $item->start_date?->toDateString()) ->filter() ->min(); $endDate = $mediaItems ->map(fn ($item) => $item->end_date?->toDateString()) ->filter() ->max(); $spending = (float) $managementItem->spending + $mediaItems->sum(fn ($item) => (float) $item->spending); $this->line(sprintf( '%s payment %d: %d media item%s -> management item %d (%s to %s, spending RM %.2f).', $dryRun ? 'Would merge' : 'Merging', $payment->id, $mediaItems->count(), $mediaItems->count() === 1 ? '' : 's', $managementItem->id, $startDate ?? 'null', $endDate ?? 'null', $spending, )); if (! $dryRun) { DB::transaction(function () use ($managementItem, $mediaItems, $startDate, $endDate, $spending) { $managementItem->forceFill([ 'start_date' => $startDate, 'end_date' => $endDate, 'spending' => $spending, ])->save(); $mediaItems->each->delete(); }); } $merged += $mediaItems->count(); $removed += $mediaItems->count(); } }); $this->info(sprintf( 'Done. %d media item%s merged into management, %d media item%s removed, %d skipped.', $merged, $merged === 1 ? '' : 's', $removed, $removed === 1 ? '' : 's', $skipped, )); return self::SUCCESS; } }