CaiWuXiTong/tests/Feature/Business/CourierSurchargeSettlementPageTest.php

363 lines
17 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
namespace Tests\Feature\Business;
use App\Models\Auth\Permission;
use Illuminate\Http\UploadedFile;
use Mockery;
use Modules\EcommerceFinance\Repositories\CourierSurchargeSettlementMirrorRepository;
use PhpOffice\PhpSpreadsheet\IOFactory;
use PhpOffice\PhpSpreadsheet\RichText\RichText;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\Writer\Xlsx;
use Tests\Feature\FeatureTestCase;
class CourierSurchargeSettlementPageTest extends FeatureTestCase
{
public function test_page_renders_requested_settlement_columns_and_mirror_state(): 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',
]))->assertOk()
->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('出库时间')
->assertSeeText('平台商品ID')
->assertSeeText('查件原因')
->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-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['courierSurchargeSettlementFilters']['status'] === '已计算');
}
public function test_quote_page_only_exposes_quote_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',
]))->assertOk()
->assertSeeText('附加费报价')
->assertDontSee(route('business.pages.show', [
'section' => 'courier-payables',
'page' => 'courier-surcharge',
'tab' => 'settlement',
]), false)
->assertDontSee('data-surcharge-panel="settlement"', false)
->assertSee('data-surcharge-panel="quotes"', false);
}
public function test_old_settlement_tab_url_redirects_to_standalone_page(): 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',
'waybill' => '0000123456789',
]))->assertRedirect(route('business.pages.show', [
'section' => 'courier-payables',
'page' => 'courier-surcharge-settlement',
'waybill' => '0000123456789',
]));
}
public function test_settlement_page_renders_as_courier_payables_page(): 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',
]))->assertOk()
->assertSeeText('附加费结算')
->assertSee('data-finance-table-name="courier-surcharge-settlement"', false)
->assertSee('value="0000123456789"', false);
$this->loginAs()->get(route('business.pages.show', [
'section' => 'courier-payables',
]))->assertOk()
->assertSeeText('附加费结算');
}
public function test_settlement_rows_support_click_highlight(): void
{
$this->user->attachPermission(Permission::where('name', 'read-admin-panel')->firstOrFail());
$repository = Mockery::mock(CourierSurchargeSettlementMirrorRepository::class);
$repository->shouldReceive('available')->andReturn(true);
$repository->shouldReceive('ready')->andReturn(true);
$repository->shouldReceive('paginate')->andReturn([
'data' => [[
'courier_name' => '曹县德邦',
'shipped_at' => '2026-10-12 18:38:33',
'waybill' => 'DPK317248316615',
'platform_product_id' => '993815011271',
'product_code' => 'MKHDNZ0409260601380',
'shop_name' => '拼多多-HX旗舰店101',
'online_order_no' => '260912-325069063762746',
'length' => 168,
'width' => 30,
'height' => 20,
'volume' => 100800,
'inspection_type' => null,
'inspection_reason' => null,
'return_waybill_no' => null,
'settlement_weight' => null,
'settlement_amount' => 8,
'surcharge_type' => '超长费',
]],
'total' => 1,
'has_more' => false,
'summary' => ['count' => 1, 'settlement_amount' => 8.0],
'sync' => ['code' => 'fresh', 'last_succeeded_at' => '2026-10-13 06:31:34'],
'state' => ['code' => 'fresh', 'last_succeeded_at' => '2026-10-13 06:31:34'],
]);
$this->app->instance(CourierSurchargeSettlementMirrorRepository::class, $repository);
$this->loginAs()->get(route('business.pages.show', [
'section' => 'courier-payables',
'page' => 'courier-surcharge-settlement',
]))->assertOk()
->assertSee('data-settlement-row', false)
->assertSee('is-clickable', false)
->assertSee('is-active', false)
->assertSeeText('点击行可高亮标记')
->assertSeeText('曹县德邦')
->assertSeeText('超长费');
}
public function test_settlement_export_streams_filtered_rows_as_xlsx(): void
{
$this->user->attachPermission(Permission::where('name', 'read-admin-panel')->firstOrFail());
$repository = Mockery::mock(CourierSurchargeSettlementMirrorRepository::class);
$repository->shouldReceive('exportRows')
->once()
->withArgs(static fn (array $filters): bool => ($filters['courier_name'] ?? '') === '曹县德邦')
->andReturn((function (): \Generator {
yield (object) [
'courier_name' => '曹县德邦',
'waybill' => 'DPK317249507921',
'shipped_at' => '2026-10-09 08:39:40',
'platform_product_id' => null,
'product_code' => 'DNZ032912N887V01',
'shop_name' => '拼多多-满富油家具旗舰店',
'online_order_no' => '261009-325069063762746',
'length' => 194,
'width' => 83,
'height' => 12.5,
'volume' => 201305,
'inspection_type' => null,
'inspection_reason' => null,
'return_waybill_no' => null,
'settlement_weight' => null,
'settlement_amount' => 8,
'surcharge_type' => '超长费',
];
})());
$this->app->instance(CourierSurchargeSettlementMirrorRepository::class, $repository);
$response = $this->loginAs()->get(route('business.courier-surcharge.settlement.export', [
'courier_name' => '曹县德邦',
]));
$response->assertOk();
$this->assertStringContainsString(
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
(string) $response->headers->get('content-type'),
);
$path = tempnam(sys_get_temp_dir(), 'surcharge_settlement_export_');
file_put_contents($path, $response->streamedContent());
$sheet = IOFactory::load($path)->getActiveSheet();
$plain = static fn (mixed $value): mixed => $value instanceof RichText ? $value->getPlainText() : $value;
$headers = [];
foreach ($sheet->getRowIterator(1, 1) as $row) {
foreach ($row->getCellIterator() as $cell) {
$headers[$cell->getColumn()] = $plain($cell->getValue());
}
}
$column = static fn (string $label): string => (string) array_search($label, $headers, true);
$value = static fn (string $label): mixed => $plain($sheet->getCell($column($label) . '2')->getValue());
try {
$this->assertSame('快递名称', $headers['A']);
$this->assertSame('出库时间', $headers['B']);
$this->assertSame('单号', $headers['C']);
$this->assertSame('附加费类型', $headers['Q']);
$this->assertSame('曹县德邦', $value('快递名称'));
$this->assertSame('DPK317249507921', $value('单号'));
$this->assertSame('2026-10-09 08:39:40', $value('出库时间'));
$this->assertSame('DNZ032912N887V01', $value('商品编码'));
$this->assertSame('拼多多-满富油家具旗舰店', $value('店铺名称'));
$this->assertEquals(194, $value('长'));
$this->assertEquals(12.5, $value('高'));
$this->assertEquals(201305, $value('体积'));
$this->assertEquals(8, $value('结算金额'));
$this->assertSame('超长费', $value('附加费类型'));
$this->assertNull($value('查件类型'));
} finally {
unlink($path);
}
}
public function test_settlement_import_streams_decision_workbook(): void
{
$this->user->attachPermission(Permission::where('name', 'read-admin-panel')->firstOrFail());
$repository = Mockery::mock(CourierSurchargeSettlementMirrorRepository::class);
$repository->shouldReceive('decideImportRows')
->once()
->withArgs(static function (array $pairs): bool {
return count($pairs) === 2
&& $pairs[0]['waybill'] === 'DPK317138931411'
&& $pairs[0]['surcharge_type'] === '退回费'
&& $pairs[0]['courier_name'] === '曹县德邦小件'
&& $pairs[0]['amount'] === 10.0
&& $pairs[1]['waybill'] === 'DPK1'
&& $pairs[1]['surcharge_type'] === '超长费'
&& $pairs[1]['courier_name'] === ''
&& $pairs[1]['amount'] === null;
})
->andReturn([
[
'row_number' => 2, 'waybill' => 'DPK317138931411', 'surcharge_type' => '退回费',
'decision' => '正常结', 'reason' => '', 'courier_name' => '曹县德邦小件',
'shipped_at' => '2026-07-09 13:25:51', 'platform_product_id' => '968882879362',
'product_code' => 'YMJ000904N722', 'shop_name' => '拼多多-卓禾住宅家具旗舰店',
'online_order_no' => '260709-594595049040320', 'length' => null, 'width' => null,
'height' => null, 'volume' => null, 'inspection_type' => '扣单',
'inspection_reason' => '买家-不想要', 'return_waybill_no' => 'DPK317138931411',
'settlement_weight' => 2.4, 'settlement_amount' => 20, 'settlement_status' => '已计算',
'evidence' => '查件扣单/买家-不想要;退款确认 2026-07-15 15:00:09;售后退货退款已进仓 2026-07-18 09:53:32;实退 1',
],
[
'row_number' => 3, 'waybill' => 'DPK1', 'surcharge_type' => '超长费',
'decision' => '不结', 'reason' => '未找到超长费结算行:单边未超报价阈值或不在已拉取范围',
'courier_name' => null, 'shipped_at' => null, 'platform_product_id' => null,
'product_code' => null, 'shop_name' => null, 'online_order_no' => null,
'length' => null, 'width' => null, 'height' => null, 'volume' => null,
'inspection_type' => null, 'inspection_reason' => null, 'return_waybill_no' => null,
'settlement_weight' => null, 'settlement_amount' => null, 'settlement_status' => null,
'evidence' => null,
],
]);
$this->app->instance(CourierSurchargeSettlementMirrorRepository::class, $repository);
$spreadsheet = new Spreadsheet();
$spreadsheet->getActiveSheet()->fromArray([
['单号', '附加费类型', '快递名称', '金额'],
['DPK317138931411', '退回费', '曹县德邦小件', 10],
['DPK1', '超长费'],
]);
$importPath = tempnam(sys_get_temp_dir(), 'surcharge_import_');
(new Xlsx($spreadsheet))->save($importPath);
$response = $this->loginAs()->post(route('business.courier-surcharge.settlement.import'), [
'file' => new UploadedFile(
$importPath,
'surcharge-import.xlsx',
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
null,
true,
),
]);
$response->assertOk();
$this->assertStringContainsString(
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
(string) $response->headers->get('content-type'),
);
$resultPath = tempnam(sys_get_temp_dir(), 'surcharge_import_result_');
file_put_contents($resultPath, $response->streamedContent());
$sheet = IOFactory::load($resultPath)->getActiveSheet();
$plain = static fn (mixed $value): mixed => $value instanceof RichText ? $value->getPlainText() : $value;
try {
$this->assertSame('序号', $plain($sheet->getCell('A1')->getValue()));
$this->assertSame('结算结论', $plain($sheet->getCell('D1')->getValue()));
$this->assertSame('不结原因', $plain($sheet->getCell('E1')->getValue()));
$this->assertSame('正常结', $plain($sheet->getCell('D2')->getValue()));
$this->assertSame('DPK317138931411', $plain($sheet->getCell('B2')->getValue()));
$this->assertSame('退回费', $plain($sheet->getCell('C2')->getValue()));
$this->assertSame('导入金额', $plain($sheet->getCell('U1')->getValue()));
$this->assertSame('差异金额', $plain($sheet->getCell('V1')->getValue()));
$this->assertEquals(10, $plain($sheet->getCell('U2')->getValue()));
$this->assertEquals(10, $plain($sheet->getCell('V2')->getValue()));
$this->assertSame('不结', $plain($sheet->getCell('D3')->getValue()));
$this->assertStringContainsString('未找到超长费', (string) $plain($sheet->getCell('E3')->getValue()));
$this->assertNull($plain($sheet->getCell('V3')->getValue()));
} finally {
@unlink($importPath);
@unlink($resultPath);
}
}
public function test_settlement_import_template_streams_workbook(): void
{
$this->user->attachPermission(Permission::where('name', 'read-admin-panel')->firstOrFail());
$response = $this->loginAs()->get(route('business.courier-surcharge.settlement.import-template'));
$response->assertOk();
$this->assertStringContainsString(
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
(string) $response->headers->get('content-type'),
);
$path = tempnam(sys_get_temp_dir(), 'surcharge_import_template_');
file_put_contents($path, $response->streamedContent());
$sheet = IOFactory::load($path)->getActiveSheet();
$plain = static fn (mixed $value): mixed => $value instanceof RichText ? $value->getPlainText() : $value;
try {
$this->assertSame('单号', $plain($sheet->getCell('A1')->getValue()));
$this->assertSame('附加费类型', $plain($sheet->getCell('B1')->getValue()));
$this->assertSame('快递名称', $plain($sheet->getCell('C1')->getValue()));
$this->assertSame('金额(可选)', $plain($sheet->getCell('D1')->getValue()));
$this->assertSame('DPK317138931411', $plain($sheet->getCell('A2')->getValue()));
$this->assertSame('退回费', $plain($sheet->getCell('B2')->getValue()));
$this->assertSame('曹县德邦小件', $plain($sheet->getCell('C2')->getValue()));
$this->assertEquals(20, $plain($sheet->getCell('D2')->getValue()));
} finally {
@unlink($path);
}
}
}