90 lines
3.7 KiB
PHP
90 lines
3.7 KiB
PHP
<?php
|
|
|
|
namespace App\Http\Controllers\Business;
|
|
|
|
use App\Models\Business\CourierStockQuoteEntry;
|
|
use App\Support\CourierStockQuoteEntryService;
|
|
use Illuminate\Http\RedirectResponse;
|
|
use Illuminate\Http\Request;
|
|
use Illuminate\Routing\Controller;
|
|
use Illuminate\Support\Facades\Storage;
|
|
use Illuminate\View\View;
|
|
use Symfony\Component\HttpFoundation\StreamedResponse;
|
|
|
|
class CourierStockQuoteEntries extends Controller
|
|
{
|
|
public function __construct(private readonly CourierStockQuoteEntryService $service)
|
|
{
|
|
}
|
|
|
|
public function create(): View
|
|
{
|
|
return view('business.pages.courier-payables.stock-quote-entry', ['entry' => null, 'couriers' => $this->service->courierOptions()]);
|
|
}
|
|
|
|
public function store(Request $request): RedirectResponse
|
|
{
|
|
$data = $request->validate([
|
|
...$this->metadataRules(),
|
|
'courier_expcode' => ['required', 'string', 'max:64'],
|
|
'quote_type' => ['required', 'string', 'max:64'],
|
|
'sheet_name' => ['nullable', 'string', 'max:255'],
|
|
...$this->fileRules(true),
|
|
]);
|
|
$entry = $this->service->create($data, (int) user_id());
|
|
|
|
return redirect()->route('business.courier-quote-changes.show', $entry->change)
|
|
->with('success', '存量报价草稿已保存。请核对原报价、计费规则和实际执行日期后提交审核。');
|
|
}
|
|
|
|
public function edit(CourierStockQuoteEntry $stockQuoteEntry): View
|
|
{
|
|
$this->ensureEditable($stockQuoteEntry);
|
|
|
|
return view('business.pages.courier-payables.stock-quote-entry', ['entry' => $stockQuoteEntry, 'couriers' => []]);
|
|
}
|
|
|
|
public function update(Request $request, CourierStockQuoteEntry $stockQuoteEntry): RedirectResponse
|
|
{
|
|
$this->ensureEditable($stockQuoteEntry);
|
|
$data = $request->validate([...$this->metadataRules(), ...$this->fileRules(false), 'sheet_name' => ['nullable', 'string', 'max:255']]);
|
|
$this->service->update($stockQuoteEntry, $data, (int) user_id());
|
|
|
|
return redirect()->route('business.courier-quote-changes.show', $stockQuoteEntry->change)->with('success', '草稿已更新,历次原报价及附件已保留。请重新核对后提交审核。');
|
|
}
|
|
|
|
public function download(CourierStockQuoteEntry $stockQuoteEntry, int $file): StreamedResponse
|
|
{
|
|
abort_unless($stockQuoteEntry->company_id === (int) company_id(), 404);
|
|
$attachment = $stockQuoteEntry->files[$file] ?? null;
|
|
abort_if($attachment === null || ! Storage::disk('uploads')->exists($attachment['path']), 404, '附件不存在。');
|
|
|
|
return Storage::disk('uploads')->download($attachment['path'], $attachment['name']);
|
|
}
|
|
|
|
private function metadataRules(): array
|
|
{
|
|
return [
|
|
'effective_date' => ['required', 'date_format:Y-m-d'],
|
|
'billing_rules' => ['required', 'string', 'min:2', 'max:4000'],
|
|
'summary' => ['required', 'string', 'min:2', 'max:2000'],
|
|
];
|
|
}
|
|
|
|
private function fileRules(bool $requiresSource): array
|
|
{
|
|
return [
|
|
'source_quote' => [$requiresSource ? 'required' : 'nullable', 'file', 'mimes:xlsx,xls', 'max:20480'],
|
|
'confirmation_files' => ['nullable', 'array', 'max:10'],
|
|
'confirmation_files.*' => ['file', 'mimes:pdf,doc,docx,jpg,jpeg,png,xlsx,xls,eml,msg', 'max:20480'],
|
|
'signed_files' => ['nullable', 'array', 'max:10'],
|
|
'signed_files.*' => ['file', 'mimes:pdf,doc,docx,jpg,jpeg,png', 'max:20480'],
|
|
];
|
|
}
|
|
|
|
private function ensureEditable(CourierStockQuoteEntry $entry): void
|
|
{
|
|
abort_unless($entry->company_id === (int) company_id() && $entry->change?->isEditable() && $entry->change->created_by === user_id(), 403);
|
|
}
|
|
}
|