199 lines
8.4 KiB
PHP
199 lines
8.4 KiB
PHP
<?php
|
||
|
||
namespace Tests\Unit\EcommerceFinance;
|
||
|
||
use Illuminate\Database\Schema\Blueprint;
|
||
use Illuminate\Support\Carbon;
|
||
use Illuminate\Support\Facades\DB;
|
||
use Illuminate\Support\Facades\Schema;
|
||
use Modules\EcommerceFinance\Repositories\JushuitanCostPriceHistoryMirrorRepository;
|
||
use Tests\TestCase;
|
||
|
||
class JushuitanCostPriceHistoryMirrorRepositoryTest extends TestCase
|
||
{
|
||
private JushuitanCostPriceHistoryMirrorRepository $repository;
|
||
|
||
protected function setUp(): void
|
||
{
|
||
parent::setUp();
|
||
config()->set('database.connections.business_mirror', [
|
||
'driver' => 'sqlite',
|
||
'database' => ':memory:',
|
||
'prefix' => '',
|
||
'foreign_key_constraints' => true,
|
||
]);
|
||
config()->set('upstream_mirrors.connection', 'business_mirror');
|
||
DB::purge('business_mirror');
|
||
$this->createTables();
|
||
$this->repository = app(JushuitanCostPriceHistoryMirrorRepository::class);
|
||
}
|
||
|
||
public function test_it_stores_and_formats_multiple_cost_price_operations_for_the_same_sku(): void
|
||
{
|
||
$generation = '11111111-1111-4111-8111-111111111111';
|
||
$this->repository->startRun(
|
||
'full',
|
||
$generation,
|
||
Carbon::parse('2026-06-01'),
|
||
Carbon::parse('2026-07-01'),
|
||
false,
|
||
);
|
||
$this->repository->storePage([
|
||
[
|
||
'operation_id' => '1',
|
||
'sku_id' => '15961g',
|
||
'operation_type' => '商品与库存管理导入',
|
||
'operation_description' => '采购价:72.2222->65',
|
||
'operator_name' => '简尚',
|
||
'operated_at' => '2026-06-06 14:32:02.993',
|
||
'before_price' => 72.2222,
|
||
'after_price' => 65,
|
||
'diff_amount' => -7.2222,
|
||
],
|
||
[
|
||
'operation_id' => '2',
|
||
'sku_id' => '15961G',
|
||
'operation_type' => '编辑',
|
||
'operation_description' => '采购价:65->63',
|
||
'operator_name' => '测试人',
|
||
'operated_at' => '2026-06-07 08:00:00',
|
||
'before_price' => 65,
|
||
'after_price' => 63,
|
||
'diff_amount' => -2,
|
||
],
|
||
], Carbon::parse('2026-07-01'), 1, $generation, 2, 2);
|
||
$this->repository->complete('full', $generation, Carbon::parse('2026-07-01'), 2, 2);
|
||
|
||
$records = $this->repository->historyForSkus(['15961G'])->get('15961G');
|
||
$history = $this->repository->formatHistory($records);
|
||
|
||
$this->assertCount(2, $history);
|
||
$this->assertSame(['2', '1'], array_column($history, 'id'));
|
||
$this->assertSame('聚水潭商品及库存管理', $history[0]['source']);
|
||
$this->assertSame('测试人', $history[0]['operator']);
|
||
$this->assertSame('编辑', $history[0]['operation']);
|
||
$this->assertSame('采购价:65->63', $history[0]['remark']);
|
||
$this->assertSame('63', (string) $history[0]['after_price']);
|
||
$this->assertTrue($this->repository->syncStatus()['initialized']);
|
||
}
|
||
|
||
public function test_incremental_empty_page_and_failed_run_keep_previous_history(): void
|
||
{
|
||
DB::connection('business_mirror')->table(JushuitanCostPriceHistoryMirrorRepository::TABLE)->insert([
|
||
'operation_id' => 'existing',
|
||
'sku_id' => 'SKU-KEEP',
|
||
'sku_id_normalized' => 'SKU-KEEP',
|
||
'operation_description' => '采购价:20->18',
|
||
'operated_at' => '2026-06-01 00:00:00',
|
||
'before_price' => 20,
|
||
'after_price' => 18,
|
||
'diff_amount' => -2,
|
||
'_mirror_generation' => 'old-generation',
|
||
'row_hash' => hash('sha256', 'existing'),
|
||
'_mirror_synced_at' => '2026-06-01 00:00:00',
|
||
]);
|
||
DB::connection('business_mirror')->table(JushuitanCostPriceHistoryMirrorRepository::STATE_TABLE)->insert([
|
||
'dataset_key' => JushuitanCostPriceHistoryMirrorRepository::DATASET_KEY,
|
||
'status' => 'succeeded',
|
||
'run_mode' => 'incremental',
|
||
'generation' => '22222222-2222-4222-8222-222222222222',
|
||
'window_started_at' => '2026-06-01 00:00:00',
|
||
'window_ends_at' => '2026-06-03 00:00:00',
|
||
'initial_completed_at' => '2026-06-01 00:00:00',
|
||
'last_succeeded_at' => '2026-06-01 00:00:00',
|
||
]);
|
||
|
||
$this->repository->storePage(
|
||
[],
|
||
Carbon::parse('2026-06-03'),
|
||
1,
|
||
'22222222-2222-4222-8222-222222222222',
|
||
0,
|
||
0,
|
||
);
|
||
$this->repository->fail('upstream_unavailable');
|
||
|
||
$this->assertSame(1, DB::connection('business_mirror')->table(JushuitanCostPriceHistoryMirrorRepository::TABLE)->count());
|
||
$this->assertSame('failed', $this->repository->state()['status']);
|
||
}
|
||
|
||
public function test_empty_full_sync_keeps_existing_audit_history(): void
|
||
{
|
||
DB::connection('business_mirror')->table(JushuitanCostPriceHistoryMirrorRepository::TABLE)->insert([
|
||
'operation_id' => 'existing',
|
||
'sku_id' => 'SKU-KEEP',
|
||
'sku_id_normalized' => 'SKU-KEEP',
|
||
'operation_description' => '采购价:20->18',
|
||
'operated_at' => '2026-06-01 00:00:00',
|
||
'before_price' => 20,
|
||
'after_price' => 18,
|
||
'diff_amount' => -2,
|
||
'_mirror_generation' => 'old-generation',
|
||
'row_hash' => hash('sha256', 'existing'),
|
||
'_mirror_synced_at' => '2026-06-01 00:00:00',
|
||
]);
|
||
$generation = '33333333-3333-4333-8333-333333333333';
|
||
$this->repository->startRun(
|
||
'full',
|
||
$generation,
|
||
Carbon::parse('2026-06-01'),
|
||
Carbon::parse('2026-07-01'),
|
||
false,
|
||
);
|
||
|
||
$this->repository->complete(
|
||
'full',
|
||
$generation,
|
||
Carbon::parse('2026-07-01'),
|
||
0,
|
||
0,
|
||
);
|
||
|
||
$this->assertSame(1, DB::connection('business_mirror')->table(JushuitanCostPriceHistoryMirrorRepository::TABLE)->count());
|
||
$this->assertSame('succeeded', $this->repository->state()['status']);
|
||
}
|
||
|
||
private function createTables(): void
|
||
{
|
||
Schema::connection('business_mirror')->create(JushuitanCostPriceHistoryMirrorRepository::STATE_TABLE, function (Blueprint $table): void {
|
||
$table->string('dataset_key')->primary();
|
||
$table->string('status')->default('pending');
|
||
$table->string('run_mode')->nullable();
|
||
$table->string('generation')->nullable();
|
||
$table->dateTime('window_started_at')->nullable();
|
||
$table->dateTime('window_ends_at')->nullable();
|
||
$table->dateTime('cursor_window_started_at')->nullable();
|
||
$table->unsignedInteger('cursor_page')->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_processed_source_rows')->default(0);
|
||
$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(JushuitanCostPriceHistoryMirrorRepository::TABLE, function (Blueprint $table): void {
|
||
$table->string('operation_id')->primary();
|
||
$table->string('sku_id');
|
||
$table->string('sku_id_normalized');
|
||
$table->string('i_id')->nullable();
|
||
$table->string('product_name')->nullable();
|
||
$table->string('properties_value')->nullable();
|
||
$table->string('sku_type')->nullable();
|
||
$table->string('operation_type')->nullable();
|
||
$table->text('operation_description')->nullable();
|
||
$table->string('operator_name')->nullable();
|
||
$table->dateTime('operated_at')->nullable();
|
||
$table->decimal('before_price', 20, 4)->nullable();
|
||
$table->decimal('after_price', 20, 4)->nullable();
|
||
$table->decimal('diff_amount', 20, 4)->nullable();
|
||
$table->string('_mirror_generation')->nullable();
|
||
$table->string('row_hash');
|
||
$table->dateTime('_mirror_synced_at');
|
||
$table->timestamps();
|
||
});
|
||
}
|
||
}
|