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 */ 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', ]); } }