mirror of
https://github.com/NNTmux/newznab-tmux.git
synced 2026-08-28 17:01:16 +00:00
Add payments summary
This commit is contained in:
@@ -37,6 +37,8 @@ class AdminPaymentController extends BasePageController
|
|||||||
'email' => $request->string('email')->trim()->value(),
|
'email' => $request->string('email')->trim()->value(),
|
||||||
'payment_status' => $request->string('payment_status')->trim()->value(),
|
'payment_status' => $request->string('payment_status')->trim()->value(),
|
||||||
'invoice_status' => $request->string('invoice_status')->trim()->value(),
|
'invoice_status' => $request->string('invoice_status')->trim()->value(),
|
||||||
|
'start_date' => $request->string('start_date')->trim()->value(),
|
||||||
|
'end_date' => $request->string('end_date')->trim()->value(),
|
||||||
];
|
];
|
||||||
|
|
||||||
$sort = $request->string('sort')->value();
|
$sort = $request->string('sort')->value();
|
||||||
@@ -52,11 +54,31 @@ class AdminPaymentController extends BasePageController
|
|||||||
->paginate((int) config('nntmux.items_per_page'))
|
->paginate((int) config('nntmux.items_per_page'))
|
||||||
->withQueryString();
|
->withQueryString();
|
||||||
|
|
||||||
|
$summary = Payment::query()
|
||||||
|
->filter($filters)
|
||||||
|
->selectRaw("
|
||||||
|
COALESCE(NULLIF(payment_method, ''), 'Unknown') AS method,
|
||||||
|
COUNT(*) AS tx_count,
|
||||||
|
COALESCE(SUM(CAST(NULLIF(invoice_amount, '') AS DECIMAL(20,8))), 0) AS invoice_total,
|
||||||
|
COALESCE(SUM(CAST(NULLIF(payment_value, '') AS DECIMAL(20,8))), 0) AS value_total
|
||||||
|
")
|
||||||
|
->groupBy('method')
|
||||||
|
->orderBy('method')
|
||||||
|
->get();
|
||||||
|
|
||||||
|
$summaryTotals = [
|
||||||
|
'tx_count' => (int) $summary->sum('tx_count'),
|
||||||
|
'invoice_total' => (float) $summary->sum(fn ($r) => (float) $r->invoice_total),
|
||||||
|
'value_total' => (float) $summary->sum(fn ($r) => (float) $r->value_total),
|
||||||
|
];
|
||||||
|
|
||||||
$paymentStatuses = BtcPaymentController::paymentStatusesForAdminFilter();
|
$paymentStatuses = BtcPaymentController::paymentStatusesForAdminFilter();
|
||||||
$invoiceStatuses = BtcPaymentController::invoiceStatusesForAdminFilter();
|
$invoiceStatuses = BtcPaymentController::invoiceStatusesForAdminFilter();
|
||||||
|
|
||||||
$this->viewData = array_merge($this->viewData, [
|
$this->viewData = array_merge($this->viewData, [
|
||||||
'payments' => $payments,
|
'payments' => $payments,
|
||||||
|
'summary' => $summary,
|
||||||
|
'summaryTotals' => $summaryTotals,
|
||||||
'filters' => $filters,
|
'filters' => $filters,
|
||||||
'sort' => $sort,
|
'sort' => $sort,
|
||||||
'order' => $order,
|
'order' => $order,
|
||||||
|
|||||||
+18
-1
@@ -7,6 +7,7 @@ namespace App\Models;
|
|||||||
use Illuminate\Database\Eloquent\Builder;
|
use Illuminate\Database\Eloquent\Builder;
|
||||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
use Illuminate\Database\Eloquent\Model;
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
use Illuminate\Support\Carbon;
|
||||||
|
|
||||||
class Payment extends Model
|
class Payment extends Model
|
||||||
{
|
{
|
||||||
@@ -24,7 +25,7 @@ class Payment extends Model
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @param Builder<Payment> $query
|
* @param Builder<Payment> $query
|
||||||
* @param array{username?: string, email?: string, payment_status?: string, invoice_status?: string} $filters
|
* @param array{username?: string, email?: string, payment_status?: string, invoice_status?: string, start_date?: string, end_date?: string} $filters
|
||||||
* @return Builder<Payment>
|
* @return Builder<Payment>
|
||||||
*/
|
*/
|
||||||
public function scopeFilter(Builder $query, array $filters): Builder
|
public function scopeFilter(Builder $query, array $filters): Builder
|
||||||
@@ -52,6 +53,22 @@ class Payment extends Model
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (! empty($filters['start_date'])) {
|
||||||
|
try {
|
||||||
|
$query->where('created_at', '>=', Carbon::parse($filters['start_date'])->startOfDay());
|
||||||
|
} catch (\Exception) {
|
||||||
|
// ignore invalid date input
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (! empty($filters['end_date'])) {
|
||||||
|
try {
|
||||||
|
$query->where('created_at', '<=', Carbon::parse($filters['end_date'])->endOfDay());
|
||||||
|
} catch (\Exception) {
|
||||||
|
// ignore invalid date input
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return $query;
|
return $query;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -47,6 +47,16 @@
|
|||||||
@endforeach
|
@endforeach
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
<div>
|
||||||
|
<label for="filter-start-date" class="mb-1 block text-sm font-medium text-gray-700 dark:text-gray-300">From date</label>
|
||||||
|
<input type="date" name="start_date" id="filter-start-date" value="{{ $filters['start_date'] }}"
|
||||||
|
class="w-full rounded-md border border-gray-300 bg-white px-3 py-2 text-sm text-gray-900 focus:border-blue-500 focus:ring-blue-500 dark:border-gray-600 dark:bg-gray-800 dark:text-gray-100 dark:focus:border-blue-400 dark:focus:ring-blue-400">
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label for="filter-end-date" class="mb-1 block text-sm font-medium text-gray-700 dark:text-gray-300">To date</label>
|
||||||
|
<input type="date" name="end_date" id="filter-end-date" value="{{ $filters['end_date'] }}"
|
||||||
|
class="w-full rounded-md border border-gray-300 bg-white px-3 py-2 text-sm text-gray-900 focus:border-blue-500 focus:ring-blue-500 dark:border-gray-600 dark:bg-gray-800 dark:text-gray-100 dark:focus:border-blue-400 dark:focus:ring-blue-400">
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex flex-wrap gap-2">
|
<div class="flex flex-wrap gap-2">
|
||||||
<input type="hidden" name="sort" value="{{ $sort }}">
|
<input type="hidden" name="sort" value="{{ $sort }}">
|
||||||
@@ -61,6 +71,53 @@
|
|||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@if($summary->isNotEmpty())
|
||||||
|
<div class="border-b border-gray-200 px-6 py-4 dark:border-gray-700">
|
||||||
|
<h3 class="mb-3 flex items-center text-sm font-semibold text-gray-700 dark:text-gray-200">
|
||||||
|
<i class="fas fa-chart-pie mr-2 text-blue-600 dark:text-blue-400"></i>
|
||||||
|
Summary by payment method
|
||||||
|
@if(!empty($filters['start_date']) || !empty($filters['end_date']))
|
||||||
|
<span class="ml-2 text-xs font-normal text-gray-500 dark:text-gray-400">
|
||||||
|
({{ $filters['start_date'] ?: '…' }} → {{ $filters['end_date'] ?: '…' }})
|
||||||
|
</span>
|
||||||
|
@endif
|
||||||
|
</h3>
|
||||||
|
<div class="overflow-x-auto">
|
||||||
|
<table class="min-w-full text-sm">
|
||||||
|
<thead class="text-gray-500 dark:text-gray-400">
|
||||||
|
<tr>
|
||||||
|
<th class="py-1 pr-4 text-left font-medium">Method</th>
|
||||||
|
<th class="py-1 pr-4 text-right font-medium">Transactions</th>
|
||||||
|
<th class="py-1 pr-4 text-right font-medium">Invoice amount total</th>
|
||||||
|
<th class="py-1 text-right font-medium">Payment value total</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
@foreach($summary as $row)
|
||||||
|
<tr class="border-t border-gray-100 dark:border-gray-700">
|
||||||
|
<td class="py-1 pr-4 font-medium text-gray-900 dark:text-gray-100">{{ $row->method }}</td>
|
||||||
|
<td class="py-1 pr-4 text-right text-gray-700 dark:text-gray-300">{{ number_format((int) $row->tx_count) }}</td>
|
||||||
|
<td class="py-1 pr-4 text-right text-gray-700 dark:text-gray-300">{{ rtrim(rtrim(number_format((float) $row->invoice_total, 8, '.', ''), '0'), '.') ?: '0' }}</td>
|
||||||
|
<td class="py-1 text-right text-gray-700 dark:text-gray-300">{{ rtrim(rtrim(number_format((float) $row->value_total, 8, '.', ''), '0'), '.') ?: '0' }}</td>
|
||||||
|
</tr>
|
||||||
|
@endforeach
|
||||||
|
</tbody>
|
||||||
|
<tfoot class="border-t-2 border-gray-300 font-semibold dark:border-gray-600">
|
||||||
|
<tr>
|
||||||
|
<td class="py-1 pr-4 text-gray-900 dark:text-gray-100">Total</td>
|
||||||
|
<td class="py-1 pr-4 text-right text-gray-900 dark:text-gray-100">{{ number_format($summaryTotals['tx_count']) }}</td>
|
||||||
|
<td class="py-1 pr-4 text-right text-gray-900 dark:text-gray-100">{{ rtrim(rtrim(number_format($summaryTotals['invoice_total'], 8, '.', ''), '0'), '.') ?: '0' }}</td>
|
||||||
|
<td class="py-1 text-right text-gray-900 dark:text-gray-100">{{ rtrim(rtrim(number_format($summaryTotals['value_total'], 8, '.', ''), '0'), '.') ?: '0' }}</td>
|
||||||
|
</tr>
|
||||||
|
</tfoot>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
<p class="mt-2 text-xs text-gray-500 dark:text-gray-400">
|
||||||
|
Totals are summed across the currently filtered payments. Currency is implied by the payment method.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
@endif
|
||||||
|
|
||||||
@if($payments->count() > 0)
|
@if($payments->count() > 0)
|
||||||
<x-admin.data-table>
|
<x-admin.data-table>
|
||||||
<x-slot:head>
|
<x-slot:head>
|
||||||
|
|||||||
Reference in New Issue
Block a user