diff --git a/app/Http/Controllers/Business/Pages.php b/app/Http/Controllers/Business/Pages.php index 907d6cc6..e0e96ec9 100644 --- a/app/Http/Controllers/Business/Pages.php +++ b/app/Http/Controllers/Business/Pages.php @@ -324,6 +324,15 @@ class Pages extends Controller abort_if(empty($sectionConfig), 403, '当前账号没有该页面权限。'); + // Keep the old direct URL working after settlement becomes a tab. + if ($section === 'courier-payables' && $page === 'courier-surcharge-settlement') { + return redirect()->route('business.pages.show', array_merge(request()->query(), [ + 'section' => $section, + 'page' => 'courier-surcharge', + 'tab' => 'settlement', + ])); + } + $pages = collect($sectionConfig['pages'] ?? []); if ($pages->isEmpty()) { @@ -390,6 +399,18 @@ class Pages extends Controller } if ($tab === null) { + if ($page === 'courier-surcharge') { + $activeTab = $tabs->first(); + + return view('business.pages.show', $this->viewData( + $sectionConfig, + $pageConfig, + $tabs, + $activeTab, + $this->resolveContent($page, $activeTab['slug']), + )); + } + return $this->redirectToPage($sectionConfig, $pageConfig); } @@ -2645,7 +2666,7 @@ class Pages extends Controller 'online-daifa-price' => $this->contentForOnlineDaifaPrice(), 'product-costs' => $this->contentForProductCosts(), 'financial-analysis' => $this->contentForFinancialAnalysis(), - 'courier-surcharge' => $this->contentForCourierSurcharge(), + 'courier-surcharge' => $this->contentForCourierSurcharge($tab), 'freight-difference', 'other-surcharge-summary', 'return-fee' => $this->contentForCourierPayableSummary($page), 'shipping-data' => $this->contentForShippingData(), 'return-pickup-management' => $this->contentForReturnPickupManagement(), @@ -3644,24 +3665,26 @@ class Pages extends Controller ]; } - protected function contentForCourierSurcharge(): array + protected function contentForCourierSurcharge(?string $tab = null): array { $clean = static fn (mixed $value, int $length = 60): string => mb_substr(trim((string) $value), 0, $length); + $quoteInput = $tab === 'settlement' ? [] : request()->query(); $filters = [ - 'keyword' => $clean(request('keyword', ''), 40), - 'courier' => $clean(request('courier', ''), 40), - 'type' => $clean(request('type', ''), 40), - 'mode' => $clean(request('mode', ''), 40), - 'scope' => $clean(request('scope', ''), 20), - 'reconciler' => $clean(request('reconciler', ''), 40), - 'supplier' => $clean(request('supplier', ''), 191), - 'status' => $clean(request('status', ''), 20), + 'keyword' => $clean($quoteInput['keyword'] ?? '', 40), + 'courier' => $clean($quoteInput['courier'] ?? '', 40), + 'type' => $clean($quoteInput['type'] ?? '', 40), + 'mode' => $clean($quoteInput['mode'] ?? '', 40), + 'scope' => $clean($quoteInput['scope'] ?? '', 20), + 'reconciler' => $clean($quoteInput['reconciler'] ?? '', 40), + 'supplier' => $clean($quoteInput['supplier'] ?? '', 191), + 'status' => $clean($quoteInput['status'] ?? '', 20), ]; $data = $this->courierSurchargeQuotes->pageData($filters); $auditReady = $this->courierSurchargeAudits->ready(); return [ - 'view' => 'business.pages.courier-payables.courier-surcharge', + 'view' => 'business.pages.courier-payables.courier-surcharge-workspace', + 'courierSurchargeActiveTab' => $tab ?? 'quotes', 'courierSurchargeRows' => $data['rows'], 'courierSurchargeFilters' => $filters, 'courierSurchargeSummary' => $data['summary'], diff --git a/config/business_navigation.php b/config/business_navigation.php index bed51c82..37e03707 100644 --- a/config/business_navigation.php +++ b/config/business_navigation.php @@ -712,7 +712,14 @@ $navigation = [ ['slug' => 'compensation-details', 'title' => '赔偿明细'], ['slug' => 'advance-details', 'title' => '借支明细'], ['slug' => 'other-adjustments', 'title' => '其他扣款补款'], - ['slug' => 'courier-surcharge', 'title' => '附加费报价维护'], + [ + 'slug' => 'courier-surcharge', + 'title' => '附加费报价维护', + 'tabs' => [ + ['slug' => 'quotes', 'title' => '附加费报价'], + ['slug' => 'settlement', 'title' => '附加费结算'], + ], + ], ['slug' => 'payable-cloud-warehouse-vehicle-fee', 'title' => '应付云仓车费'], ['slug' => 'courier-payables-report', 'title' => '快递应付表'], ['slug' => 'freight-difference', 'title' => '运费差'], diff --git a/resources/views/business/pages/courier-payables/courier-surcharge-settlement.blade.php b/resources/views/business/pages/courier-payables/courier-surcharge-settlement.blade.php new file mode 100644 index 00000000..20069ec9 --- /dev/null +++ b/resources/views/business/pages/courier-payables/courier-surcharge-settlement.blade.php @@ -0,0 +1,201 @@ +@php + $rows = $courierSurchargeSettlementRows ?? collect(); + $columns = [ + ['key' => 'courier_name', 'label' => '快递名称', 'fixed' => 'true'], + ['key' => 'waybill', 'label' => '单号'], + ['key' => 'platform_product_id', 'label' => '平台商品ID'], + ['key' => 'product_code', 'label' => '商品编码'], + ['key' => 'shop_name', 'label' => '店铺名称'], + ['key' => 'online_order_no', 'label' => '线上订单号'], + ['key' => 'length', 'label' => '长'], + ['key' => 'width', 'label' => '宽'], + ['key' => 'height', 'label' => '高'], + ['key' => 'volume', 'label' => '体积'], + ['key' => 'inspection_type', 'label' => '查件类型'], + ['key' => 'inspection_original', 'label' => '查件原件'], + ['key' => 'return_waybill_no', 'label' => '退回单号'], + ['key' => 'settlement_weight', 'label' => '结算重量'], + ['key' => 'settlement_amount', 'label' => '结算金额', 'fixed' => 'end'], + ]; + $filterValue = static fn (string $key): string => trim((string) request()->query($key, '')); + $displayValue = static function (mixed $value, string $key): string { + if ($value === null || $value === '') { + return '—'; + } + + if ($key === 'settlement_amount' && is_numeric($value)) { + return number_format((float) $value, 2, '.', ''); + } + + return (string) $value; + }; +@endphp + +
+ + +
+ +
等待接入结算数据;确认数据来源后,将按附加费报价规则计算。
+
+ +
+
附加费结算
结算标准读取附加费报价维护
+
当前明细
{{ $rows->count() }}
+
结算金额
待接入
+
数据状态
待确认来源
+
+ +
+
+
+
+
+
+
+
重置
+
+ +
+
附加费结算明细
快递名称和结算金额固定显示,其余字段可在“列设置”中调整。
列设置按当前用户和本页面保存
+
当前筛选结果:{{ $rows->count() }} 条报价匹配和金额计算将在确认数据来源后接入
+
+ + + @foreach ($columns as $column) + + @endforeach + + + @forelse ($rows as $row) + + @foreach ($columns as $column) + + @endforeach + + @empty + + @endforelse + +
{{ $column['label'] }}
{{ $displayValue(data_get($row, $column['key']), $column['key']) }}
页面已就绪,等待接入附加费结算数据。
+
+
+
diff --git a/resources/views/business/pages/courier-payables/courier-surcharge-workspace.blade.php b/resources/views/business/pages/courier-payables/courier-surcharge-workspace.blade.php new file mode 100644 index 00000000..41ce8674 --- /dev/null +++ b/resources/views/business/pages/courier-payables/courier-surcharge-workspace.blade.php @@ -0,0 +1,63 @@ +@php + $surchargeTabUrls = collect(['quotes', 'settlement'])->mapWithKeys(fn ($tab) => [ + $tab => route('business.pages.show', ['section' => 'courier-payables', 'page' => 'courier-surcharge', 'tab' => $tab]), + ])->all(); +@endphp +
+ + +
+ + diff --git a/tests/Feature/Business/CourierSurchargePageTest.php b/tests/Feature/Business/CourierSurchargePageTest.php index 133c5c77..1614bf87 100644 --- a/tests/Feature/Business/CourierSurchargePageTest.php +++ b/tests/Feature/Business/CourierSurchargePageTest.php @@ -31,7 +31,8 @@ class CourierSurchargePageTest extends FeatureTestCase 'page' => 'courier-surcharge', ])) ->assertOk() - ->assertSeeText('附加费报价维护') + ->assertSeeText('附加费报价') + ->assertSee('aria-label="附加费报价维护"', false) ->assertSeeText('正式维护数据') ->assertSeeText('报价规则列表') ->assertSeeText('管理附加费类型') diff --git a/tests/Feature/Business/CourierSurchargeSettlementPageTest.php b/tests/Feature/Business/CourierSurchargeSettlementPageTest.php new file mode 100644 index 00000000..8fe98792 --- /dev/null +++ b/tests/Feature/Business/CourierSurchargeSettlementPageTest.php @@ -0,0 +1,93 @@ +user->attachPermission(Permission::where('name', 'read-admin-panel')->firstOrFail()); + + $this->loginAs()->get(route('business.pages.show', [ + 'section' => 'courier-payables', + 'page' => 'courier-surcharge', + 'tab' => 'settlement', + ]))->assertOk() + ->assertSee('data-surcharge-panel="quotes" hidden', false) + ->assertSeeText('附加费结算') + ->assertSeeText('页面已就绪,等待接入附加费结算数据。') + ->assertSee('data-finance-table-name="courier-surcharge-settlement"', false) + ->assertSee('data-finance-fixed="true"', false) + ->assertSee('data-finance-fixed="end"', false) + ->assertSeeText('快递名称') + ->assertSeeText('平台商品ID') + ->assertSeeText('查件原件') + ->assertSeeText('退回单号') + ->assertSeeText('结算重量') + ->assertSeeText('结算金额'); + } + + public function test_settlement_filters_are_preserved_in_the_form(): void + { + $this->user->attachPermission(Permission::where('name', 'read-admin-panel')->firstOrFail()); + + $this->loginAs()->get(route('business.pages.show', [ + 'section' => 'courier-payables', + 'page' => 'courier-surcharge', + 'tab' => 'settlement', + 'courier_name' => '测试快递', + 'waybill' => '001234', + 'shop_name' => '测试店铺', + 'online_order_no' => 'SO-001', + 'status' => '待接入', + ]))->assertOk() + ->assertSee('value="测试快递"', false) + ->assertSee('value="001234"', false) + ->assertSee('value="测试店铺"', false) + ->assertSee('value="SO-001"', false) + ->assertSee('value="待接入" selected', false) + ->assertViewHas('content', fn (array $content) => $content['courierSurchargeFilters']['status'] === ''); + } + + public function test_quote_page_exposes_quote_and_settlement_tabs(): void + { + $this->user->attachPermission(Permission::where('name', 'read-admin-panel')->firstOrFail()); + + $this->loginAs()->get(route('business.pages.show', [ + 'section' => 'courier-payables', + 'page' => 'courier-surcharge', + ]))->assertOk() + ->assertSeeText('附加费报价') + ->assertSeeText('附加费结算') + ->assertSee('data-surcharge-panel="settlement" hidden', false) + ->assertSee(route('business.pages.show', [ + 'section' => 'courier-payables', + 'page' => 'courier-surcharge', + 'tab' => 'quotes', + ]), false) + ->assertSee(route('business.pages.show', [ + 'section' => 'courier-payables', + 'page' => 'courier-surcharge', + 'tab' => 'settlement', + ]), false); + } + + public function test_old_settlement_page_url_redirects_to_settlement_tab(): void + { + $this->user->attachPermission(Permission::where('name', 'read-admin-panel')->firstOrFail()); + + $this->loginAs()->get(route('business.pages.show', [ + 'section' => 'courier-payables', + 'page' => 'courier-surcharge-settlement', + 'waybill' => '0000123456789', + ]))->assertRedirect(route('business.pages.show', [ + 'section' => 'courier-payables', + 'page' => 'courier-surcharge', + 'tab' => 'settlement', + 'waybill' => '0000123456789', + ])); + } +}