供应商负数预警读取供应商应付终版数据集,筛选供应商余额小于 0 的记录。 Co-authored-by: 苏木 <594326199@qq.com> Co-committed-by: 苏木 <594326199@qq.com>
148 lines
5.0 KiB
PHP
148 lines
5.0 KiB
PHP
<?php
|
||
|
||
namespace Modules\EcommerceFinance\View;
|
||
|
||
use App\Http\Controllers\Business\PayablesFinalActions;
|
||
use Illuminate\Pagination\LengthAwarePaginator;
|
||
use Modules\EcommerceFinance\Services\SupplierPayableOverrideStore;
|
||
|
||
/**
|
||
* 供应商负数预警:直接读取「供应商应付(终版)→ 供应商应付表」,
|
||
* 仅保留供应商余额小于 0 的记录。
|
||
*/
|
||
class SupplierNegativeAlertPageData
|
||
{
|
||
private const DATASET = 'supplier:supplier-payables-report';
|
||
|
||
private const PER_PAGE = 25;
|
||
|
||
public function __construct(
|
||
private readonly SupplierPayableOverrideStore $store,
|
||
) {
|
||
}
|
||
|
||
/** @return array<string,mixed> */
|
||
public function page(): array
|
||
{
|
||
$rows = $this->store->listRows(
|
||
PayablesFinalActions::DATASET_PREFIX . self::DATASET,
|
||
(int) (company_id() ?: 1),
|
||
);
|
||
|
||
$negativeRows = [];
|
||
foreach ($rows as $row) {
|
||
$balance = $this->number($row['supplier_balance'] ?? null);
|
||
if ($balance === null || $balance >= 0) {
|
||
continue;
|
||
}
|
||
|
||
$row['supplier_balance'] = $balance;
|
||
$negativeRows[] = $row;
|
||
}
|
||
|
||
usort($negativeRows, static function (array $left, array $right): int {
|
||
return strcmp(
|
||
(string) ($right['summary_month'] ?? ''),
|
||
(string) ($left['summary_month'] ?? ''),
|
||
) ?: strnatcasecmp(
|
||
(string) ($left['supplier'] ?? ''),
|
||
(string) ($right['supplier'] ?? ''),
|
||
);
|
||
});
|
||
|
||
$months = [];
|
||
foreach ($negativeRows as $row) {
|
||
$month = trim((string) ($row['summary_month'] ?? ''));
|
||
if (preg_match('/^\d{4}-\d{2}$/', $month) === 1) {
|
||
$months[$month] = true;
|
||
}
|
||
}
|
||
$months = array_keys($months);
|
||
rsort($months);
|
||
|
||
$requestedMonth = trim((string) request()->query('month', ''));
|
||
$month = in_array($requestedMonth, $months, true) ? $requestedMonth : '';
|
||
if ($month !== '') {
|
||
$negativeRows = array_values(array_filter(
|
||
$negativeRows,
|
||
static fn (array $row): bool => (string) ($row['summary_month'] ?? '') === $month,
|
||
));
|
||
}
|
||
|
||
$supplierNames = [];
|
||
foreach ($negativeRows as $row) {
|
||
$supplier = trim((string) ($row['supplier'] ?? ''));
|
||
if ($supplier !== '') {
|
||
$supplierNames[$supplier] = true;
|
||
}
|
||
}
|
||
$supplierNames = array_keys($supplierNames);
|
||
sort($supplierNames, SORT_NATURAL | SORT_FLAG_CASE);
|
||
|
||
$supplierQuery = mb_substr(trim((string) request()->query('supplier', '')), 0, 191);
|
||
if ($supplierQuery !== '') {
|
||
$needle = mb_strtolower($supplierQuery);
|
||
$negativeRows = array_values(array_filter(
|
||
$negativeRows,
|
||
static function (array $row) use ($needle): bool {
|
||
$haystack = mb_strtolower(implode("\n", [
|
||
(string) ($row['supplier'] ?? ''),
|
||
(string) ($row['company'] ?? ''),
|
||
]));
|
||
|
||
return str_contains($haystack, $needle);
|
||
},
|
||
));
|
||
}
|
||
|
||
$supplierCounts = [];
|
||
foreach ($negativeRows as $row) {
|
||
$key = trim((string) ($row['company'] ?? '')) . "\0" . trim((string) ($row['supplier'] ?? ''));
|
||
$supplierCounts[$key] = true;
|
||
}
|
||
|
||
$total = count($negativeRows);
|
||
$pages = max((int) ceil($total / self::PER_PAGE), 1);
|
||
$page = min(max((int) request()->query('page', 1), 1), $pages);
|
||
$items = array_map(
|
||
static fn (array $row): object => (object) $row,
|
||
array_slice($negativeRows, ($page - 1) * self::PER_PAGE, self::PER_PAGE),
|
||
);
|
||
|
||
return [
|
||
'view' => 'business.pages.negative-alerts.supplier-negative-alert',
|
||
'negativeAlertRows' => new LengthAwarePaginator(
|
||
$items,
|
||
$total,
|
||
self::PER_PAGE,
|
||
$page,
|
||
[
|
||
'path' => request()->url(),
|
||
'query' => request()->except('page'),
|
||
],
|
||
),
|
||
'negativeAlertMonths' => $months,
|
||
'negativeAlertMonth' => $month,
|
||
'negativeAlertSupplier' => $supplierQuery,
|
||
'negativeAlertSupplierNames' => $supplierNames,
|
||
'negativeAlertSupplierCount' => count($supplierCounts),
|
||
'negativeAlertTotal' => $total,
|
||
'negativeAlertSourceUrl' => route('business.pages.show', [
|
||
'section' => 'supplier-payables-final',
|
||
'page' => 'supplier-payables-report',
|
||
]),
|
||
];
|
||
}
|
||
|
||
private function number(mixed $value): ?float
|
||
{
|
||
if ($value === null || trim((string) $value) === '') {
|
||
return null;
|
||
}
|
||
|
||
$normalized = str_replace([',', ',', ' '], '', trim((string) $value));
|
||
|
||
return is_numeric($normalized) ? (float) $normalized : null;
|
||
}
|
||
}
|