179 lines
6.8 KiB
PHP
179 lines
6.8 KiB
PHP
<?php
|
|
|
|
namespace Modules\EcommerceFinance\Http\Controllers;
|
|
|
|
use App\Utilities\SidebarPermissions;
|
|
use Illuminate\Http\Request;
|
|
use Illuminate\Routing\Controller;
|
|
use Modules\EcommerceFinance\AccountBillColumns;
|
|
use Modules\EcommerceFinance\Repositories\DewuSettlementBillRepository;
|
|
use RuntimeException;
|
|
|
|
class DewuAccountBills extends Controller
|
|
{
|
|
public function index(Request $request, DewuSettlementBillRepository $repository)
|
|
{
|
|
$this->authorizeStoreReceivingBills();
|
|
|
|
if ($request->boolean('export')) {
|
|
return $this->exportResponse($request, $repository);
|
|
}
|
|
|
|
$validated = $request->validate($this->filterRules() + [
|
|
'sort' => ['nullable', 'in:occurred_at,income,expense,record_code'],
|
|
'dir' => ['nullable', 'in:asc,desc'],
|
|
'page' => ['nullable', 'integer', 'min:1'],
|
|
'limit' => ['nullable', 'integer', 'min:1', 'max:100'],
|
|
]);
|
|
$filters = collect($validated)->only(array_keys($this->filterRules()))->all();
|
|
|
|
try {
|
|
$data = $repository->paginateAccountBills(
|
|
$filters,
|
|
(string) ($validated['sort'] ?? 'occurred_at'),
|
|
(string) ($validated['dir'] ?? 'desc'),
|
|
(int) ($validated['page'] ?? 1),
|
|
(int) ($validated['limit'] ?? 10),
|
|
);
|
|
} catch (RuntimeException $exception) {
|
|
if ($exception->getMessage() !== 'dewu_authoritative_bills_not_ready') {
|
|
throw $exception;
|
|
}
|
|
|
|
return response()->json([
|
|
'message' => '得物完整账单尚未完成首次导入,当前不会回退到不完整的聚水潭辅助表。',
|
|
'data' => [],
|
|
'total' => 0,
|
|
'current_page' => 1,
|
|
'last_page' => 1,
|
|
'per_page' => (int) ($validated['limit'] ?? 10),
|
|
'summary' => ['income' => 0, 'expense' => 0, 'balance' => 0, 'count' => 0],
|
|
'columns' => AccountBillColumns::for('dewu'),
|
|
], 503);
|
|
}
|
|
|
|
$data['columns'] = AccountBillColumns::for('dewu');
|
|
|
|
return response()->json($data);
|
|
}
|
|
|
|
public function filterOptions(DewuSettlementBillRepository $repository)
|
|
{
|
|
$this->authorizeStoreReceivingBills();
|
|
|
|
try {
|
|
return response()->json($repository->accountBillFilterOptions());
|
|
} catch (RuntimeException $exception) {
|
|
if ($exception->getMessage() !== 'dewu_authoritative_bills_not_ready') {
|
|
throw $exception;
|
|
}
|
|
|
|
return response()->json([
|
|
'message' => '得物完整账单尚未完成首次导入。',
|
|
'shops' => [],
|
|
'bill_items' => [],
|
|
], 503);
|
|
}
|
|
}
|
|
|
|
public function export(Request $request, DewuSettlementBillRepository $repository)
|
|
{
|
|
$this->authorizeStoreReceivingBills();
|
|
|
|
return $this->exportResponse($request, $repository);
|
|
}
|
|
|
|
private function exportResponse(Request $request, DewuSettlementBillRepository $repository)
|
|
{
|
|
$validated = $request->validate($this->filterRules() + [
|
|
'sort' => ['nullable', 'in:occurred_at,income,expense,record_code'],
|
|
'dir' => ['nullable', 'in:asc,desc'],
|
|
]);
|
|
$filters = collect($validated)->only(array_keys($this->filterRules()))->all();
|
|
$definition = AccountBillColumns::for('dewu');
|
|
$available = collect($definition['columns'] ?? [])->keyBy('field');
|
|
$requested = $request->query('columns', []);
|
|
if (is_string($requested)) {
|
|
$requested = array_filter(array_map('trim', explode(',', $requested)));
|
|
}
|
|
if (! is_array($requested) || count($requested) > 40) {
|
|
$requested = [];
|
|
}
|
|
$requested = collect($requested)
|
|
->filter(static fn (mixed $value): bool => is_scalar($value))
|
|
->map(static fn (mixed $value): string => mb_substr(trim((string) $value), 0, 128))
|
|
->filter()
|
|
->unique();
|
|
$columns = $requested->isEmpty()
|
|
? $available->values()
|
|
: $requested->map(fn (string $field) => $available->get($field))->filter()->values();
|
|
abort_if($columns->isEmpty(), 422, '至少选择一个可导出的字段。');
|
|
|
|
try {
|
|
$rows = $repository->exportAccountBills(
|
|
$filters,
|
|
(string) ($validated['sort'] ?? 'occurred_at'),
|
|
(string) ($validated['dir'] ?? 'asc'),
|
|
);
|
|
} catch (RuntimeException $exception) {
|
|
if ($exception->getMessage() !== 'dewu_authoritative_bills_not_ready') {
|
|
throw $exception;
|
|
}
|
|
|
|
return response()->json(['message' => '得物完整账单尚未完成首次导入。'], 503);
|
|
}
|
|
|
|
return response()->streamDownload(function () use ($rows, $columns): void {
|
|
$csv = fopen('php://output', 'w');
|
|
fputs($csv, "\xEF\xBB\xBF");
|
|
fputcsv($csv, $columns->pluck('label')->all());
|
|
foreach ($rows as $row) {
|
|
fputcsv($csv, $columns->map(
|
|
fn (array $column): string => $this->exportValue($row, $column)
|
|
)->all());
|
|
}
|
|
fclose($csv);
|
|
}, 'dewu_account_bills.csv', [
|
|
'Content-Type' => 'text/csv; charset=UTF-8',
|
|
'Cache-Control' => 'private, no-store',
|
|
]);
|
|
}
|
|
|
|
/** @return array<string,array<int,string>> */
|
|
private function filterRules(): array
|
|
{
|
|
return [
|
|
'store_name' => ['nullable', 'string', 'max:255'],
|
|
'bill_item' => ['nullable', 'string', 'max:255'],
|
|
'start' => ['nullable', 'date_format:Y-m-d'],
|
|
'end' => ['nullable', 'date_format:Y-m-d', 'after_or_equal:start'],
|
|
'keyword' => ['nullable', 'string', 'max:255'],
|
|
];
|
|
}
|
|
|
|
/** @param array<string,mixed> $row */
|
|
private function exportValue(array $row, array $column): string
|
|
{
|
|
$field = (string) ($column['field'] ?? '');
|
|
$value = str_starts_with($field, 'payload.')
|
|
? data_get($row['payload'] ?? [], substr($field, 8))
|
|
: data_get($row, $field);
|
|
$text = (string) ($value ?? '');
|
|
if (preg_match('/^\d{12,}$/', $text) === 1) {
|
|
return '="' . $text . '"';
|
|
}
|
|
|
|
return preg_match('/^[=+\-@]/u', $text) === 1 ? "'" . $text : $text;
|
|
}
|
|
|
|
private function authorizeStoreReceivingBills(): void
|
|
{
|
|
$section = collect(SidebarPermissions::navigationFor(user()))
|
|
->firstWhere('slug', 'billing-transactions');
|
|
$page = collect($section['pages'] ?? [])
|
|
->firstWhere('slug', 'store-receiving-bills');
|
|
|
|
abort_if(empty($page), 403, '当前账号没有店铺收款账户账单权限。');
|
|
}
|
|
}
|