From 9846f212974b6470ef5be226efcde9402fd2aeff Mon Sep 17 00:00:00 2001 From: renshen <1005457301@qq.com> Date: Sun, 20 Sep 2026 10:05:55 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E8=BF=90=E8=B4=B9=E5=B7=AE?= =?UTF-8?q?=E5=AF=BC=E5=85=A5=E6=A8=A1=E6=9D=BF=E4=B8=8B=E8=BD=BD=20(#209)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Business/CourierPayableSummaries.php | 21 +++ .../freight-difference-import-template.xlsx | Bin 0 -> 54410 bytes .../courier-payables/summary-table.blade.php | 125 +++++++++++++++- routes/admin.php | 3 + .../CourierPayableSummaryPagesTest.php | 134 ++++++++++++++++++ 5 files changed, 282 insertions(+), 1 deletion(-) create mode 100644 resources/templates/courier-payables/freight-difference-import-template.xlsx diff --git a/app/Http/Controllers/Business/CourierPayableSummaries.php b/app/Http/Controllers/Business/CourierPayableSummaries.php index 58fc94c0..cd6e88e0 100644 --- a/app/Http/Controllers/Business/CourierPayableSummaries.php +++ b/app/Http/Controllers/Business/CourierPayableSummaries.php @@ -8,6 +8,7 @@ use Illuminate\Http\RedirectResponse; use Illuminate\Http\Request; use Illuminate\Routing\Controller; use RuntimeException; +use Symfony\Component\HttpFoundation\BinaryFileResponse; use Symfony\Component\HttpFoundation\StreamedResponse; class CourierPayableSummaries extends Controller @@ -45,6 +46,26 @@ class CourierPayableSummaries extends Controller ); } + public function template(string $summaryPage): BinaryFileResponse + { + $this->authorizePage($summaryPage); + abort_unless($summaryPage === 'freight-difference', 404); + + $path = resource_path('templates/courier-payables/freight-difference-import-template.xlsx'); + abort_unless(is_file($path), 404); + + $response = response()->download($path, 'freight_difference_import_template.xlsx', [ + 'Content-Type' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', + 'Cache-Control' => 'private, no-store', + ]); + + return $response->setContentDisposition( + 'attachment', + '运费差导入模板.xlsx', + 'freight_difference_import_template.xlsx', + ); + } + public function export(string $summaryPage): StreamedResponse|RedirectResponse { $this->authorizePage($summaryPage); diff --git a/resources/templates/courier-payables/freight-difference-import-template.xlsx b/resources/templates/courier-payables/freight-difference-import-template.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..aab26937b83d3a1e064d581e180d9088c0b6b089 GIT binary patch literal 54410 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
;AMv?lII<-b9@;PG$2K{ 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 literal 0 HcmV?d00001 diff --git a/resources/views/business/pages/courier-payables/summary-table.blade.php b/resources/views/business/pages/courier-payables/summary-table.blade.php index f68c5588..cbd9fbc3 100644 --- a/resources/views/business/pages/courier-payables/summary-table.blade.php +++ b/resources/views/business/pages/courier-payables/summary-table.blade.php @@ -9,6 +9,12 @@ @endif
+ @if ($courierSummaryPage === 'freight-difference') + + @else
@csrf @@ -17,6 +23,7 @@ 导入
+ @endif $courierSummaryRows->total() === 0]) @@ -77,6 +84,61 @@ {{ $courierSummaryRows->onEachSide(1)->links() }} @endif + + @if ($courierSummaryPage === 'freight-difference') + +
+ @csrf +
+
+ 导入运费差 + 支持 .xlsx、.xls、.csv,单个文件不超过 10 MB +
+ +
+
+
+ + +
+
+ + @endif + +@if ($courierSummaryPage === 'freight-difference') + +@endif diff --git a/routes/admin.php b/routes/admin.php index 41430275..5e432428 100644 --- a/routes/admin.php +++ b/routes/admin.php @@ -200,6 +200,9 @@ Route::prefix('workspace/courier-payables/courier-surcharge') Route::post('workspace/courier-payables/{summaryPage}/summary-import', [CourierPayableSummaries::class, 'import']) ->where('summaryPage', 'freight-difference|other-surcharge-summary') ->name('business.courier-payable-summaries.import'); +Route::get('workspace/courier-payables/{summaryPage}/summary-template', [CourierPayableSummaries::class, 'template']) + ->where('summaryPage', 'freight-difference') + ->name('business.courier-payable-summaries.template'); Route::get('workspace/courier-payables/{summaryPage}/summary-export', [CourierPayableSummaries::class, 'export']) ->where('summaryPage', 'freight-difference|other-surcharge-summary') ->name('business.courier-payable-summaries.export'); diff --git a/tests/Feature/Business/CourierPayableSummaryPagesTest.php b/tests/Feature/Business/CourierPayableSummaryPagesTest.php index b8f27e3b..4e7ebe41 100644 --- a/tests/Feature/Business/CourierPayableSummaryPagesTest.php +++ b/tests/Feature/Business/CourierPayableSummaryPagesTest.php @@ -6,6 +6,8 @@ use App\Business\CourierPayableSummaryStore; use App\Models\Auth\Permission; use Illuminate\Http\UploadedFile; use Illuminate\Support\Facades\Storage; +use PhpOffice\PhpSpreadsheet\Cell\DataType; +use PhpOffice\PhpSpreadsheet\IOFactory; use Tests\Feature\FeatureTestCase; class CourierPayableSummaryPagesTest extends FeatureTestCase @@ -49,6 +51,134 @@ class CourierPayableSummaryPagesTest extends FeatureTestCase } } + public function test_freight_difference_import_dialog_downloads_the_supplied_xlsx_template(): void + { + $pageResponse = $this->loginAs()->get(route('business.pages.show', [ + 'section' => 'courier-payables', + 'page' => 'freight-difference', + ])); + + $pageResponse + ->assertOk() + ->assertSee('data-courier-summary-import-dialog', false) + ->assertSeeText('下载模板') + ->assertSee(route('business.courier-payable-summaries.template', [ + 'summaryPage' => 'freight-difference', + ]), false); + + $templateResponse = $this->loginAs()->get(route('business.courier-payable-summaries.template', [ + 'summaryPage' => 'freight-difference', + ])); + + $templateResponse + ->assertOk() + ->assertDownload('freight_difference_import_template.xlsx') + ->assertHeader('content-type', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'); + $this->assertStringContainsString( + "filename*=utf-8''" . rawurlencode('运费差导入模板.xlsx'), + (string) $templateResponse->headers->get('Content-Disposition'), + ); + + $spreadsheet = IOFactory::load(resource_path('templates/courier-payables/freight-difference-import-template.xlsx')); + $worksheet = $spreadsheet->getActiveSheet(); + + $this->assertSame([ + '负责人', + '快递公司', + '快递单号', + '店铺', + 'id', + '条码', + '交易单号', + '差异(结算运费-提供成本运费)', + '是否配件', + '配件成品条码', + ], $worksheet->rangeToArray('A1:J1', null, false, false)[0]); + $this->assertSame('FFFFC000', $worksheet->getStyle('D1')->getFill()->getStartColor()->getARGB()); + $this->assertSame('FFFFC000', $worksheet->getStyle('E1')->getFill()->getStartColor()->getARGB()); + $this->assertSame('FFFFC000', $worksheet->getStyle('G1')->getFill()->getStartColor()->getARGB()); + $this->assertSame('@', $worksheet->getStyle('E2')->getNumberFormat()->getFormatCode()); + $this->assertSame('@', $worksheet->getStyle('G2')->getNumberFormat()->getFormatCode()); + $this->assertSame('', (string) $worksheet->getCell('A2')->getValue()); + + $spreadsheet->disconnectWorksheets(); + } + + public function test_other_surcharge_page_does_not_offer_the_freight_difference_template(): void + { + $this->loginAs()->get(route('business.pages.show', [ + 'section' => 'courier-payables', + 'page' => 'other-surcharge-summary', + ])) + ->assertOk() + ->assertDontSeeText('下载模板') + ->assertDontSee('data-courier-summary-import-dialog', false); + } + + public function test_completed_freight_difference_template_preserves_long_identifiers_on_import(): void + { + $spreadsheet = IOFactory::load(resource_path('templates/courier-payables/freight-difference-import-template.xlsx')); + $worksheet = $spreadsheet->getActiveSheet(); + $worksheet->fromArray([ + '苏木', + '测试快递', + 'YT7632543323146', + '测试店铺', + '855226246304', + 'DNZ0117123N1210V01', + '3312228147193110069', + 0.1827, + '成品', + '', + ], null, 'A2'); + $worksheet->getCell('E2')->setValueExplicit('855226246304', DataType::TYPE_STRING); + $worksheet->getCell('G2')->setValueExplicit('3312228147193110069', DataType::TYPE_STRING); + + $path = tempnam(sys_get_temp_dir(), 'freight-template-'); + $this->assertNotFalse($path); + $xlsxPath = $path . '.xlsx'; + + try { + IOFactory::createWriter($spreadsheet, 'Xlsx')->save($xlsxPath); + $spreadsheet->disconnectWorksheets(); + + $file = new UploadedFile( + $xlsxPath, + '运费差导入模板.xlsx', + 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', + null, + true, + ); + + $this->loginAs()->post(route('business.courier-payable-summaries.import', [ + 'summaryPage' => 'freight-difference', + ]), ['import' => $file]) + ->assertRedirect(route('business.pages.show', [ + 'section' => 'courier-payables', + 'page' => 'freight-difference', + ])) + ->assertSessionHas('success', '导入完成:1 条数据,10 个字段。'); + + $snapshot = app(CourierPayableSummaryStore::class)->snapshot( + (int) $this->company->id, + 'freight-difference', + ); + $this->assertSame('855226246304', $snapshot['rows'][0][4]); + $this->assertSame('3312228147193110069', $snapshot['rows'][0][6]); + $this->assertSame('0.1827', $snapshot['rows'][0][7]); + } finally { + if (isset($spreadsheet)) { + $spreadsheet->disconnectWorksheets(); + } + if ($path !== false && is_file($path)) { + unlink($path); + } + if (isset($xlsxPath) && is_file($xlsxPath)) { + unlink($xlsxPath); + } + } + } + public function test_import_replaces_the_page_snapshot_and_export_returns_all_rows(): void { $file = UploadedFile::fake()->createWithContent( @@ -104,5 +234,9 @@ class CourierPayableSummaryPagesTest extends FeatureTestCase $this->loginAs()->get(route('business.courier-payable-summaries.export', [ 'summaryPage' => 'freight-difference', ]))->assertForbidden(); + + $this->loginAs()->get(route('business.courier-payable-summaries.template', [ + 'summaryPage' => 'freight-difference', + ]))->assertForbidden(); } }