增加其他附加费导入模板 #211
@ -13,6 +13,19 @@ use Symfony\Component\HttpFoundation\StreamedResponse;
|
||||
|
||||
class CourierPayableSummaries extends Controller
|
||||
{
|
||||
private const IMPORT_TEMPLATES = [
|
||||
'freight-difference' => [
|
||||
'path' => 'templates/courier-payables/freight-difference-import-template.xlsx',
|
||||
'ascii_name' => 'freight_difference_import_template.xlsx',
|
||||
'download_name' => '运费差导入模板.xlsx',
|
||||
],
|
||||
'other-surcharge-summary' => [
|
||||
'path' => 'templates/courier-payables/other-surcharge-import-template.xlsx',
|
||||
'ascii_name' => 'other_surcharge_import_template.xlsx',
|
||||
'download_name' => '其他附加费导入模板.xlsx',
|
||||
],
|
||||
];
|
||||
|
||||
public function __construct(private readonly CourierPayableSummaryStore $store)
|
||||
{
|
||||
$this->middleware('auth');
|
||||
@ -49,20 +62,21 @@ class CourierPayableSummaries extends Controller
|
||||
public function template(string $summaryPage): BinaryFileResponse
|
||||
{
|
||||
$this->authorizePage($summaryPage);
|
||||
abort_unless($summaryPage === 'freight-difference', 404);
|
||||
$template = self::IMPORT_TEMPLATES[$summaryPage] ?? null;
|
||||
abort_unless(is_array($template), 404);
|
||||
|
||||
$path = resource_path('templates/courier-payables/freight-difference-import-template.xlsx');
|
||||
$path = resource_path($template['path']);
|
||||
abort_unless(is_file($path), 404);
|
||||
|
||||
$response = response()->download($path, 'freight_difference_import_template.xlsx', [
|
||||
$response = response()->download($path, $template['ascii_name'], [
|
||||
'Content-Type' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
|
||||
'Cache-Control' => 'private, no-store',
|
||||
]);
|
||||
|
||||
return $response->setContentDisposition(
|
||||
'attachment',
|
||||
'运费差导入模板.xlsx',
|
||||
'freight_difference_import_template.xlsx',
|
||||
$template['download_name'],
|
||||
$template['ascii_name'],
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
Binary file not shown.
@ -1,3 +1,18 @@
|
||||
@php
|
||||
$courierSummaryImportTemplate = [
|
||||
'freight-difference' => [
|
||||
'dialog_title' => '导入运费差',
|
||||
'template_name' => '运费差导入模板',
|
||||
'field_count' => 11,
|
||||
],
|
||||
'other-surcharge-summary' => [
|
||||
'dialog_title' => '导入其他附加费汇总',
|
||||
'template_name' => '其他附加费导入模板',
|
||||
'field_count' => 11,
|
||||
],
|
||||
][$courierSummaryPage] ?? null;
|
||||
@endphp
|
||||
|
||||
<section class="courier-summary" data-courier-payable-summary="{{ $courierSummaryPage }}" aria-label="{{ $courierSummaryTitle }}">
|
||||
<header class="courier-summary__toolbar">
|
||||
<div class="courier-summary__heading">
|
||||
@ -9,20 +24,11 @@
|
||||
@endif
|
||||
</div>
|
||||
<div class="courier-summary__actions">
|
||||
@if ($courierSummaryPage === 'freight-difference')
|
||||
@if ($courierSummaryImportTemplate)
|
||||
<button type="button" class="courier-summary__button" data-courier-summary-import-open>
|
||||
<span class="material-icons-outlined" aria-hidden="true">upload_file</span>
|
||||
<span>导入</span>
|
||||
</button>
|
||||
@else
|
||||
<form method="POST" enctype="multipart/form-data" action="{{ route('business.courier-payable-summaries.import', ['summaryPage' => $courierSummaryPage]) }}">
|
||||
@csrf
|
||||
<input id="courier-summary-import-{{ $courierSummaryPage }}" type="file" name="import" accept=".xlsx,.xls,.csv" required hidden onchange="this.form.submit()">
|
||||
<label class="courier-summary__button" for="courier-summary-import-{{ $courierSummaryPage }}">
|
||||
<span class="material-icons-outlined" aria-hidden="true">upload_file</span>
|
||||
<span>导入</span>
|
||||
</label>
|
||||
</form>
|
||||
@endif
|
||||
<a
|
||||
href="{{ route('business.courier-payable-summaries.export', ['summaryPage' => $courierSummaryPage]) }}"
|
||||
@ -85,7 +91,7 @@
|
||||
</footer>
|
||||
@endif
|
||||
|
||||
@if ($courierSummaryPage === 'freight-difference')
|
||||
@if ($courierSummaryImportTemplate)
|
||||
<dialog class="courier-summary__import-dialog" data-courier-summary-import-dialog aria-labelledby="courier-summary-import-title">
|
||||
<form
|
||||
method="POST"
|
||||
@ -96,7 +102,7 @@
|
||||
@csrf
|
||||
<header class="courier-summary__import-header">
|
||||
<div>
|
||||
<strong id="courier-summary-import-title">导入运费差</strong>
|
||||
<strong id="courier-summary-import-title">{{ $courierSummaryImportTemplate['dialog_title'] }}</strong>
|
||||
<span>支持 .xlsx、.xls、.csv,单个文件不超过 10 MB</span>
|
||||
</div>
|
||||
<button type="button" class="courier-summary__icon-button" data-courier-summary-import-close aria-label="关闭导入窗口" title="关闭">
|
||||
@ -107,8 +113,8 @@
|
||||
<div class="courier-summary__template-row">
|
||||
<span class="material-icons-outlined" aria-hidden="true">description</span>
|
||||
<div>
|
||||
<strong>运费差导入模板</strong>
|
||||
<span>.xlsx · 11 个字段</span>
|
||||
<strong>{{ $courierSummaryImportTemplate['template_name'] }}</strong>
|
||||
<span>.xlsx · {{ $courierSummaryImportTemplate['field_count'] }} 个字段</span>
|
||||
</div>
|
||||
<a class="courier-summary__button" href="{{ route('business.courier-payable-summaries.template', ['summaryPage' => $courierSummaryPage]) }}">
|
||||
<span class="material-icons-outlined" aria-hidden="true">download</span>
|
||||
@ -191,10 +197,10 @@
|
||||
@media (max-width:700px) { .courier-summary__toolbar { align-items:flex-start; flex-direction:column; } .courier-summary__actions { width:100%; } .courier-summary__template-row { grid-template-columns:28px minmax(0,1fr); } .courier-summary__template-row .courier-summary__button { grid-column:1/-1; justify-content:center; } }
|
||||
</style>
|
||||
|
||||
@if ($courierSummaryPage === 'freight-difference')
|
||||
@if ($courierSummaryImportTemplate)
|
||||
<script>
|
||||
(() => {
|
||||
const root = document.querySelector('[data-courier-payable-summary="freight-difference"]');
|
||||
const root = document.querySelector('[data-courier-payable-summary="{{ $courierSummaryPage }}"]');
|
||||
if (!root) return;
|
||||
|
||||
const dialog = root.querySelector('[data-courier-summary-import-dialog]');
|
||||
|
||||
@ -201,7 +201,7 @@ Route::post('workspace/courier-payables/{summaryPage}/summary-import', [CourierP
|
||||
->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')
|
||||
->where('summaryPage', 'freight-difference|other-surcharge-summary')
|
||||
->name('business.courier-payable-summaries.template');
|
||||
Route::get('workspace/courier-payables/{summaryPage}/summary-export', [CourierPayableSummaries::class, 'export'])
|
||||
->where('summaryPage', 'freight-difference|other-surcharge-summary')
|
||||
|
||||
@ -106,15 +106,64 @@ class CourierPayableSummaryPagesTest extends FeatureTestCase
|
||||
$spreadsheet->disconnectWorksheets();
|
||||
}
|
||||
|
||||
public function test_other_surcharge_page_does_not_offer_the_freight_difference_template(): void
|
||||
public function test_other_surcharge_import_dialog_downloads_the_supplied_xlsx_template(): void
|
||||
{
|
||||
$this->loginAs()->get(route('business.pages.show', [
|
||||
$pageResponse = $this->loginAs()->get(route('business.pages.show', [
|
||||
'section' => 'courier-payables',
|
||||
'page' => 'other-surcharge-summary',
|
||||
]))
|
||||
]));
|
||||
|
||||
$pageResponse
|
||||
->assertOk()
|
||||
->assertDontSeeText('下载模板')
|
||||
->assertDontSee('data-courier-summary-import-dialog', false);
|
||||
->assertSee('data-courier-summary-import-dialog', false)
|
||||
->assertSeeText('导入其他附加费汇总')
|
||||
->assertSeeText('其他附加费导入模板')
|
||||
->assertSeeText('.xlsx · 11 个字段')
|
||||
->assertSeeText('下载模板')
|
||||
->assertSee(route('business.courier-payable-summaries.template', [
|
||||
'summaryPage' => 'other-surcharge-summary',
|
||||
]), false);
|
||||
|
||||
$templateResponse = $this->loginAs()->get(route('business.courier-payable-summaries.template', [
|
||||
'summaryPage' => 'other-surcharge-summary',
|
||||
]));
|
||||
|
||||
$templateResponse
|
||||
->assertOk()
|
||||
->assertDownload('other_surcharge_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/other-surcharge-import-template.xlsx'));
|
||||
$worksheet = $spreadsheet->getActiveSheet();
|
||||
|
||||
$this->assertSame([
|
||||
'日期',
|
||||
'负责人',
|
||||
'快递公司',
|
||||
'快递单号',
|
||||
'商品ID',
|
||||
'条码',
|
||||
'店铺',
|
||||
'交易单号',
|
||||
'金额',
|
||||
'备注',
|
||||
'成品条码',
|
||||
], $worksheet->rangeToArray('A1:K1', null, false, false)[0]);
|
||||
$this->assertSame('@', $worksheet->getStyle('A2')->getNumberFormat()->getFormatCode());
|
||||
$this->assertSame('@', $worksheet->getStyle('D2')->getNumberFormat()->getFormatCode());
|
||||
$this->assertSame('@', $worksheet->getStyle('E2')->getNumberFormat()->getFormatCode());
|
||||
$this->assertSame('@', $worksheet->getStyle('F2')->getNumberFormat()->getFormatCode());
|
||||
$this->assertSame('@', $worksheet->getStyle('H2')->getNumberFormat()->getFormatCode());
|
||||
$this->assertSame('0.00########', $worksheet->getStyle('I2')->getNumberFormat()->getFormatCode());
|
||||
$this->assertSame('@', $worksheet->getStyle('K2')->getNumberFormat()->getFormatCode());
|
||||
$this->assertSame('', (string) $worksheet->getCell('A2')->getValue());
|
||||
$this->assertSame('', (string) $worksheet->getCell('K18')->getValue());
|
||||
|
||||
$spreadsheet->disconnectWorksheets();
|
||||
}
|
||||
|
||||
public function test_completed_freight_difference_template_preserves_long_identifiers_on_import(): void
|
||||
@ -183,6 +232,73 @@ class CourierPayableSummaryPagesTest extends FeatureTestCase
|
||||
}
|
||||
}
|
||||
|
||||
public function test_completed_other_surcharge_template_preserves_long_identifiers_on_import(): void
|
||||
{
|
||||
$spreadsheet = IOFactory::load(resource_path('templates/courier-payables/other-surcharge-import-template.xlsx'));
|
||||
$worksheet = $spreadsheet->getActiveSheet();
|
||||
$worksheet->fromArray([
|
||||
'2026-07',
|
||||
'苏木',
|
||||
'测试快递',
|
||||
'SF5199125637478',
|
||||
'6041543429417',
|
||||
'SJ038017N1410V01',
|
||||
'测试店铺',
|
||||
'5110751415866048404',
|
||||
-60,
|
||||
'安装费',
|
||||
'CP001',
|
||||
], null, 'A2');
|
||||
$worksheet->getCell('E2')->setValueExplicit('6041543429417', DataType::TYPE_STRING);
|
||||
$worksheet->getCell('H2')->setValueExplicit('5110751415866048404', DataType::TYPE_STRING);
|
||||
|
||||
$path = tempnam(sys_get_temp_dir(), 'other-surcharge-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' => 'other-surcharge-summary',
|
||||
]), ['import' => $file])
|
||||
->assertRedirect(route('business.pages.show', [
|
||||
'section' => 'courier-payables',
|
||||
'page' => 'other-surcharge-summary',
|
||||
]))
|
||||
->assertSessionHas('success', '导入完成:1 条数据,11 个字段。');
|
||||
|
||||
$snapshot = app(CourierPayableSummaryStore::class)->snapshot(
|
||||
(int) $this->company->id,
|
||||
'other-surcharge-summary',
|
||||
);
|
||||
$this->assertSame('2026-07', $snapshot['rows'][0][0]);
|
||||
$this->assertSame('6041543429417', $snapshot['rows'][0][4]);
|
||||
$this->assertSame('5110751415866048404', $snapshot['rows'][0][7]);
|
||||
$this->assertSame('-60', $snapshot['rows'][0][8]);
|
||||
$this->assertSame('安装费', $snapshot['rows'][0][9]);
|
||||
} 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(
|
||||
@ -242,5 +358,9 @@ class CourierPayableSummaryPagesTest extends FeatureTestCase
|
||||
$this->loginAs()->get(route('business.courier-payable-summaries.template', [
|
||||
'summaryPage' => 'freight-difference',
|
||||
]))->assertForbidden();
|
||||
|
||||
$this->loginAs()->get(route('business.courier-payable-summaries.template', [
|
||||
'summaryPage' => 'other-surcharge-summary',
|
||||
]))->assertForbidden();
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user