CaiWuXiTong/tests/Unit/EcommerceFinance/OnlineDaifaCostAuditTest.php
limeng 4783185e3f feat(线上代发价格): 新增标签筛选,关键字支持审批编号 (#872)
- 筛选栏增加“标签”:刘萧代发 / 1688代发 / 采购单管理(钉钉行按收款人区分,采购单行固定为采购单管理),页面、汇总、成本核查和导出同一口径
- 关键字原本标注支持审批编号但实际不查,钉钉来源增加匹配审批 JSON(businessId)
涉及:只读查询与页面筛选;不涉及迁移、权限和上游写入。

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VANWYsNUbu2piMtCKymoyd
2026-11-04 18:30:13 +08:00

156 lines
8.3 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\Unit\EcommerceFinance;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;
use Modules\EcommerceFinance\Repositories\DingOnlineDaifaPriceMirrorRepository as Repository;
use Tests\TestCase;
class OnlineDaifaCostAuditTest extends TestCase
{
protected function setUp(): void
{
parent::setUp();
config([
'database.connections.business_mirror' => ['driver' => 'sqlite', 'database' => ':memory:', 'prefix' => ''],
'upstream_mirrors.connection' => 'business_mirror',
]);
Cache::setDefaultDriver('array');
Cache::flush();
DB::purge('business_mirror');
$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(Repository::TARGET_TABLE, function (Blueprint $table): void {
$table->string('process_instance_id');
$table->unsignedInteger('detail_index');
foreach (['product_id', 'product_name', 'daifa_trade_no', 'shop_trade_no', 'shop_name', 'payee_name', 'supplier_name', 'material_no'] as $column) {
$table->string($column)->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();
});
$schema->create('ops_jst_sku', function (Blueprint $table): void {
$table->unsignedBigInteger('autoid');
$table->string('sku_id');
$table->string('sku_type');
$table->decimal('cost_price', 18, 4)->nullable();
});
$db = DB::connection('business_mirror');
$db->table('business_mirror_table_states')->insert([
'dataset_key' => Repository::DATASET_KEY, 'status' => 'succeeded',
'initial_completed_at' => '2026-10-01 00:00:00', 'last_succeeded_at' => '2026-11-03 05:00:00',
]);
$ding = static fn (string $id, string $soId, string $material, ?float $amount): array => [
'process_instance_id' => $id, 'detail_index' => 0, 'shop_trade_no' => $soId, 'shop_name' => '京东-测试店',
'material_no' => $material, 'ship_qty' => 1, 'daifa_amount' => $amount,
'workflow_payload' => '{"status":"COMPLETED","result":"agree","businessId":"' . $id . '"}', 'scheme_payload' => '[]', 'task_payload' => '[]',
'workflow_created_at' => '2026-10-10 10:00:00',
];
$db->table(Repository::TARGET_TABLE)->insert([
$ding('OVER', '1001', 'ZH-CHAIR-2', 250.00), // 组合装:2 把椅子,成本 2×100=200,报 250 → 多报销 50
$ding('OK', '1002', 'DESK-B', 80.00), // 普通商品成本 80,报 80 → 正常
$ding('MISS', '1003', 'NOCOST', 30.00), // 成本价为 0 → 成本缺失
$ding('NONE', '9999', 'ANY', 10.00), // 聚水潭找不到订单 → 无发货明细
]);
$db->table('ops_jst_orders')->insert([
['Id' => 1, 'o_id' => 1, 'so_id' => '1001', 'shop_name' => 'x', 'status' => 'Sent', 'labels' => null],
['Id' => 2, 'o_id' => 2, 'so_id' => '1002', 'shop_name' => 'x', 'status' => 'Sent', 'labels' => null],
['Id' => 3, 'o_id' => 3, 'so_id' => '1003', 'shop_name' => 'x', 'status' => 'Sent', 'labels' => null],
]);
$db->table('ops_jst_order_item')->insert([
['Id' => 1, 'o_id' => 1, 'sku_id' => 'CHAIR-A', 'qty' => 2, 'src_combine_sku_id' => 'ZH-CHAIR-2'],
['Id' => 2, 'o_id' => 2, 'sku_id' => 'DESK-B', 'qty' => 1, 'src_combine_sku_id' => null],
['Id' => 3, 'o_id' => 3, 'sku_id' => 'NOCOST', 'qty' => 1, 'src_combine_sku_id' => null],
]);
$db->table('ops_jst_sku')->insert([
['autoid' => 1, 'sku_id' => 'CHAIR-A', 'sku_type' => 'normal', 'cost_price' => 90],
['autoid' => 2, 'sku_id' => 'CHAIR-A', 'sku_type' => 'normal', 'cost_price' => 100],
['autoid' => 3, 'sku_id' => 'DESK-B', 'sku_type' => 'normal', 'cost_price' => 80],
['autoid' => 4, 'sku_id' => 'NOCOST', 'sku_type' => 'normal', 'cost_price' => 0],
]);
}
public function test_cost_audit_splits_combo_and_flags_over_reimbursement(): void
{
$result = app(Repository::class)->paginate([], 1, 100);
$rows = collect($result['data'])->keyBy('process_instance_id');
$this->assertSame(Repository::AUDIT_OVER, $rows['OVER']['audit_result']);
$this->assertSame(200.0, $rows['OVER']['system_cost']);
$this->assertSame(50.0, $rows['OVER']['cost_diff']);
$this->assertSame('CHAIR-A×2×100=200.00', $rows['OVER']['audit_detail']);
$this->assertSame(Repository::AUDIT_OK, $rows['OK']['audit_result']);
$this->assertSame(0.0, $rows['OK']['cost_diff']);
$this->assertSame(Repository::AUDIT_COST_MISSING, $rows['MISS']['audit_result']);
$this->assertNull($rows['MISS']['cost_diff']);
$this->assertSame(Repository::AUDIT_NO_SHIPMENT, $rows['NONE']['audit_result']);
$this->assertSame(1, $result['summary']['audit_counts'][Repository::AUDIT_OVER]);
$this->assertSame(50.0, $result['summary']['over_amount']);
}
public function test_tag_filter_splits_ding_rows_by_payee(): void
{
DB::connection('business_mirror')->table(Repository::TARGET_TABLE)->where('process_instance_id', 'OK')
->update(['payee_name' => '宁波顾家望业家居有限公司']);
$repository = app(Repository::class);
$liuxiao = $repository->paginate(['tag' => Repository::TAG_LIUXIAO], 1, 100);
$this->assertSame(['OK'], array_column($liuxiao['data'], 'process_instance_id'));
$this->assertSame(Repository::TAG_LIUXIAO, $liuxiao['data'][0]['tag']);
$other = $repository->paginate(['tag' => Repository::TAG_1688], 1, 100);
$this->assertSame(3, $other['total']);
$this->assertNotContains('OK', array_column($other['data'], 'process_instance_id'));
$this->assertSame(0, $repository->paginate(['tag' => Repository::TAG_PURCHASE], 1, 100)['total']);
$export = iterator_to_array($repository->exportRows(['tag' => Repository::TAG_LIUXIAO]), false);
$this->assertSame(['OK'], array_column($export, 'process_instance_id'));
}
public function test_audit_filter_pages_and_exports_only_matching_rows(): void
{
$repository = app(Repository::class);
$result = $repository->paginate(['audit' => Repository::AUDIT_OVER], 1, 100);
$this->assertSame(1, $result['total']);
$this->assertSame(['OVER'], array_column($result['data'], 'process_instance_id'));
$export = iterator_to_array($repository->exportRows(['audit' => Repository::AUDIT_COST_MISSING]), false);
$this->assertSame(['MISS'], array_column($export, 'process_instance_id'));
$this->assertSame(Repository::AUDIT_COST_MISSING, $export[0]['audit_result']);
}
}