CaiWuXiTong/tests/Feature/Console/SupplierSummaryInboundImportTest.php

160 lines
6.7 KiB
PHP

<?php
namespace Tests\Feature\Console;
use App\Models\Business\InventoryWarehouseNameMapping;
use Illuminate\Support\Facades\DB;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\Writer\Xlsx;
use Tests\Feature\FeatureTestCase;
class SupplierSummaryInboundImportTest extends FeatureTestCase
{
public function test_monthly_import_preserves_identical_rows_and_reports_duplicates_and_failures(): void
{
$provider = '测试仓储方-' . uniqid();
InventoryWarehouseNameMapping::query()->create([
'company_id' => 1,
'warehouse_provider' => $provider,
'warehouse' => $provider . '主仓',
'warehouse_short_name' => '测试简称',
]);
$ambiguousProvider = '测试歧义仓储方-' . uniqid();
foreach (['甲', '乙'] as $name) {
InventoryWarehouseNameMapping::query()->create([
'company_id' => 1,
'warehouse_provider' => $ambiguousProvider,
'warehouse' => $ambiguousProvider . $name . '主仓',
'warehouse_short_name' => '歧义简称' . $name,
]);
}
$connection = (string) config('upstream_mirrors.connection', 'business_mirror');
DB::connection($connection)->table('inventory_inbound_detail_rows')->insert([
'report_month' => '2026-08-01',
'row_key' => sha1('historic-row'),
'imported_at' => now(),
]);
$path = $this->temporaryPath('supplier-summary-', '.xlsx');
$firstResult = $this->temporaryPath('supplier-result-', '.json');
$secondResult = $this->temporaryPath('supplier-result-', '.json');
try {
$this->writeWorkbook($path, $provider, $ambiguousProvider);
$this->artisan('inventory:supplier-summary:import', [
'file' => $path,
'--month' => '2026-09',
'--result-json' => $firstResult,
])
->expectsOutputToContain('成功=2')
->expectsOutputToContain('另有 2 条失败原因')
->assertExitCode(1);
$result = json_decode((string) file_get_contents($firstResult), true);
$this->assertSame('partial', $result['status']);
$this->assertSame('2026-09-01', $result['report_month']);
$this->assertSame(2, $result['success']);
$this->assertSame(0, $result['duplicates']);
$this->assertSame(12, $result['failed']);
$this->assertSame(12, $result['failure_reason_count']);
$this->assertSame(4, $result['failure_reasons'][0]['row']);
$this->assertStringContainsString('仓库未匹配', $result['failure_reasons'][0]['reason']);
$this->assertSame(
'仓库未匹配到唯一仓库简称:' . $ambiguousProvider,
$result['failure_reasons'][11]['reason'],
);
$this->assertSame(
1,
DB::connection($connection)->table('inventory_inbound_detail_rows')
->where('report_month', '2026-08-01')->count(),
);
$september = DB::connection($connection)->table('inventory_inbound_detail_rows')
->where('report_month', '2026-09-01')
->get();
$this->assertCount(2, $september);
$this->assertSame('BARCODE-1', $september->first()->barcode);
$this->assertSame('测试简称', $september->first()->warehouse_short_name);
$this->assertSame('2026-09-03 10:00:00', $september->first()->created_at_raw);
$this->assertEquals(20, $september->first()->amount);
$this->assertEquals(22, $september->first()->estimated_amount);
$this->assertNotSame(
$september[0]->row_key,
$september[1]->row_key,
);
$this->artisan('inventory:supplier-summary:import', [
'file' => $path,
'--month' => '2026-09',
'--result-json' => $secondResult,
])->assertExitCode(1);
$second = json_decode((string) file_get_contents($secondResult), true);
$this->assertSame('failed', $second['status']);
$this->assertSame(0, $second['success']);
$this->assertSame(2, $second['duplicates']);
$this->assertSame(12, $second['failed']);
$this->assertSame(
2,
DB::connection($connection)->table('inventory_inbound_detail_rows')
->where('report_month', '2026-09-01')->count(),
);
} finally {
foreach ([$path, $firstResult, $secondResult] as $file) {
@unlink($file);
}
}
}
private function writeWorkbook(
string $path,
string $provider,
string $ambiguousProvider,
): void
{
$spreadsheet = new Spreadsheet();
$sheet = $spreadsheet->getActiveSheet();
$sheet->setTitle('明细');
$sheet->fromArray([
'来源单号', "单据编号\n(采购单号)", '创建时间', '供应商', '货号', '条码',
'规格名', '库存变动量', '单价', '金额', '预估单价', '预估金额',
'供应商条码', '备注', '仓库', '创建时间', '快递名称', '快递单号',
'未发出', '负责人',
], null, 'A1');
for ($row = 2; $row <= 14; $row++) {
$warehouse = $row <= 3 ? $provider : '不存在的仓库';
$sheet->fromArray([
'SRC-1', 'PO-1', '46245', '测试供应商', 'ITEM-1', 'BARCODE-1',
'测试规格', 2, 10, null, 11, null, 'SUP-BAR-1', '测试备注',
$warehouse, '2026-09-03 10:00:00', '顺丰', 'SF123', '否',
'测试负责人',
], null, 'A' . $row);
$sheet->setCellValue('J' . $row, '=H' . $row . '*I' . $row);
$sheet->setCellValue('L' . $row, '=K' . $row . '*H' . $row);
}
$sheet->fromArray([
'SRC-2', 'PO-2', '46246', '测试供应商', 'ITEM-2', 'BARCODE-2',
'测试规格二', 1, 10, null, 10, null, 'SUP-BAR-2', null,
$ambiguousProvider, '2026-09-04 10:00:00', null, null, null,
'测试负责人',
], null, 'A15');
$sheet->setCellValue('J15', '=H15*I15');
$sheet->setCellValue('L15', '=K15*H15');
(new Xlsx($spreadsheet))->save($path);
$spreadsheet->disconnectWorksheets();
}
private function temporaryPath(string $prefix, string $suffix): string
{
$temporary = tempnam(sys_get_temp_dir(), $prefix);
$path = $temporary . $suffix;
rename($temporary, $path);
return $path;
}
}