128 lines
5.9 KiB
PHP
128 lines
5.9 KiB
PHP
<?php
|
|
|
|
namespace Tests\Unit\EcommerceFinance;
|
|
|
|
use Modules\EcommerceFinance\Services\AccountMappingResyncDispatcher;
|
|
use Modules\EcommerceFinance\Services\AccountMappingStore;
|
|
use Illuminate\Database\Schema\Blueprint;
|
|
use Illuminate\Support\Facades\DB;
|
|
use Illuminate\Support\Facades\Schema;
|
|
use ReflectionClass;
|
|
use Tests\TestCase;
|
|
|
|
class AccountMappingResyncDispatcherTest extends TestCase
|
|
{
|
|
public function test_identical_and_display_only_changes_do_not_require_receipt_rebuilds(): void
|
|
{
|
|
$rule = ['platform' => '京东', 'item' => '测试货款', 'memo' => '收入', 'basis' => '收入', 'feeMemo' => '说明'];
|
|
$this->assertFalse(AccountMappingStore::requiresReceiptResync($rule, $rule));
|
|
$this->assertFalse(AccountMappingStore::requiresReceiptResync($rule, array_replace($rule, ['feeMemo' => '更新说明'])));
|
|
$this->assertTrue(AccountMappingStore::requiresReceiptResync($rule, array_replace($rule, ['memo' => '退款'])));
|
|
$this->assertTrue(AccountMappingStore::requiresReceiptResync($rule, array_replace($rule, ['platform' => '抖音'])));
|
|
}
|
|
|
|
public function test_only_existing_platform_month_pairs_are_enqueued(): void
|
|
{
|
|
config(['upstream_pipeline.batch_worker_enabled' => true]);
|
|
$schema = Schema::connection('business_mirror');
|
|
$schema->dropIfExists('store_receipt_order_match_rows');
|
|
$schema->create('store_receipt_order_match_rows', function (Blueprint $table): void {
|
|
$table->string('platform');
|
|
$table->date('report_month');
|
|
});
|
|
if (! Schema::hasTable(AccountMappingResyncDispatcher::JOBS_TABLE)) {
|
|
Schema::create(AccountMappingResyncDispatcher::JOBS_TABLE, function (Blueprint $table): void {
|
|
$table->increments('id');
|
|
$table->string('platform');
|
|
$table->string('month');
|
|
$table->string('status');
|
|
$table->text('message')->nullable();
|
|
$table->timestamps();
|
|
});
|
|
}
|
|
DB::table(AccountMappingResyncDispatcher::JOBS_TABLE)->delete();
|
|
DB::connection('business_mirror')->table('store_receipt_order_match_rows')->insert([
|
|
['platform' => '淘系支付宝', 'report_month' => '2026-09-01'],
|
|
['platform' => '淘系微信', 'report_month' => '2026-10-01'],
|
|
]);
|
|
$this->assertSame(['jobs' => 2], app(AccountMappingResyncDispatcher::class)->dispatchFor(['淘宝']));
|
|
$this->assertSame(['2026-09'], DB::table(AccountMappingResyncDispatcher::JOBS_TABLE)->where('platform', 'taobao-alipay')->pluck('month')->all());
|
|
$this->assertSame(['2026-10'], DB::table(AccountMappingResyncDispatcher::JOBS_TABLE)->where('platform', 'taobao-wechat')->pluck('month')->all());
|
|
}
|
|
|
|
public function test_reimporting_unchanged_rules_does_not_invalidate_history(): void
|
|
{
|
|
$originalStorage = $this->app->storagePath();
|
|
$directory = sys_get_temp_dir() . '/mapping-resync-' . bin2hex(random_bytes(6));
|
|
\Illuminate\Support\Facades\File::makeDirectory($directory . '/app', 0777, true);
|
|
$this->app->useStoragePath($directory);
|
|
try {
|
|
$store = app(AccountMappingStore::class);
|
|
$store->reset();
|
|
$rows = [['platform' => '京东', 'item' => '测试资源优化项目', 'memo' => '收入']];
|
|
$this->assertSame(['京东'], $store->importRows($rows, true)['resync_platforms']);
|
|
$same = $store->importRows($rows, true);
|
|
$this->assertSame(0, $same['updated']);
|
|
$this->assertSame([], $same['resync_platforms']);
|
|
$this->assertSame([], $store->importRows([array_replace($rows[0], ['feeMemo' => '更新说明'])], true)['resync_platforms']);
|
|
$this->assertSame(['京东'], $store->importRows([array_replace($rows[0], ['basis' => AccountMappingStore::BASIS_IN])], true)['resync_platforms']);
|
|
} finally {
|
|
$this->app->useStoragePath($originalStorage);
|
|
\Illuminate\Support\Facades\File::deleteDirectory($directory);
|
|
(new \ReflectionProperty(AccountMappingStore::class, 'allMemo'))->setValue(null);
|
|
}
|
|
}
|
|
public function test_production_leaves_queue_processing_to_the_limited_batch_worker(): void
|
|
{
|
|
config(['upstream_pipeline.batch_worker_enabled' => true]);
|
|
$dispatcher = $this->recordingDispatcher();
|
|
$dispatcher->spawnWorker();
|
|
|
|
$this->assertSame(0, $dispatcher->launches);
|
|
}
|
|
|
|
public function test_local_development_still_launches_an_immediate_worker(): void
|
|
{
|
|
config(['upstream_pipeline.batch_worker_enabled' => false]);
|
|
$dispatcher = $this->recordingDispatcher();
|
|
$dispatcher->spawnWorker();
|
|
|
|
$this->assertSame(1, $dispatcher->launches);
|
|
}
|
|
|
|
private function recordingDispatcher(): AccountMappingResyncDispatcher
|
|
{
|
|
return new class extends AccountMappingResyncDispatcher {
|
|
public int $launches = 0;
|
|
|
|
protected function launchWorker(): void
|
|
{
|
|
$this->launches++;
|
|
}
|
|
};
|
|
}
|
|
|
|
public function test_all_taobao_family_platforms_trigger_the_matching_receipt_sources(): void
|
|
{
|
|
$reflection = new ReflectionClass(AccountMappingResyncDispatcher::class);
|
|
$map = $reflection->getConstant('PLATFORM_MAP');
|
|
|
|
$this->assertSame(
|
|
[['taobao-alipay', '淘系支付宝'], ['taobao-wechat', '淘系微信']],
|
|
$map['淘宝']
|
|
);
|
|
$this->assertSame(
|
|
[['taobao-alipay', '淘系支付宝'], ['taobao-wechat', '淘系微信']],
|
|
$map['天猫']
|
|
);
|
|
$this->assertSame([['taobao-alipay', '淘系支付宝']], $map['阿里巴巴']);
|
|
}
|
|
|
|
public function test_platform_without_receipt_sync_is_a_noop(): void
|
|
{
|
|
$result = app(AccountMappingResyncDispatcher::class)->dispatchFor(['唯品会JX']);
|
|
|
|
$this->assertSame(['jobs' => 0], $result);
|
|
}
|
|
}
|