120 lines
4.7 KiB
PHP
120 lines
4.7 KiB
PHP
<?php
|
|
|
|
namespace App\Console\Commands;
|
|
|
|
use App\Models\ClientInvoicePayment;
|
|
use Illuminate\Console\Command;
|
|
use Illuminate\Database\Eloquent\Builder;
|
|
use Illuminate\Support\Facades\DB;
|
|
|
|
class RepairLinkedInvoicePaymentItems extends Command
|
|
{
|
|
protected $signature = 'customer:repair-linked-invoice-payment-items
|
|
{--invoice-id=* : Only repair these referenced linked invoice IDs}
|
|
{--dry-run : Show changes without saving them}';
|
|
|
|
protected $description = 'Move media item date ranges and spending to management items on invoices referenced by linked_invoice_id, then remove media items.';
|
|
|
|
public function handle(): int
|
|
{
|
|
$dryRun = (bool) $this->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;
|
|
}
|
|
}
|