## 做了什么 线上代发价格页面与 CSV 导出新增两列: - **实际发货商品编码**:按店铺交易单号(钉钉行)/内部单号(采购单行)关联聚水潭订单(非淘系 + 淘系),列出组合装拆开后的子商品编码×数量;优先只取本行商品编码拆出的子商品,普通商品取自身,对不上时列整单;忽略被拆分/合并/作废原单,拆单合并显示 - **聚水潭标记|多标签**:订单 labels ## 修改文件 - modules/EcommerceFinance/Repositories/DingOnlineDaifaPriceMirrorRepository.php - app/Http/Controllers/Business/Pages.php(导出加列) - resources/views/business/pages/product-inventory/online-daifa-price.blade.php - tests/Unit/EcommerceFinance/OnlineDaifaShipSkuLabelsTest.php(新增)、tests/Feature/Business/OnlineDaifaPricePageTest.php ## 验证 - 新增 4 个单测(组合装、混合订单、拆单、无订单)+ 原采购单单测在精简 Laravel 环境通过;Feature 测试新增断言未在完整环境运行 - 只按当前页/导出每 200 行的单号做 so_id/o_id 索引等值查询,不扫全表 ## 风险 不涉及金额计算、权限、数据库结构或配置;只读镜像表。 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_012AvVQFrueqWakFKTdSyu5q Reviewed-on: #730
165 lines
8.3 KiB
PHP
165 lines
8.3 KiB
PHP
<?php
|
||
|
||
namespace Tests\Unit\EcommerceFinance;
|
||
|
||
use Illuminate\Database\Schema\Blueprint;
|
||
use Illuminate\Support\Facades\DB;
|
||
use Illuminate\Support\Facades\Schema;
|
||
use Modules\EcommerceFinance\Repositories\DingOnlineDaifaPriceMirrorRepository;
|
||
use Tests\TestCase;
|
||
|
||
class OnlineDaifaShipSkuLabelsTest extends TestCase
|
||
{
|
||
protected function setUp(): void
|
||
{
|
||
parent::setUp();
|
||
|
||
config([
|
||
'database.connections.business_mirror' => ['driver' => 'sqlite', 'database' => ':memory:', 'prefix' => ''],
|
||
'upstream_mirrors.connection' => 'business_mirror',
|
||
]);
|
||
DB::purge('business_mirror');
|
||
|
||
$this->createSchema();
|
||
$this->seedRows();
|
||
}
|
||
|
||
public function test_combo_row_lists_the_child_skus_and_order_labels(): void
|
||
{
|
||
$row = $this->row('3634442001971995');
|
||
|
||
$this->assertSame('VTYZ010102×1, GDYRB020102×1', $row['ship_skus']);
|
||
$this->assertSame('店铺-京东供销,京东供销订单,京东快递,京喜,线上发货,以旧换新·国家补贴,指定快递', $row['jst_labels']);
|
||
}
|
||
|
||
public function test_only_the_children_of_this_rows_combo_are_listed_when_the_order_mixes_items(): void
|
||
{
|
||
$this->assertSame('CHAIR-A×2', $this->row('5000000000000001', 'ZH-CHAIR-A-2')['ship_skus']);
|
||
$this->assertSame('DESK-B×1', $this->row('5000000000000001', 'DESK-B')['ship_skus']);
|
||
$this->assertSame('CHAIR-A×2, DESK-B×1', $this->row('5000000000000001', 'UNKNOWN-CODE')['ship_skus']);
|
||
}
|
||
|
||
public function test_split_parent_orders_are_ignored_and_children_are_merged(): void
|
||
{
|
||
$row = $this->row('6000000000000001');
|
||
|
||
$this->assertSame('SOFA-L×1, SOFA-R×1', $row['ship_skus']);
|
||
$this->assertSame('拆分', $row['jst_labels']);
|
||
}
|
||
|
||
public function test_rows_without_a_jst_order_stay_blank_and_export_matches_page(): void
|
||
{
|
||
$repository = app(DingOnlineDaifaPriceMirrorRepository::class);
|
||
$this->assertSame('', $this->row('9999999999999999')['ship_skus']);
|
||
$this->assertSame('', $this->row('9999999999999999')['jst_labels']);
|
||
|
||
$page = $repository->paginate([], 1, 100)['data'];
|
||
$export = iterator_to_array($repository->exportRows([]), false);
|
||
$this->assertSame(array_column($page, 'ship_skus'), array_column($export, 'ship_skus'));
|
||
$this->assertSame(array_column($page, 'jst_labels'), array_column($export, 'jst_labels'));
|
||
}
|
||
|
||
/** @return array<string,mixed> */
|
||
private function row(string $shopTradeNo, ?string $materialNo = null): array
|
||
{
|
||
$data = app(DingOnlineDaifaPriceMirrorRepository::class)->paginate(['keyword' => $shopTradeNo], 1, 100)['data'];
|
||
foreach ($data as $row) {
|
||
if ($materialNo === null || $row['material_no'] === $materialNo) {
|
||
return $row;
|
||
}
|
||
}
|
||
$this->fail('row not found');
|
||
}
|
||
|
||
private function createSchema(): void
|
||
{
|
||
$schema = Schema::connection('business_mirror');
|
||
$schema->create('business_mirror_table_states', function (Blueprint $table): void {
|
||
$table->string('dataset_key')->primary();
|
||
$table->string('status');
|
||
$table->dateTime('initial_completed_at')->nullable();
|
||
$table->dateTime('last_succeeded_at')->nullable();
|
||
});
|
||
$schema->create(DingOnlineDaifaPriceMirrorRepository::TARGET_TABLE, function (Blueprint $table): void {
|
||
$table->string('process_instance_id');
|
||
$table->unsignedInteger('detail_index');
|
||
$table->string('product_id')->nullable();
|
||
$table->string('product_name')->nullable();
|
||
$table->string('daifa_trade_no')->nullable();
|
||
$table->string('shop_trade_no')->nullable();
|
||
$table->string('shop_name')->nullable();
|
||
$table->string('payee_name')->nullable();
|
||
$table->string('supplier_name')->nullable();
|
||
$table->string('material_no')->nullable();
|
||
$table->integer('ship_qty')->nullable();
|
||
$table->decimal('paid_amount', 20, 2)->nullable();
|
||
$table->decimal('daifa_amount', 20, 2)->nullable();
|
||
$table->decimal('price_diff', 20, 2)->nullable();
|
||
$table->text('workflow_payload')->nullable();
|
||
$table->text('scheme_payload')->nullable();
|
||
$table->text('task_payload')->nullable();
|
||
$table->dateTime('workflow_created_at')->nullable();
|
||
});
|
||
$schema->create('ops_jst_orders', function (Blueprint $table): void {
|
||
$table->unsignedBigInteger('Id')->primary();
|
||
$table->unsignedBigInteger('o_id')->index();
|
||
$table->string('so_id')->nullable()->index();
|
||
$table->string('shop_name')->nullable();
|
||
$table->string('status')->nullable();
|
||
$table->text('labels')->nullable();
|
||
});
|
||
$schema->create('ops_jst_order_item', function (Blueprint $table): void {
|
||
$table->unsignedBigInteger('Id')->primary();
|
||
$table->unsignedBigInteger('o_id')->index();
|
||
$table->string('sku_id')->nullable();
|
||
$table->decimal('qty', 20, 4)->nullable();
|
||
$table->string('src_combine_sku_id')->nullable();
|
||
});
|
||
}
|
||
|
||
private function seedRows(): void
|
||
{
|
||
$db = DB::connection('business_mirror');
|
||
$db->table('business_mirror_table_states')->insert([
|
||
'dataset_key' => DingOnlineDaifaPriceMirrorRepository::DATASET_KEY,
|
||
'status' => 'succeeded',
|
||
'initial_completed_at' => '2026-10-01 00:00:00',
|
||
'last_succeeded_at' => '2026-10-28 09:00:00',
|
||
]);
|
||
|
||
$ding = static fn (string $id, int $index, string $soId, string $material): array => [
|
||
'process_instance_id' => $id, 'detail_index' => $index, 'shop_trade_no' => $soId,
|
||
'shop_name' => '店铺-京东供销', 'material_no' => $material, 'ship_qty' => 1,
|
||
'workflow_payload' => '{"status":"COMPLETED","result":"agree"}', 'scheme_payload' => '[]', 'task_payload' => '[]',
|
||
'workflow_created_at' => '2026-10-0' . $index . ' 10:00:00',
|
||
];
|
||
$db->table(DingOnlineDaifaPriceMirrorRepository::TARGET_TABLE)->insert([
|
||
$ding('P1', 1, '3634442001971995', 'ZH-GDYRB020102-1-VTYZ010102-1'),
|
||
$ding('P2', 1, '5000000000000001', 'ZH-CHAIR-A-2'),
|
||
$ding('P2', 2, '5000000000000001', 'DESK-B'),
|
||
$ding('P2', 3, '5000000000000001', 'UNKNOWN-CODE'),
|
||
$ding('P3', 1, '6000000000000001', 'ZH-SOFA'),
|
||
$ding('P4', 1, '9999999999999999', 'NONE'),
|
||
]);
|
||
|
||
$db->table('ops_jst_orders')->insert([
|
||
['Id' => 1, 'o_id' => 9557207, 'so_id' => '3634442001971995', 'shop_name' => '店铺-京东供销', 'status' => 'Sent',
|
||
'labels' => '店铺-京东供销,京东供销订单,京东快递,京喜,线上发货,以旧换新·国家补贴,指定快递'],
|
||
['Id' => 2, 'o_id' => 100, 'so_id' => '5000000000000001', 'shop_name' => 'x', 'status' => 'Sent', 'labels' => null],
|
||
['Id' => 3, 'o_id' => 200, 'so_id' => '6000000000000001', 'shop_name' => 'x', 'status' => 'Split', 'labels' => '原单'],
|
||
['Id' => 4, 'o_id' => 201, 'so_id' => '6000000000000001', 'shop_name' => 'x', 'status' => 'Sent', 'labels' => '拆分'],
|
||
['Id' => 5, 'o_id' => 202, 'so_id' => '6000000000000001', 'shop_name' => 'x', 'status' => 'Sent', 'labels' => '拆分'],
|
||
]);
|
||
$db->table('ops_jst_order_item')->insert([
|
||
['Id' => 1, 'o_id' => 9557207, 'sku_id' => 'VTYZ010102', 'qty' => 1, 'src_combine_sku_id' => 'ZH-GDYRB020102-1-VTYZ010102-1'],
|
||
['Id' => 2, 'o_id' => 9557207, 'sku_id' => 'GDYRB020102', 'qty' => 1, 'src_combine_sku_id' => 'ZH-GDYRB020102-1-VTYZ010102-1'],
|
||
['Id' => 3, 'o_id' => 100, 'sku_id' => 'CHAIR-A', 'qty' => 2, 'src_combine_sku_id' => 'ZH-CHAIR-A-2'],
|
||
['Id' => 4, 'o_id' => 100, 'sku_id' => 'DESK-B', 'qty' => 1, 'src_combine_sku_id' => null],
|
||
['Id' => 5, 'o_id' => 200, 'sku_id' => 'SOFA-L', 'qty' => 1, 'src_combine_sku_id' => 'ZH-SOFA'],
|
||
['Id' => 6, 'o_id' => 200, 'sku_id' => 'SOFA-R', 'qty' => 1, 'src_combine_sku_id' => 'ZH-SOFA'],
|
||
['Id' => 7, 'o_id' => 201, 'sku_id' => 'SOFA-L', 'qty' => 1, 'src_combine_sku_id' => 'ZH-SOFA'],
|
||
['Id' => 8, 'o_id' => 202, 'sku_id' => 'SOFA-R', 'qty' => 1, 'src_combine_sku_id' => 'ZH-SOFA'],
|
||
]);
|
||
}
|
||
}
|