CaiWuXiTong/tests/Unit/EcommerceFinance/StoreReceivingDewuBillMirrorRepositoryTest.php
yueyang edb32c33cf 接入得物收款账单镜像 (#185)
固定同步 Dewu 主收款渠道,接入得物账户分页、筛选、汇总和导出,并补充镜像与回归测试。

未部署,未执行生产首次同步。
2026-09-15 11:09:03 +08:00

190 lines
8.6 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\StoreReceivingAlipayBillMirrorRepository;
use Modules\EcommerceFinance\Repositories\StoreReceivingDewuBillMirrorRepository;
use Modules\EcommerceFinance\Services\BusinessMirrorDatasetRegistry;
use Tests\TestCase;
class StoreReceivingDewuBillMirrorRepositoryTest extends TestCase
{
private StoreReceivingDewuBillMirrorRepository $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' => [
StoreReceivingDewuBillMirrorRepository::DATASET => [
'source_key' => 'jiansun', 'schema' => 'dbo',
'object' => 'jst_originalBillInfo', 'target' => 'js_jst_dewu_receiving_bill_rows',
'keys' => ['Id'],
'fixed_filters' => ['channel' => StoreReceivingDewuBillMirrorRepository::SOURCE_CHANNEL],
],
StoreReceivingAlipayBillMirrorRepository::SHOP_DATASET => [
'source_key' => 'operations_replica', 'schema' => 'rpt',
'object' => 'jst_shopInfo', 'target' => 'ops_jst_shop_info', 'keys' => ['Id'],
],
],
]);
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->dateTime('initial_completed_at')->nullable();
$table->string('status')->nullable();
$table->dateTime('last_succeeded_at')->nullable();
$table->unsignedBigInteger('mirror_row_count')->nullable();
$table->boolean('mirror_row_count_is_exact')->default(false);
});
$schema->create('js_jst_dewu_receiving_bill_rows', function (Blueprint $table): void {
$table->integer('Id');
$table->integer('shop_id')->nullable();
foreach (['channel', 'primary_key', 'fee_name', 'inout_type', 'p_auto_id', 'shop_i_id', 'shop_sku_id', 'sku_id', 'so_id', 'combine_type'] as $column) {
$table->string($column)->nullable();
}
$table->dateTime('fee_time')->nullable();
$table->dateTime('createTime')->nullable();
$table->dateTime('updateTime')->nullable();
$table->bigInteger('auto_id')->nullable();
$table->decimal('amount', 20, 6)->nullable();
});
$schema->create('ops_jst_shop_info', function (Blueprint $table): void {
$table->integer('Id');
$table->integer('shop_id')->nullable();
$table->string('shop_name')->nullable();
});
$source = new StoreReceivingAlipayBillMirrorRepository(
new BusinessMirrorDatasetRegistry(), new GenericBusinessMirrorRepository(app('db')),
);
$this->repository = new StoreReceivingDewuBillMirrorRepository($source);
$this->markReady();
}
public function test_it_reads_only_the_dewu_dataset_and_maps_available_source_fields(): void
{
DB::connection('business_mirror')->table('ops_jst_shop_info')->insert([
['Id' => 10, 'shop_id' => 7, 'shop_name' => '得物-测试店'],
['Id' => 11, 'shop_id' => 8, 'shop_name' => '其他店'],
]);
DB::connection('business_mirror')->table('js_jst_dewu_receiving_bill_rows')->insert([
$this->row(1, 7, '2026-09-13 18:48:12', '1', 21.00, '交易收入'),
$this->row(2, 7, '2026-09-13 19:00:00', '-1', 18.07, '平台服务费'),
]);
$result = $this->repository->paginate([], 'occurred_at', 'desc', 1, 10);
$this->assertSame(2, $result['total']);
$this->assertSame('200000000000000002', $result['data'][0]['record_code']);
$this->assertSame('得物-测试店', $result['data'][0]['store_name']);
$this->assertSame('110211-ORDER-2', $result['data'][0]['order_no']);
$this->assertSame('Dewu', $result['data'][0]['payload']['channel']);
$this->assertSame('支出', $result['data'][0]['payload']['business_type']);
$this->assertSame('SKU-2', $result['data'][0]['payload']['goods_no']);
$this->assertSame('聚水潭', $result['data'][0]['modifier']);
$this->assertSame(21.0, $result['summary']['income']);
$this->assertSame(18.07, $result['summary']['expense']);
$this->assertSame(2.93, $result['summary']['balance']);
}
public function test_filters_options_export_and_exact_total_use_the_fixed_channel_slice(): void
{
DB::connection('business_mirror')->table('ops_jst_shop_info')->insert([
['Id' => 10, 'shop_id' => 7, 'shop_name' => '得物-A店'],
['Id' => 11, 'shop_id' => 8, 'shop_name' => '得物-B店'],
]);
DB::connection('business_mirror')->table('js_jst_dewu_receiving_bill_rows')->insert([
$this->row(1, 7, '2026-08-12 09:00:00', '1', 22.80, '交易收入'),
$this->row(2, 8, '2026-08-13 09:00:00', '-1', 0.14, '平台服务费'),
]);
$connection = DB::connection('business_mirror');
$connection->table('business_mirror_table_states')
->where('dataset_key', StoreReceivingDewuBillMirrorRepository::DATASET)
->update(['mirror_row_count' => 2, 'mirror_row_count_is_exact' => true]);
$connection->enableQueryLog();
$connection->flushQueryLog();
$unfiltered = $this->repository->paginate([], 'record_code', 'asc', 1, 10);
$filtered = $this->repository->paginate([
'store_name' => 'A店',
'bill_item' => '交易',
'start' => '2026-08-12',
'end' => '2026-08-12',
'keyword' => '110211-ORDER-1',
], 'record_code', 'asc', 1, 10);
$options = $this->repository->filterOptions();
$export = iterator_to_array($this->repository->exportRows(['bill_item' => '平台服务费']));
$this->assertSame(2, $unfiltered['total']);
$this->assertSame(1, $filtered['total']);
$this->assertSame('200000000000000001', $filtered['data'][0]['record_code']);
$this->assertSame(['得物-A店', '得物-B店'], $options['shops']);
$this->assertSame(['交易收入', '平台服务费'], $options['bill_items']);
$this->assertCount(1, $export);
$this->assertSame('200000000000000002', $export[0]['record_code']);
$targetQueries = array_filter(
$connection->getQueryLog(),
static fn (array $query): bool => str_contains($query['query'], 'js_jst_dewu_receiving_bill_rows'),
);
$this->assertNotEmpty($targetQueries);
$this->assertCount(0, array_filter(
$targetQueries,
static fn (array $query): bool => str_contains($query['query'], '"b"."channel" = ?'),
));
$connection->disableQueryLog();
}
private function markReady(): void
{
foreach ([StoreReceivingDewuBillMirrorRepository::DATASET, StoreReceivingAlipayBillMirrorRepository::SHOP_DATASET] as $dataset) {
DB::connection('business_mirror')->table('business_mirror_table_states')->insert([
'dataset_key' => $dataset,
'initial_completed_at' => '2026-09-14 09:00:00',
'status' => 'succeeded',
'last_succeeded_at' => '2026-09-14 09:00:00',
]);
}
}
private function row(
int $id,
int $shopId,
string $time,
string $direction,
float $amount,
string $feeName,
): array {
return [
'Id' => $id,
'shop_id' => $shopId,
'channel' => 'Dewu',
'primary_key' => 'KEY-' . $id,
'fee_name' => $feeName,
'inout_type' => $direction,
'p_auto_id' => 'P-' . $id,
'shop_i_id' => 'ITEM-' . $id,
'shop_sku_id' => 'SHOP-SKU-' . $id,
'sku_id' => 'SKU-' . $id,
'so_id' => '110211-ORDER-' . $id,
'combine_type' => 'normal',
'fee_time' => $time,
'createTime' => '2026-09-14 13:00:48',
'updateTime' => '2026-09-14 13:02:32',
'auto_id' => 200000000000000000 + $id,
'amount' => $amount,
];
}
}