From 125e9ea8aa0218761152b9aef558ef1ac7204efe Mon Sep 17 00:00:00 2001 From: limeng <1131177064@qq.com> Date: Sat, 17 Oct 2026 12:48:24 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E5=AD=98=E9=87=8F=E6=8A=A5=E4=BB=B7?= =?UTF-8?q?=E5=AE=A1=E6=A0=B8=E7=94=9F=E6=95=88=E5=B9=B6=E6=94=AF=E6=8C=81?= =?UTF-8?q?=E7=AD=BE=E7=BD=B2=E5=8E=9F=E4=BB=B6=E9=A2=84=E8=A7=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Business/CourierStockQuoteEntries.php | 2 +- app/Models/Business/CourierQuoteVersion.php | 14 ++++++++ app/Support/CourierQuoteChangeService.php | 4 +-- app/Support/CourierRequoteService.php | 2 +- app/Support/QuoteManagementSnapshot.php | 31 +++++++++++++---- .../partials/stock-quote-review.blade.php | 2 +- .../quote-change-show.blade.php | 2 +- .../quote-management.blade.php | 11 ++++++ .../stock-quote-entry.blade.php | 2 +- .../Business/CourierStockQuoteBatchTest.php | 2 +- .../Business/CourierStockQuoteEntryTest.php | 34 +++++++++++++++++-- 11 files changed, 90 insertions(+), 16 deletions(-) diff --git a/app/Http/Controllers/Business/CourierStockQuoteEntries.php b/app/Http/Controllers/Business/CourierStockQuoteEntries.php index beb94014..a2c58aca 100644 --- a/app/Http/Controllers/Business/CourierStockQuoteEntries.php +++ b/app/Http/Controllers/Business/CourierStockQuoteEntries.php @@ -166,7 +166,7 @@ class CourierStockQuoteEntries extends Controller $headers = ['Cache-Control' => 'private, no-store', 'X-Content-Type-Options' => 'nosniff']; if ($preview) { $mime = $attachment['mime_type'] ?? $disk->mimeType($attachment['path']); - abort_unless(in_array($mime, ['image/jpeg', 'image/png', 'image/gif', 'image/webp', 'image/bmp'], true), 415, '此格式请下载原文件查看。'); + abort_unless(in_array($mime, ['application/pdf', 'image/jpeg', 'image/png', 'image/gif', 'image/webp', 'image/bmp'], true), 415, '此格式请下载原文件查看。'); return $disk->response($attachment['path'], $attachment['name'], [...$headers, 'Content-Type' => $mime]); } diff --git a/app/Models/Business/CourierQuoteVersion.php b/app/Models/Business/CourierQuoteVersion.php index 74916822..05bd7336 100644 --- a/app/Models/Business/CourierQuoteVersion.php +++ b/app/Models/Business/CourierQuoteVersion.php @@ -61,6 +61,20 @@ class CourierQuoteVersion extends Model return $this->status === self::STATUS_VOIDED; } + /** 存量报价审核后按执行日期生效,不以补签或历史签署资料为前置条件。 */ + public function isApprovedStockQuote(): bool + { + return $this->status === self::STATUS_APPROVED + && $this->change?->status === CourierQuoteChange::STATUS_APPROVED + && $this->change->isStockQuote(); + } + + public function signatureLabel(): string + { + return $this->isApprovedStockQuote() && !in_array($this->signature_status, ['历史签署资料已归档', '已签署并归档'], true) + ? '存量报价,审核生效(无需签章)' : (string) $this->signature_status; + } + public function change(): BelongsTo { return $this->belongsTo(CourierQuoteChange::class, 'source_change_id'); diff --git a/app/Support/CourierQuoteChangeService.php b/app/Support/CourierQuoteChangeService.php index cd9f578b..7f6d64e1 100644 --- a/app/Support/CourierQuoteChangeService.php +++ b/app/Support/CourierQuoteChangeService.php @@ -142,7 +142,7 @@ final class CourierQuoteChangeService $hasHistoricalFiles = $change->isStockQuote() && collect(CourierStockQuoteEntry::query()->findOrFail(data_get($change->quote_payload, 'stock_quote_entry_id'))->files)->contains('kind', 'signed'); if ($change->isStockQuote() && $historicalDocumentsConfirmed && ! $hasHistoricalFiles) { - throw ValidationException::withMessages(['stock_signature_verified' => '尚未上传历史签署资料,请补充资料或保留待确认/待补签状态。']); + throw ValidationException::withMessages(['stock_signature_verified' => '尚未上传历史签署资料,请补充资料或取消历史资料核验;不影响存量报价审核生效。']); } $historicalSigned = $hasHistoricalFiles && $historicalDocumentsConfirmed; $values = $source['values']; @@ -182,7 +182,7 @@ final class CourierQuoteChangeService 'values_json' => json_encode($values, JSON_UNESCAPED_UNICODE | JSON_THROW_ON_ERROR), 'formulas_json' => json_encode($formulas, JSON_UNESCAPED_UNICODE | JSON_THROW_ON_ERROR), 'status' => 'approved', - 'signature_status' => $change->isStockQuote() ? ($historicalSigned ? '历史签署资料已归档' : '待确认/待补签') : '未签署', + 'signature_status' => $change->isStockQuote() ? ($historicalSigned ? '历史签署资料已归档' : '存量报价,审核生效(无需签章)') : '未签署', 'created_by' => $change->created_by, 'approved_by' => $userId, ]); diff --git a/app/Support/CourierRequoteService.php b/app/Support/CourierRequoteService.php index c2ff6478..5bc9dbbb 100644 --- a/app/Support/CourierRequoteService.php +++ b/app/Support/CourierRequoteService.php @@ -370,7 +370,7 @@ final class CourierRequoteService { return $versions ->filter(static fn (CourierQuoteVersion $version): bool => ! $version->isVoided() - && self::isSignedVersion($version) + && ($version->isApprovedStockQuote() || self::isSignedVersion($version)) && ($includeTemporary || ! $version->isTemporary()) && $version->coversDate($date)) ->sortBy([ diff --git a/app/Support/QuoteManagementSnapshot.php b/app/Support/QuoteManagementSnapshot.php index 9a1090cb..cbd3353e 100644 --- a/app/Support/QuoteManagementSnapshot.php +++ b/app/Support/QuoteManagementSnapshot.php @@ -165,11 +165,12 @@ final class QuoteManagementSnapshot 'column_count' => $columnCount, 'formula_count' => $this->formulaCount($formulas), 'status' => $this->versionLifecycleStatus($version), - 'signature_status' => $version->signature_status, + 'signature_status' => $version->signatureLabel(), 'values' => $values, 'formulas' => $formulas, 'source_change_id' => $version->source_change_id, 'signed_files' => $this->signedFiles($version), + 'stock_originals' => $this->stockOriginals($version), 'signed_at' => $version->signature?->completed_at?->format('Y-m-d H:i') ?? $version->signature?->archived_at?->format('Y-m-d H:i'), ]; @@ -205,6 +206,24 @@ final class QuoteManagementSnapshot return $files; } + private function stockOriginals(CourierQuoteVersion $version): array + { + if (!$version->change?->isStockQuote() || !($entry = $version->change->stockEntry)) return []; + $files = []; + foreach ($entry->files as $index => $file) { + if (($file['kind'] ?? '') !== 'signed') continue; + // 早期手动上传未记录 MIME;入口按扩展名提供,响应仍按实际 MIME 白名单校验。 + $previewable = isset($file['mime_type']) + ? in_array($file['mime_type'], ['application/pdf', 'image/jpeg', 'image/png', 'image/gif', 'image/webp', 'image/bmp'], true) + : in_array(strtolower(pathinfo($file['name'], PATHINFO_EXTENSION)), ['pdf', 'jpg', 'jpeg', 'png', 'gif', 'webp', 'bmp'], true); + $files[] = [ + 'name' => $file['name'], 'previewable' => $previewable, + 'url' => route('business.courier-stock-quotes.download', [$entry, $index, 'preview' => $previewable ? 1 : 0]), + ]; + } + return $files; + } + private function decodeMatrix(?string $json): array { if ($json === null || trim($json) === '') { @@ -224,7 +243,7 @@ final class QuoteManagementSnapshot return '已作废'; } - if (! $this->isSigned($version)) { + if (! $this->isExecutable($version)) { return '待生效(待签章)'; } @@ -235,10 +254,10 @@ final class QuoteManagementSnapshot return $version->isTemporary() ? '生效中(临时)' : '生效中'; } - /** 回签单已归档(以签署记录为准,版本上的文字状态可能滞后)。 */ - private function isSigned(CourierQuoteVersion $version): bool + /** 存量报价审核生效;其他报价仍要求回签归档。 */ + private function isExecutable(CourierQuoteVersion $version): bool { - return in_array($version->signature_status, ['已签署并归档', '历史签署资料已归档'], true) + return $version->isApprovedStockQuote() || in_array($version->signature_status, ['已签署并归档', '历史签署资料已归档'], true) || $version->signature?->status === \App\Models\Business\CourierQuoteSignature::STATUS_ARCHIVED; } @@ -261,7 +280,7 @@ final class QuoteManagementSnapshot : 'name:' . $version->company_name)) as $group) { $current = CourierRequoteService::resolveAt($group, $today); $base = CourierRequoteService::resolveAt($group, $today, false); - $started = $group->filter(fn (CourierQuoteVersion $version): bool => ! $version->isVoided() && $this->isSigned($version) + $started = $group->filter(fn (CourierQuoteVersion $version): bool => ! $version->isVoided() && $this->isExecutable($version) && $version->effective_date !== null && $version->effective_date->lte($today)); foreach ($started as $version) { if ($current !== null && $version->id === $current->id) { diff --git a/resources/views/business/pages/courier-payables/partials/stock-quote-review.blade.php b/resources/views/business/pages/courier-payables/partials/stock-quote-review.blade.php index 9cb8e9db..7ae666d2 100644 --- a/resources/views/business/pages/courier-payables/partials/stock-quote-review.blade.php +++ b/resources/views/business/pages/courier-payables/partials/stock-quote-review.blade.php @@ -22,7 +22,7 @@ @if(collect($stockEntry->files)->contains('kind', 'signed'))
@endif -未核验签署依据时,审核后仍为“待确认/待补签”。历史资料归档与本系统电子签署分别记录。
+存量报价审核通过后按实际执行日期生效,无需签章。历史签署资料可另行核验归档,不影响报价生效。
@endif diff --git a/resources/views/business/pages/courier-payables/quote-change-show.blade.php b/resources/views/business/pages/courier-payables/quote-change-show.blade.php index 3cfe18ba..5230df4e 100644 --- a/resources/views/business/pages/courier-payables/quote-change-show.blade.php +++ b/resources/views/business/pages/courier-payables/quote-change-show.blade.php @@ -88,7 +88,7 @@支持 xlsx、xls,单文件不超过 20 MB。原始内容和公式会保留。
多工作表文件请填写本次报价所在的准确工作表名称。
最多 10 个,每个不超过 20 MB。
上传资料后由审核人核验;缺少有效签署依据时标记为待确认/待补签。
上传资料后由审核人核验归档;存量报价审核后按执行日期生效,无需签章。