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 00000000..aab26937 Binary files /dev/null and b/resources/templates/courier-payables/freight-difference-import-template.xlsx differ 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(); } }