Files
exchange-2.0/app/Http/Controllers/Reports/UnfinishedPaymentOrders.php
T
2025-07-25 19:22:19 +08:00

156 lines
5.0 KiB
PHP

<?php
namespace App\Http\Controllers\Reports;
use App\Classes\Modules\Bookings\Services\CalculatesBookingPaidAmount;
use App\Http\Controllers\Controller;
use App\Models\Booking;
use Illuminate\Http\Request;
use Carbon\Carbon;
class UnfinishedPaymentOrders extends Controller
{
public function execute(Request $request)
{
$page = (int) $request->input('page', 1);
$perPage = 2500;
$offset = ($page - 1) * $perPage;
$cutOffDate = $request->cut_off_date ? Carbon::parse($request->cut_off_date) : null;
$baseQuery = Booking::with('company')
->when($cutOffDate, fn($q) => $q->where('created_at', '<=', $cutOffDate))
->orderByDesc('id');
$total = $baseQuery->count();
$bookings = $baseQuery->offset($offset)->limit($perPage)->get();
$calculator = new CalculatesBookingPaidAmount();
$filtered = $bookings->filter(function ($b) use ($calculator, $cutOffDate) {
$paid = $calculator->executeUntilDate($b, $cutOffDate);
$outstanding = $b->fix_amount - $paid;
return $paid > 0 && $outstanding > 0;
});
return response()->json([
'success' => true,
'current_page' => $page,
'next_page' => ($offset + $perPage < $total) ? $page + 1 : null,
'count' => $filtered->count(),
'data' => $filtered->map(function ($b) use ($calculator, $cutOffDate) {
$paid = $calculator->executeUntilDate($b, $cutOffDate);
return [
'id' => $b->id,
'order_ref' => $b->marking ?? $b->id,
'booking_amount' => number_format($b->fix_amount, 2),
'paid_amount' => number_format($paid, 2),
'outstanding_amount' => number_format($b->fix_amount - $paid, 2),
'customer' => optional($b->company)->reference,
'created_at' => $b->created_at->toDateTimeString(),
];
})->values(),
]);
}
public function loadView(Request $request)
{
$cutOffDateString = $request->cut_off_date ?? '';
$cutOffDateParsed = $cutOffDateString ? Carbon::parse($cutOffDateString)->toDateString() : '-';
echo <<<HTML
<p>Cut Off Date: {$cutOffDateParsed}</p>
<div class="log">🔄 Processing... Total 0</div>
<br>
<style>
table {
border-collapse: collapse;
width: 100%;
font-family: Arial, sans-serif;
font-size: 14px;
}
th, td {
padding: 6px 10px;
border: 1px solid #ccc;
}
thead {
background: #f1f1f1;
}
.log {
margin-top: 15px;
font-family: monospace;
white-space: pre-line;
}
</style>
<table id="results-table">
<thead>
<tr>
<th>Order Ref</th>
<th>Booking Amount</th>
<th>Paid Amount</th>
<th>Outstanding Amount</th>
<th>Customer</th>
<th>Order Created Date</th>
</tr>
</thead>
<tbody></tbody>
</table>
<script>
let currentPage = 1;
const cutOffDate = encodeURIComponent("{$cutOffDateString}");
const tableBody = document.querySelector('#results-table tbody');
const log = document.querySelector('.log');
const bookingUrlTemplate = "/transfer/__ORDER_REF__";
const customerUrlTemplate = "/customer/__ORDER_REF__";
let totalRows = 0;
function updateLogMessage() {
log.textContent = `🔄 Processing... Total \${totalRows}`;
}
function runNextBatch() {
const url = `/run-batch-unfinished-payment-orders?page=\${currentPage}&cut_off_date=\${cutOffDate}`;
fetch(url)
.then(res => {
if (!res.ok) throw new Error("404 or server error");
return res.json();
})
.then(data => {
if (data.success) {
totalRows += data.count;
updateLogMessage();
data.data.forEach(item => {
const row = document.createElement('tr');
row.innerHTML = `
<td><a href="\${bookingUrlTemplate.replace('__ORDER_REF__', item.order_ref)}" target="_blank">\${item.order_ref}</a></td>
<td>\${item.booking_amount}</td>
<td>\${item.paid_amount}</td>
<td>\${item.outstanding_amount}</td>
<td><a href="\${customerUrlTemplate.replace('__ORDER_REF__', item.customer)}" target="_blank">\${item.customer ?? '-'}</a></td>
<td>\${item.created_at}</td>
`;
tableBody.appendChild(row);
});
if (data.next_page) {
currentPage = data.next_page;
runNextBatch();
} else {
log.textContent = `✅ Completed. Total \${totalRows}`;
}
}
})
.catch(err => {
log.textContent = "❌ Error: " + err + "\\n";
});
}
runNextBatch();
</script>
HTML;
}
}