169 lines
7.0 KiB
PHP
169 lines
7.0 KiB
PHP
<?php
|
|
|
|
namespace App\Http\Controllers\Business;
|
|
|
|
use App\Business\CourierSurchargeQuoteRepository;
|
|
use App\Business\CourierSurchargeQuoteWorkbookImporter;
|
|
use App\Models\Business\CourierSurchargeQuote;
|
|
use Illuminate\Http\RedirectResponse;
|
|
use Illuminate\Http\Request;
|
|
use Illuminate\Routing\Controller;
|
|
use Illuminate\Support\Str;
|
|
use Symfony\Component\HttpFoundation\StreamedResponse;
|
|
|
|
class CourierSurchargeQuotes extends Controller
|
|
{
|
|
public function __construct(
|
|
private readonly CourierSurchargeQuoteRepository $quotes,
|
|
private readonly CourierSurchargeQuoteWorkbookImporter $workbookImporter,
|
|
) {
|
|
$this->middleware('auth');
|
|
$this->middleware('company.identify');
|
|
$this->middleware('business.page:courier-payables,courier-surcharge');
|
|
}
|
|
|
|
public function store(Request $request): RedirectResponse
|
|
{
|
|
abort_unless($this->quotes->ready(), 503, '附加费报价数据表尚未完成迁移,请联系管理员。');
|
|
|
|
$this->quotes->create($this->validated($request), (int) user_id());
|
|
|
|
return $this->redirect()->with('success', '报价规则已新增并保存。');
|
|
}
|
|
|
|
public function update(Request $request, CourierSurchargeQuote $quote): RedirectResponse
|
|
{
|
|
$this->ensureCompany($quote);
|
|
abort_unless($this->quotes->ready(), 503, '附加费报价数据表尚未完成迁移,请联系管理员。');
|
|
|
|
$this->quotes->update($quote, $this->validated($request), (int) user_id());
|
|
|
|
return $this->redirect()->with('success', '报价规则已更新并保存。');
|
|
}
|
|
|
|
public function setStatus(Request $request, CourierSurchargeQuote $quote): RedirectResponse
|
|
{
|
|
$this->ensureCompany($quote);
|
|
abort_unless($this->quotes->ready(), 503, '附加费报价数据表尚未完成迁移,请联系管理员。');
|
|
|
|
$status = $request->validate([
|
|
'status' => ['required', 'in:' . CourierSurchargeQuote::STATUS_ACTIVE . ',' . CourierSurchargeQuote::STATUS_INACTIVE],
|
|
])['status'];
|
|
$this->quotes->setStatus($quote, $status, (int) user_id());
|
|
|
|
return $this->redirect()->with('success', '报价规则状态已更新。');
|
|
}
|
|
|
|
public function importTemplate(): StreamedResponse
|
|
{
|
|
abort_unless($this->quotes->ready(), 503, '附加费报价数据表尚未完成迁移,请联系管理员。');
|
|
|
|
return $this->workbookImporter->template();
|
|
}
|
|
|
|
public function importPreview(Request $request): RedirectResponse
|
|
{
|
|
abort_unless($this->quotes->ready(), 503, '附加费报价数据表尚未完成迁移,请联系管理员。');
|
|
|
|
$file = $request->validate([
|
|
'import_file' => ['required', 'file', 'max:10240'],
|
|
])['import_file'];
|
|
$preview = $this->workbookImporter->preview($file);
|
|
$token = Str::random(48);
|
|
$previews = collect((array) $request->session()->get('courier_surcharge_import_previews', []))
|
|
->filter(fn (mixed $item): bool => is_array($item) && (int) ($item['expires_at'] ?? 0) >= now()->timestamp)
|
|
->take(-2)
|
|
->all();
|
|
$previews[$token] = [
|
|
'company_id' => (int) company_id(),
|
|
'user_id' => (int) user_id(),
|
|
'expires_at' => now()->addMinutes(20)->timestamp,
|
|
'rows' => $preview['rows'],
|
|
];
|
|
$request->session()->put('courier_surcharge_import_previews', $previews);
|
|
|
|
return $this->redirect()->with('courierSurchargeImportPreview', $preview + ['token' => $token]);
|
|
}
|
|
|
|
public function importCommit(Request $request): RedirectResponse
|
|
{
|
|
abort_unless($this->quotes->ready(), 503, '附加费报价数据表尚未完成迁移,请联系管理员。');
|
|
|
|
$validated = $request->validate([
|
|
'preview_token' => ['required', 'string', 'size:48'],
|
|
'duplicate_policy' => ['required', 'in:' . CourierSurchargeQuoteWorkbookImporter::DUPLICATE_SKIP . ',' . CourierSurchargeQuoteWorkbookImporter::DUPLICATE_UPDATE],
|
|
]);
|
|
$previews = (array) $request->session()->get('courier_surcharge_import_previews', []);
|
|
$payload = $previews[$validated['preview_token']] ?? null;
|
|
|
|
if (! is_array($payload)
|
|
|| (int) ($payload['company_id'] ?? 0) !== (int) company_id()
|
|
|| (int) ($payload['user_id'] ?? 0) !== (int) user_id()
|
|
|| (int) ($payload['expires_at'] ?? 0) < now()->timestamp) {
|
|
unset($previews[$validated['preview_token']]);
|
|
$request->session()->put('courier_surcharge_import_previews', $previews);
|
|
|
|
return $this->redirect()->withErrors([
|
|
'import' => '导入预览已失效或不属于当前账号,请重新选择文件预览。',
|
|
]);
|
|
}
|
|
|
|
$counts = $this->workbookImporter->commit(
|
|
(array) ($payload['rows'] ?? []),
|
|
$validated['duplicate_policy'],
|
|
(int) user_id(),
|
|
);
|
|
unset($previews[$validated['preview_token']]);
|
|
$request->session()->put('courier_surcharge_import_previews', $previews);
|
|
|
|
return $this->redirect()->with(
|
|
'success',
|
|
sprintf(
|
|
'附加费报价导入完成:新增 %d 条,更新 %d 条,跳过 %d 条。',
|
|
$counts['created'],
|
|
$counts['updated'],
|
|
$counts['skipped'],
|
|
),
|
|
);
|
|
}
|
|
|
|
/** @return array<string,mixed> */
|
|
private function validated(Request $request): array
|
|
{
|
|
$data = $request->validate([
|
|
'courier' => ['required', 'string', 'max:191'],
|
|
'scope' => ['required', 'in:' . implode(',', CourierSurchargeQuoteRepository::SCOPES)],
|
|
'reconciler' => ['required', 'string', 'max:100'],
|
|
'supplier' => ['nullable', 'string', 'max:191'],
|
|
'types' => ['required', 'array', 'min:1', 'max:50'],
|
|
'types.*' => ['string', 'in:' . implode(',', $this->quotes->activeTypeNames())],
|
|
'mode' => ['required', 'in:' . implode(',', CourierSurchargeQuoteRepository::MODES)],
|
|
'standard' => ['required', 'string', 'max:2000'],
|
|
'condition' => ['required', 'string', 'max:2000'],
|
|
'effective_at' => ['required', 'date_format:Y-m-d'],
|
|
'remark' => ['nullable', 'string', 'max:2000'],
|
|
]);
|
|
|
|
$data['courier'] = trim($data['courier']);
|
|
$data['reconciler'] = trim($data['reconciler']);
|
|
$data['supplier'] = trim((string) ($data['supplier'] ?? '')) ?: null;
|
|
$data['types'] = array_values(array_unique($data['types']));
|
|
|
|
return $data;
|
|
}
|
|
|
|
private function ensureCompany(CourierSurchargeQuote $quote): void
|
|
{
|
|
abort_unless((int) $quote->company_id === (int) company_id(), 404, '报价规则不存在。');
|
|
}
|
|
|
|
private function redirect(): RedirectResponse
|
|
{
|
|
return redirect()->route('business.pages.show', [
|
|
'company_id' => company_id() ?: 1,
|
|
'section' => 'courier-payables',
|
|
'page' => 'courier-surcharge',
|
|
]);
|
|
}
|
|
}
|