Files
portal-api/app/Support/Billing/InvoicePaymentHistory.php
T

84 lines
3.1 KiB
PHP

<?php
namespace App\Support\Billing;
use App\Models\Invoice;
use App\Models\Transaction;
use Illuminate\Support\Collection;
use Illuminate\Support\Str;
class InvoicePaymentHistory
{
private const SERVICE_CREATION_PREFIX = 'SVC-';
/**
* @param Collection<int, Invoice> $invoices
* @return array<int, list<array<string, mixed>>> keyed by invoice id, oldest payment first
*/
public static function forInvoices(Collection $invoices): array
{
$history = $invoices->mapWithKeys(fn (Invoice $invoice) => [$invoice->id => []])->all();
if ($invoices->isEmpty()) {
return $history;
}
$invoiceByOrderNum = $invoices
->filter(fn (Invoice $invoice) => (int) $invoice->invoice_type === 1 && $invoice->order?->order_num)
->keyBy(fn (Invoice $invoice) => $invoice->order->order_num);
$transactions = Transaction::with('user')
->whereIn('customer_id', $invoices->pluck('customer_id')->unique())
->where(function ($query) use ($invoices, $invoiceByOrderNum) {
foreach ($invoices as $invoice) {
$query->orWhere('trans', $invoice->invoice_number)
->orWhere('trans', 'like', $invoice->invoice_number . '-%');
}
if ($invoiceByOrderNum->isNotEmpty()) {
$query->orWhere(fn ($creation) => $creation
->whereIn('trans', $invoiceByOrderNum->keys())
->where('public_code', 'like', self::SERVICE_CREATION_PREFIX . '%'));
}
})
->oldest('id')
->get();
$invoiceByNumber = $invoices->keyBy('invoice_number');
foreach ($transactions as $transaction) {
$invoice = self::matchInvoice($transaction, $invoiceByNumber, $invoiceByOrderNum);
if ($invoice) {
$history[$invoice->id][] = self::present($transaction);
}
}
return $history;
}
private static function matchInvoice(Transaction $transaction, Collection $invoiceByNumber, Collection $invoiceByOrderNum): ?Invoice
{
if (Str::startsWith((string) $transaction->public_code, self::SERVICE_CREATION_PREFIX)) {
return $invoiceByOrderNum->get($transaction->trans);
}
$number = preg_replace('/-(P\d+|REFUND)$/', '', (string) $transaction->trans);
return $invoiceByNumber->get($number);
}
private static function present(Transaction $transaction): array
{
$isRefund = Str::endsWith((string) $transaction->trans, '-REFUND');
return [
'id' => $transaction->id,
'public_code' => $transaction->public_code,
'kind' => $isRefund ? 'refund' : 'payment',
'amount' => abs((int) $transaction->amount),
'type' => $transaction->type,
'note' => $transaction->note,
'recorded_by' => $transaction->user?->fullname ?: $transaction->user?->username,
'created_at' => $transaction->created_at,
];
}
}