CaiWuXiTong/app/Http/Controllers/Business/SupplierReconciliation.php
renshen 2848c81a5e 供应商对账:退货明细改为「退货扣减确认」面板 (#369)
退货扣减确认:顶部汇总、逐行确认/异议、全部确认(不覆盖异议)、金额空按预估金额扣减,展示金额最高 15 行。
2026-10-17 09:40:54 +08:00

116 lines
4.1 KiB
PHP

<?php
namespace App\Http\Controllers\Business;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Routing\Controller;
use Modules\EcommerceFinance\Services\SupplierReturnConfirmation;
use Modules\EcommerceFinance\Services\SupplierStatementStore;
use Modules\EcommerceFinance\Services\SupplierStatementTemplate;
use Modules\EcommerceFinance\View\SupplierReconciliationPageData;
use Symfony\Component\HttpFoundation\BinaryFileResponse;
/**
* 供应商对账:对账单模板下载 + 厂家对账单上传(严格按模板校验)。
*/
class SupplierReconciliation extends Controller
{
public function __construct(
private readonly SupplierStatementTemplate $template,
private readonly SupplierStatementStore $statements,
private readonly SupplierReturnConfirmation $returnConfirmations,
private readonly SupplierReconciliationPageData $pageData,
) {
$this->middleware('auth');
$this->middleware('company.identify');
}
public function template(): BinaryFileResponse
{
$path = $this->template->path();
abort_unless(is_file($path), 404, '对账单模板不存在。');
return response()->download($path, $this->template->filename());
}
public function upload(Request $request): JsonResponse|RedirectResponse
{
$request->validate([
'import' => ['required', 'file', 'mimes:xlsx,xls,csv', 'max:51200'],
'supplier' => ['required', 'string', 'max:191'],
]);
$supplier = trim((string) $request->input('supplier'));
if ($supplier === '') {
abort(422, '请选择厂家。');
}
$records = $this->template->parse($request->file('import'), $supplier);
$rows = $this->statements->save(
$supplier,
$records,
(string) $request->file('import')->getClientOriginalName(),
(int) (company_id() ?: 1),
user_id() ? (int) user_id() : null,
);
$message = "对账单已保存:{$supplier} 共 {$rows} 行。";
return $request->expectsJson()
? response()->json(['message' => $message, 'rows' => $rows])
: back()->with('success', $message);
}
public function confirmReturn(Request $request): RedirectResponse
{
return $this->markReturn($request, SupplierReturnConfirmation::STATUS_CONFIRMED, '已确认该行退货扣减。');
}
public function disputeReturn(Request $request): RedirectResponse
{
return $this->markReturn($request, SupplierReturnConfirmation::STATUS_DISPUTED, '已提交异议,复核通过前该行暂不扣减。');
}
public function confirmAllReturns(Request $request): RedirectResponse
{
[$supplier, $companyId] = $this->returnTarget($request);
$keys = array_values(array_map(
static fn (array $row): string => (string) ($row['_action_key'] ?? ''),
$this->pageData->returnRows($supplier, $companyId),
));
$confirmed = $this->returnConfirmations->confirmAll(
$supplier,
$keys,
$companyId,
user_id() ? (int) user_id() : null,
);
return back()->with('success', "已全部确认:{$confirmed} 行退货扣减生效(异议行保持暂不扣减)。");
}
private function markReturn(Request $request, string $status, string $message): RedirectResponse
{
$request->validate(['key' => ['required', 'string', 'max:191']]);
[$supplier, $companyId] = $this->returnTarget($request);
$this->returnConfirmations->mark(
$supplier,
(string) $request->input('key'),
$status,
$companyId,
user_id() ? (int) user_id() : null,
);
return back()->with('success', $message);
}
/** @return array{0:string,1:int} */
private function returnTarget(Request $request): array
{
$request->validate(['supplier' => ['required', 'string', 'max:191']]);
return [trim((string) $request->input('supplier')), (int) (company_id() ?: 1)];
}
}