CaiWuXiTong/tests/Unit/EcommerceFinance/WorkOrderMirrorRepositoryTest.php

197 lines
11 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\GenericBusinessMirrorRepository;
use Modules\EcommerceFinance\Repositories\WorkOrderMirrorRepository;
use Modules\EcommerceFinance\Services\BusinessMirrorDatasetRegistry;
use Tests\TestCase;
class WorkOrderMirrorRepositoryTest extends TestCase
{
private WorkOrderMirrorRepository $repository;
protected function setUp(): void
{
parent::setUp();
config([
'database.connections.business_mirror' => [
'driver' => 'sqlite',
'database' => ':memory:',
'prefix' => '',
],
'upstream_mirrors.connection' => 'business_mirror',
'upstream_mirrors.datasets' => [
WorkOrderMirrorRepository::MAIN_DATASET => $this->definition('work_order_main', 'fixture_work_order_main', ['id'], 'update_time'),
WorkOrderMirrorRepository::SUB_DATASET => $this->definition('work_order_sub', 'fixture_work_order_sub', ['id'], 'update_time'),
WorkOrderMirrorRepository::CONFIG_DATASET => $this->definition('work_order_form_config', 'fixture_work_order_config', ['id'], 'update_time'),
WorkOrderMirrorRepository::VALUE_DATASET => $this->definition('work_order_form_value', 'fixture_work_order_values', ['id'], 'create_time'),
],
]);
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')->nullable();
$table->dateTime('initial_completed_at')->nullable();
$table->dateTime('last_succeeded_at')->nullable();
});
$this->createTables($schema);
foreach (array_keys(config('upstream_mirrors.datasets')) as $key) {
DB::connection('business_mirror')->table('business_mirror_table_states')->insert([
'dataset_key' => $key,
'status' => 'succeeded',
'initial_completed_at' => '2026-08-01 00:00:00',
'last_succeeded_at' => '2026-08-31 12:00:00',
]);
}
DB::connection('business_mirror')->table('fixture_work_order_config')->insert([
['id' => 1, 'work_type' => 'WAREHOUSE', 'work_type_name' => '仓内未发', 'group_name' => '协同工单', 'is_enabled' => 1],
['id' => 2, 'work_type' => 'OTHER', 'work_type_name' => '其他', 'group_name' => '其他', 'is_enabled' => 1],
]);
DB::connection('business_mirror')->table('fixture_work_order_main')->insert([
['id' => 1, 'work_type' => 'WAREHOUSE', 'order_no' => 'WO-001', 'title' => '仓内未发一', 'status' => '待处理', 'create_user' => '张三', 'create_time' => '2026-08-20 10:00:00', 'update_time' => '2026-08-20 10:00:00', 'is_deleted' => 0],
['id' => 2, 'work_type' => 'WAREHOUSE', 'order_no' => 'WO-002', 'title' => '仓内未发二', 'status' => '处理中', 'create_user' => '李四', 'create_time' => '2026-08-21 10:00:00', 'update_time' => '2026-08-21 10:00:00', 'is_deleted' => 0],
['id' => 3, 'work_type' => 'OTHER', 'order_no' => 'WO-003', 'title' => '其他类型', 'status' => '待处理', 'create_user' => '张三', 'create_time' => '2026-08-22 10:00:00', 'update_time' => '2026-08-22 10:00:00', 'is_deleted' => 0],
['id' => 4, 'work_type' => 'WAREHOUSE', 'order_no' => 'WO-004', 'title' => '已删除', 'status' => '待处理', 'create_user' => '张三', 'create_time' => '2026-08-23 10:00:00', 'update_time' => '2026-08-23 10:00:00', 'is_deleted' => 1],
]);
DB::connection('business_mirror')->table('fixture_work_order_sub')->insert([
['id' => 1, 'sub_order_no' => 'SUB-001', 'main_order_no' => 'WO-002', 'title' => '拣货任务', 'assign_user' => '王五', 'status' => '执行中', 'is_deleted' => 0],
['id' => 2, 'sub_order_no' => 'SUB-002', 'main_order_no' => 'WO-002', 'title' => '已删除任务', 'assign_user' => '赵六', 'status' => '已取消', 'is_deleted' => 1],
]);
DB::connection('business_mirror')->table('fixture_work_order_values')->insert([
['id' => 1, 'main_order_no' => 'WO-002', 'field_code' => 'reason', 'field_name' => '未发原因', 'field_value' => '缺货', 'field_type' => 'text', 'sort' => 1, 'is_deleted' => 0],
['id' => 2, 'main_order_no' => 'WO-002', 'field_code' => 'secret', 'field_name' => '删除字段', 'field_value' => '不应显示', 'field_type' => 'text', 'sort' => 2, 'is_deleted' => 1],
]);
$this->repository = new WorkOrderMirrorRepository(
new BusinessMirrorDatasetRegistry(),
new GenericBusinessMirrorRepository(app('db')),
);
}
public function test_default_type_delete_filter_pagination_and_related_rows(): void
{
$page = $this->repository->paginate(1, 1);
$this->assertTrue($page['ready']);
$this->assertSame(2, $page['total']);
$this->assertSame('WO-002', $page['data'][0]['order_no']);
$this->assertCount(1, $page['data'][0]['sub_orders']);
$this->assertSame('SUB-001', $page['data'][0]['sub_orders'][0]['sub_order_no']);
$this->assertCount(1, $page['data'][0]['form_values']);
$this->assertSame('缺货', $page['data'][0]['form_values'][0]['field_value']);
$filtered = $this->repository->paginate(1, 50, ['assign_user' => '王五']);
$this->assertSame(1, $filtered['total']);
$this->assertSame('WO-002', $filtered['data'][0]['order_no']);
$secondPage = $this->repository->paginate(2, 1);
$this->assertSame('WO-001', $secondPage['data'][0]['order_no']);
}
public function test_after_sales_alerts_are_filtered_by_type_and_form_values(): void
{
DB::connection('business_mirror')->table('fixture_work_order_config')->insert([
'id' => 3,
'work_type' => 'ORDER_AFSALES',
'work_type_name' => '天猫_售后超标',
'group_name' => '运营',
'is_enabled' => 1,
]);
DB::connection('business_mirror')->table('fixture_work_order_main')->insert([
'id' => 5,
'work_type' => 'ORDER_AFSALES',
'order_no' => 'WO-005-AF',
'title' => '售后超标提醒',
'status' => '待处理',
'create_user' => '运营一组',
'create_time' => '2026-08-24 10:00:00',
'update_time' => '2026-08-24 10:00:00',
'is_deleted' => 0,
]);
DB::connection('business_mirror')->table('fixture_work_order_values')->insert([
['id' => 3, 'main_order_no' => 'WO-005-AF', 'field_code' => 'shop_name', 'field_name' => '店铺名称', 'field_value' => '天猫旗舰店', 'field_type' => 'text', 'sort' => 1, 'is_deleted' => 0],
['id' => 4, 'main_order_no' => 'WO-005-AF', 'field_code' => 'id', 'field_name' => '商品ID', 'field_value' => 'SKU-AF-1', 'field_type' => 'text', 'sort' => 2, 'is_deleted' => 0],
]);
$result = $this->repository->paginateAfterSales(1, 10, [
'from' => '2026-08-24',
'to' => '2026-08-24',
'shop_name' => '旗舰店',
'sku_id' => 'SKU-AF',
]);
$this->assertTrue($result['ready']);
$this->assertSame(1, $result['total']);
$this->assertSame('WO-005-AF', $result['data'][0]['order_no']);
$this->assertSame('天猫_售后超标', $result['data'][0]['work_type_name']);
$this->assertSame('天猫旗舰店', $result['data'][0]['form_values'][0]['field_value']);
}
public function test_unready_state_is_explicit_and_never_looks_like_empty_data(): void
{
DB::connection('business_mirror')->table('business_mirror_table_states')
->where('dataset_key', WorkOrderMirrorRepository::SUB_DATASET)
->update(['initial_completed_at' => null, 'status' => 'running']);
$result = $this->repository->paginate(1, 25);
$this->assertFalse($result['ready']);
$this->assertSame([], $result['data']);
$this->assertSame('initial_sync_pending', $result['sync_status']['code']);
$this->assertFalse($result['sync_status']['datasets']['sub']['ready']);
}
private function definition(string $object, string $target, array $keys, ?string $watermark): array
{
return [
'source_key' => 'operations_replica',
'schema' => 'rpt',
'object' => $object,
'target' => $target,
'keys' => $keys,
'watermark' => $watermark,
];
}
private function createTables($schema): void
{
$schema->create('fixture_work_order_main', function (Blueprint $table): void {
$table->integer('id');
foreach (['work_type', 'order_no', 'title', 'status', 'create_user', 'expect_minute', 'submit_time', 'expect_end_time', 'end_time', 'score', 'update_user', 'description', 'create_time', 'update_time'] as $column) {
$table->string($column)->nullable();
}
$table->integer('is_deleted')->nullable();
});
$schema->create('fixture_work_order_sub', function (Blueprint $table): void {
$table->integer('id');
foreach (['sub_order_no', 'main_order_no', 'title', 'assign_user', 'status', 'expect_minute', 'submit_time', 'expect_end_time', 'finish_time', 'content', 'notify_submit', 'notify_soon', 'notify_overdue', 'overdue_notify_count', 'create_time', 'update_time', 'taskid'] as $column) {
$table->string($column)->nullable();
}
$table->integer('is_deleted')->nullable();
});
$schema->create('fixture_work_order_config', function (Blueprint $table): void {
$table->integer('id');
foreach (['work_type', 'work_type_name', 'group_name', 'icon', 'icon_color', 'time_limit_options', 'form_fields', 'sort', 'remark', 'create_time', 'update_time', 'timeout_reminder_count'] as $column) {
$table->string($column)->nullable();
}
$table->integer('is_enabled')->nullable();
});
$schema->create('fixture_work_order_values', function (Blueprint $table): void {
$table->integer('id');
foreach (['main_order_no', 'field_code', 'field_name', 'field_value', 'field_type', 'sort', 'create_time'] as $column) {
$table->string($column)->nullable();
}
$table->integer('is_deleted')->nullable();
});
}
}