CaiWuXiTong/tests/Unit/EcommerceFinance/DingProcessDetailMirrorRepositoryTest.php

234 lines
9.2 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\DingProcessDetailMirrorRepository;
use RuntimeException;
use Tests\TestCase;
class DingProcessDetailMirrorRepositoryTest extends TestCase
{
private DingProcessDetailMirrorRepository $repository;
protected function setUp(): void
{
parent::setUp();
config([
'database.connections.business_mirror' => [
'driver' => 'sqlite',
'database' => ':memory:',
'prefix' => '',
],
'upstream_mirrors.connection' => 'business_mirror',
'upstream_mirrors.ding_process_details.scope' => 'personal_permission',
]);
DB::purge('business_mirror');
$this->createMirrorTables();
$this->seedRows();
$this->repository = app(DingProcessDetailMirrorRepository::class);
}
public function test_paginate_returns_rows_summary_and_filter_options(): void
{
$result = $this->repository->paginate([], 1, 50);
$this->assertSame(4, $result['total']);
$this->assertCount(4, $result['data']);
$this->assertSame(4, $result['summary']['rows']);
$this->assertSame(2, $result['summary']['approvals']);
$this->assertEqualsWithDelta(650.5, $result['summary']['amount_total'], 0.001);
$this->assertEqualsWithDelta(650.5, $result['summary']['bank_amount_total'], 0.001);
$this->assertSame('personal_permission', $result['scope']);
$options = $this->repository->filterOptions();
$this->assertSame(['2026-02', '2026-01'], $options['months']);
$this->assertContains('公摊日常报销', $options['document_types']);
$this->assertContains('应付申请流程', $options['document_types']);
$this->assertContains('已完成', $options['statuses']);
$this->assertContains('审批中', $options['statuses']);
}
public function test_paginate_applies_month_status_and_keyword_filters(): void
{
$this->assertSame(
2,
$this->repository->paginate(['month' => '2026-01'], 1, 50)['total'],
);
$this->assertSame(
2,
$this->repository->paginate(['status' => '审批中'], 1, 50)['total'],
);
$this->assertSame(
1,
$this->repository->paginate(['keyword' => '办公'], 1, 50)['total'],
);
}
public function test_paginate_applies_document_type_originator_and_business_id_filters(): void
{
$this->assertSame(
2,
$this->repository->paginate([
'document_type' => '应付申请流程',
'originator_name' => '李四',
], 1, 50)['total'],
);
$this->assertSame(
2,
$this->repository->paginate(['business_id' => '0002'], 1, 50)['total'],
);
}
public function test_export_rows_returns_every_filtered_row(): void
{
$rows = iterator_to_array($this->repository->exportRows(['status' => '已完成']));
$this->assertCount(2, $rows);
$this->assertSame('202601011200000000001', (string) $rows[0]['business_id']);
}
public function test_not_ready_when_state_is_missing(): void
{
DB::connection('business_mirror')
->table('business_mirror_table_states')
->where('dataset_key', 'ding.process_details.personal_permission')
->delete();
$this->assertFalse($this->repository->ready());
$this->expectException(RuntimeException::class);
$this->expectExceptionMessage('ding_process_detail_mirror_not_ready');
$this->repository->paginate([], 1, 50);
}
private function seedRows(): void
{
$now = now();
$rows = [
$this->row('202601011200000000001', 1, '202601', '张三', '已完成', '公摊日常报销', '办公用品采购', 100.00),
$this->row('202601011200000000001', 2, '202601', '张三', '已完成', '公摊日常报销', '交通费', 50.50),
$this->row('202602031200000000002', 1, '202602', '李四', '审批中', '应付申请流程', '供应商货款', 200.00),
$this->row('202602031200000000002', 2, '202602', '李四', '审批中', '应付申请流程', '供应商货款', 300.00),
];
DB::connection('business_mirror')
->table('ding_process_detail_mirror')
->insert($rows);
DB::connection('business_mirror')
->table('business_mirror_table_states')
->insert([
'dataset_key' => 'ding.process_details.personal_permission',
'source_key' => 'dingtalk_oa',
'source_object' => 'oa approval detail (personal permission scope)',
'target_table' => 'ding_process_detail_mirror',
'status' => 'succeeded',
'run_mode' => 'full',
'generation' => '00000000-0000-0000-0000-000000000001',
'initial_completed_at' => $now,
'last_full_succeeded_at' => $now,
'last_attempted_at' => $now,
'last_succeeded_at' => $now,
'last_upserted_rows' => 4,
'mirror_row_count' => 4,
'created_at' => $now,
'updated_at' => $now,
]);
}
/** @return array<string,mixed> */
private function row(
string $businessId,
int $lineNo,
string $month,
string $originator,
string $status,
string $documentType,
string $purpose,
float $amount,
): array {
$now = now();
return [
'business_id' => $businessId,
'line_no' => $lineNo,
'business_month' => $month,
'originator_name' => $originator,
'status' => $status,
'document_type' => $documentType,
'purpose' => $purpose,
'account_code' => '5602.04',
'account_name' => '管理费用_办公费',
'amount' => $amount,
'bank_account_code' => '1002.01.001',
'bank_account_name' => '华夏银行-测试',
'bank_amount' => $amount,
'payment_method' => '银行卡',
'paid_at' => '2026-01-02 00:00',
'source_scope' => 'personal_permission',
'synced_at' => $now,
'created_at' => $now,
'updated_at' => $now,
];
}
private function createMirrorTables(): void
{
Schema::connection('business_mirror')->create(
'business_mirror_table_states',
function (Blueprint $table): void {
$table->string('dataset_key')->primary();
$table->string('source_key');
$table->string('source_object');
$table->string('target_table');
$table->string('status')->default('pending');
$table->string('run_mode')->nullable();
$table->string('generation')->nullable();
$table->json('cursor')->nullable();
$table->json('high_watermark')->nullable();
$table->dateTime('window_started_at')->nullable();
$table->dateTime('window_ends_at')->nullable();
$table->dateTime('initial_completed_at')->nullable();
$table->dateTime('last_full_succeeded_at')->nullable();
$table->dateTime('last_attempted_at')->nullable();
$table->dateTime('last_succeeded_at')->nullable();
$table->unsignedBigInteger('last_upserted_rows')->default(0);
$table->unsignedBigInteger('mirror_row_count')->default(0);
$table->string('last_error_code')->nullable();
$table->timestamps();
},
);
Schema::connection('business_mirror')->create(
'ding_process_detail_mirror',
function (Blueprint $table): void {
$table->bigIncrements('id');
$table->string('business_id', 32);
$table->unsignedInteger('line_no');
$table->string('business_month', 6)->index();
$table->string('originator_name', 100)->nullable()->index();
$table->string('status', 20)->nullable()->index();
$table->string('document_type', 100)->nullable()->index();
$table->text('purpose')->nullable();
$table->string('account_code', 64)->nullable();
$table->string('account_name', 255)->nullable();
$table->decimal('amount', 18, 2)->nullable();
$table->string('bank_account_code', 255)->nullable();
$table->string('bank_account_name', 255)->nullable();
$table->decimal('bank_amount', 18, 2)->nullable();
$table->string('payment_method', 50)->nullable();
$table->string('paid_at', 50)->nullable();
$table->string('source_scope', 40)->default('personal_permission')->index();
$table->dateTime('synced_at', 6);
$table->timestamps();
$table->unique(['business_id', 'line_no']);
},
);
}
}