- 店铺维度报表按期初数据+系统主体+爬虫新主体生成主体期间,一行一期间,修复流程历史重复行 - 变更日当天归新主体、老主体失效显示变更日前一天;关店和其他非正常状态两列显示 - - 新增店铺维度报表逻辑配置页(R1-R8)、主体商标数据逻辑配置页和预警页面 - 爬虫店铺主体按税号归一,首次抓到的新主体写入期间变更表并自动生成新期间 - 店铺基础信息、商标展示按爬虫优先;新增爬虫数据质量检查与预警处理
212 lines
14 KiB
PHP
212 lines
14 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\BusinessInformationMirrorRepository;
|
|
use Modules\EcommerceFinance\Repositories\GenericBusinessMirrorRepository;
|
|
use Modules\EcommerceFinance\Services\BusinessMirrorDatasetRegistry;
|
|
use Tests\TestCase;
|
|
|
|
class BusinessInformationMirrorRepositoryTest extends TestCase
|
|
{
|
|
private BusinessInformationMirrorRepository $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' => [
|
|
'operations_replica.rpt.fys_companyInfo' => $this->definition('fys_companyInfo', 'ops_fys_company_info'),
|
|
'operations_replica.rpt.fys_shopInfo' => $this->definition('fys_shopInfo', 'ops_fys_shop_info'),
|
|
'operations_replica.rpt.fys_TrademarkInfo' => $this->definition('fys_TrademarkInfo', 'ops_fys_trademark_info'),
|
|
],
|
|
]);
|
|
DB::purge('business_mirror');
|
|
|
|
$this->createTables();
|
|
$mirror = new GenericBusinessMirrorRepository(app('db'));
|
|
$this->repository = new BusinessInformationMirrorRepository(
|
|
new BusinessMirrorDatasetRegistry(),
|
|
$mirror,
|
|
);
|
|
}
|
|
|
|
public function test_it_reads_all_three_ready_mirrors_with_pagination_and_business_filters(): void
|
|
{
|
|
$connection = DB::connection('business_mirror');
|
|
$connection->table('ops_fys_company_info')->insert([
|
|
$this->company(1, '统一代码', '旧公司'),
|
|
$this->company(2, '统一代码', '新公司'),
|
|
$this->company(3, '其他代码', '其他公司'),
|
|
]);
|
|
$connection->table('ops_fys_shop_info')->insert([
|
|
['Id' => 8, 'openTime' => '2026-08-14 10:00:00', 'shopName' => '上游店铺名', 'erpShopName' => '测试店', 'unifiedSocialCreditCode' => '统一代码', 'trademarkNumber' => 'TM', 'platform' => '天猫', 'responsibleDepartment' => '电商', 'shopHead' => '负责人', 'shopState' => '0', 'shopType' => '直营', 'channelType' => '线上'],
|
|
]);
|
|
$connection->table('ops_fys_trademark_info')->insert([
|
|
['Id' => 5, 'trademarkNumber' => 'TM', 'trademarkName' => '有效商标', 'internationalClassification' => '20', 'trademarkStatus' => '1', 'registrationDate' => '2020-01-01', 'termOfValidity' => '2030-01-01', 'remark' => null, 'isDelete' => 0],
|
|
['Id' => 6, 'trademarkNumber' => 'TM', 'trademarkName' => '已删除', 'internationalClassification' => '20', 'trademarkStatus' => '0', 'registrationDate' => null, 'termOfValidity' => null, 'remark' => null, 'isDelete' => 1],
|
|
]);
|
|
$this->markReady();
|
|
$connection->table('ops_fys_company_info')->where('Id', 1)->update(['registeredCapitalVaildTime' => '2027-01-01']);
|
|
$connection->table('ops_fys_company_info')->where('Id', 2)->update([
|
|
'businessLicenseType' => '店铺-普通公司',
|
|
'taxCategoryAndType' => '小规模纳税人',
|
|
'legalRepresentative' => '张三',
|
|
'registeredAddress' => '上海市浦东新区测试路1号',
|
|
]);
|
|
$connection->table('ops_fys_shop_info')->where('Id', 8)->update(['sotreId' => 'STORE-8', 'renewalTime' => '2027-08-14', 'shopBankAccount' => 'fixture-account', 'trademarkNumber' => 'TM-5']);
|
|
$connection->table('ops_fys_trademark_info')->where('Id', 5)->update(['trademarkNumber' => 'TM-5', 'approvedCommodities' => '家具', 'transferenceUser' => '测试持有人', 'registrationAddress' => '测试地址', 'custodyDepartment' => '资料部']);
|
|
|
|
$companies = $this->repository->paginate('company-information.read', 2, 2);
|
|
$store = $this->repository->paginate('store-information.read', 1, 20);
|
|
$trademarks = $this->repository->paginate('trademark-information.read', 1, 20);
|
|
$receivingStores = $this->repository->receivingAccountStores();
|
|
$filteredStore = $this->repository->paginate('store-information.read', 1, 20, [
|
|
'platform' => '天猫', 'store_status' => '0', 'opened_at_from' => '2026-08-14',
|
|
]);
|
|
$filteredTrademark = $this->repository->paginate('trademark-information.read', 1, 20, [
|
|
'trademark_status' => '1', 'registration_date_from' => '2020-01-01',
|
|
]);
|
|
$filteredCompany = $this->repository->paginate('company-information.read', 1, 20, ['company_name' => '新公司']);
|
|
$relatedCompany = $this->repository->paginate('company-information.read', 1, 20, ['related_people' => '张']);
|
|
$typedCompany = $this->repository->paginate('company-information.read', 1, 20, [
|
|
'taxpayer_type' => '小规模纳税人', 'company_status' => '正常', 'company_type' => '店铺-普通公司',
|
|
]);
|
|
$cityCompany = $this->repository->paginate('company-information.read', 1, 20, ['city' => '上海']);
|
|
|
|
$this->assertSame(3, $companies['total']);
|
|
$this->assertSame(1, $companies['data'][0]['id']);
|
|
$this->assertSame('新公司', $store['data'][0]['company_name']);
|
|
$this->assertSame('有效商标', $store['data'][0]['trademark_name']);
|
|
$this->assertSame(1, $trademarks['total']);
|
|
$this->assertSame('有效商标', $trademarks['data'][0]['trademark_name']);
|
|
$this->assertSame('2027-01-01', $companies['data'][0]['subscribed_at']);
|
|
$this->assertSame('STORE-8', $store['data'][0]['store_id']);
|
|
$this->assertSame('2027-08-14', $store['data'][0]['renewed_at']);
|
|
$this->assertSame('负责人', $store['data'][0]['store_manager']);
|
|
$this->assertSame('上游店铺名', $receivingStores[0]['shop_name']);
|
|
$this->assertSame('天猫', $receivingStores[0]['source_platform']);
|
|
$this->assertSame('新公司', $receivingStores[0]['company_name']);
|
|
$this->assertSame('fixture-account', $store['data'][0]['withdrawal_account']);
|
|
$this->assertSame('TM-5', $trademarks['data'][0]['trademark_number']);
|
|
$this->assertSame('家具', $trademarks['data'][0]['approved_goods']);
|
|
$this->assertSame('测试持有人', $trademarks['data'][0]['final_holder']);
|
|
$this->assertSame(1, $filteredStore['total']);
|
|
$this->assertSame(1, $filteredTrademark['total']);
|
|
$this->assertSame('新公司', $filteredCompany['data'][0]['company_name']);
|
|
$this->assertSame('新公司', $relatedCompany['data'][0]['company_name']);
|
|
$this->assertSame(1, $typedCompany['total']);
|
|
$this->assertSame(1, $cityCompany['total']);
|
|
}
|
|
|
|
public function test_dataset_is_not_ready_until_initial_full_sync_is_marked_complete(): void
|
|
{
|
|
$this->assertFalse($this->repository->ready('company-information.read'));
|
|
$this->markReady(['operations_replica.rpt.fys_companyInfo']);
|
|
$this->assertTrue($this->repository->ready('company-information.read'));
|
|
}
|
|
|
|
private function createTables(): void
|
|
{
|
|
$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();
|
|
});
|
|
$schema->create('ops_fys_company_info', function (Blueprint $table): void {
|
|
$table->integer('Id'); $table->string('unifiedSocialCreditCode')->nullable(); $table->string('businessLicenseName')->nullable();
|
|
$table->string('registeredCapital')->nullable(); $table->string('businessLicenseType')->nullable(); $table->dateTime('IncorporationDate')->nullable();
|
|
$table->string('legalRepresentative')->nullable(); $table->string('registeredAddress')->nullable(); $table->text('businessScope')->nullable();
|
|
$table->string('accountSerialNumber')->nullable(); $table->string('companyStatus')->nullable(); $table->string('financialManager')->nullable();
|
|
$table->string('supervisor')->nullable(); $table->string('taxCategoryAndType')->nullable();
|
|
$table->dateTime('registeredCapitalVaildTime')->nullable();
|
|
});
|
|
$schema->create('ops_fys_shop_info', function (Blueprint $table): void {
|
|
$table->integer('Id'); $table->dateTime('openTime')->nullable(); $table->string('shopName')->nullable(); $table->string('erpShopName')->nullable(); $table->string('unifiedSocialCreditCode')->nullable();
|
|
$table->string('trademarkNumber')->nullable(); $table->string('platform')->nullable(); $table->string('responsibleDepartment')->nullable();
|
|
$table->string('shopHead')->nullable(); $table->string('customerDeptManager')->nullable(); $table->string('shopState')->nullable(); $table->string('shopType')->nullable(); $table->string('channelType')->nullable();
|
|
$table->string('sotreId')->nullable(); $table->dateTime('renewalTime')->nullable(); $table->string('shopBankAccount')->nullable();
|
|
});
|
|
$schema->create('ops_fys_trademark_info', function (Blueprint $table): void {
|
|
$table->integer('Id'); $table->string('trademarkNumber')->nullable(); $table->string('trademarkName')->nullable(); $table->string('internationalClassification')->nullable();
|
|
$table->string('trademarkStatus')->nullable(); $table->dateTime('registrationDate')->nullable(); $table->dateTime('termOfValidity')->nullable();
|
|
$table->text('remark')->nullable(); $table->integer('isDelete')->default(0);
|
|
foreach (['approvedCommodities', 'transferenceUser', 'registrationAddress', 'custodyDepartment'] as $column) $table->string($column)->nullable();
|
|
});
|
|
}
|
|
|
|
public function test_crawler_company_and_trademark_take_priority_over_flow_snapshot(): void
|
|
{
|
|
$schema = Schema::connection('business_mirror');
|
|
$schema->create('ops_crawl_shop_company', function (Blueprint $table): void {
|
|
$table->integer('id'); $table->string('shop_name'); $table->string('company_name')->nullable();
|
|
$table->string('tax_no')->nullable(); $table->string('crawl_date')->nullable(); $table->dateTime('update_time')->nullable();
|
|
});
|
|
$schema->create('ops_crawl_shop_trademark', function (Blueprint $table): void {
|
|
$table->integer('id'); $table->string('shop_name'); $table->string('trademark_no')->nullable();
|
|
$table->string('trademark_name')->nullable(); $table->string('crawl_date')->nullable(); $table->dateTime('update_time')->nullable();
|
|
});
|
|
|
|
$connection = DB::connection('business_mirror');
|
|
$connection->table('ops_fys_company_info')->insert([
|
|
$this->company(1, '工商代码', '系统登记主体'),
|
|
$this->company(2, '抓取代码', '爬虫抓取主体'),
|
|
]);
|
|
$connection->table('ops_fys_shop_info')->insert([
|
|
['Id' => 21, 'openTime' => '2026-08-14 10:00:00', 'shopName' => '上游店铺名', 'erpShopName' => '测试店', 'unifiedSocialCreditCode' => '工商代码', 'trademarkNumber' => '旧商标号', 'platform' => '京东', 'responsibleDepartment' => '电商', 'shopHead' => '负责人', 'shopState' => '0', 'shopType' => '直营', 'channelType' => '线上'],
|
|
]);
|
|
$connection->table('ops_fys_trademark_info')->insert([
|
|
['Id' => 9, 'trademarkNumber' => '旧商标号', 'trademarkName' => '旧商标', 'internationalClassification' => '20', 'trademarkStatus' => '1', 'registrationDate' => null, 'termOfValidity' => null, 'remark' => null, 'isDelete' => 0],
|
|
]);
|
|
$connection->table('ops_crawl_shop_company')->insert([
|
|
['id' => 1, 'shop_name' => '测试店', 'company_name' => '爬虫抓取主体', 'tax_no' => '抓取代码', 'crawl_date' => '2026-09-29', 'update_time' => '2026-09-29 08:00:00'],
|
|
]);
|
|
$connection->table('ops_crawl_shop_trademark')->insert([
|
|
['id' => 1, 'shop_name' => '测试店', 'trademark_no' => '1000', 'trademark_name' => '甲商标', 'crawl_date' => '2026-09-29', 'update_time' => '2026-09-29 08:00:00'],
|
|
['id' => 2, 'shop_name' => '测试店', 'trademark_no' => '2000', 'trademark_name' => '乙商标', 'crawl_date' => '2026-09-29', 'update_time' => '2026-09-29 08:00:00'],
|
|
]);
|
|
$this->markReady(['operations_replica.rpt.fys_shopInfo']);
|
|
|
|
$payload = $this->repository->paginate('store-information.read', 1, 10);
|
|
$this->assertSame('爬虫抓取主体', $payload['data'][0]['company_name']);
|
|
$this->assertSame('系统登记主体', $payload['data'][0]['system_company_name']);
|
|
$this->assertSame('甲商标、乙商标', $payload['data'][0]['trademark_name']);
|
|
$this->assertSame('1000、2000', $payload['data'][0]['trademark_number']);
|
|
|
|
$filtered = $this->repository->paginate('store-information.read', 1, 10, ['trademark_number' => '2000']);
|
|
$this->assertSame(1, $filtered['total']);
|
|
$this->assertSame('测试店', $filtered['data'][0]['erp_store_name']);
|
|
}
|
|
|
|
private function markReady(?array $keys = null): void
|
|
{
|
|
$keys ??= array_keys((array) config('upstream_mirrors.datasets'));
|
|
foreach ($keys as $key) {
|
|
DB::connection('business_mirror')->table('business_mirror_table_states')->insert([
|
|
'dataset_key' => $key,
|
|
'initial_completed_at' => '2026-08-14 12:00:00',
|
|
]);
|
|
}
|
|
}
|
|
|
|
private function definition(string $object, string $target): array
|
|
{
|
|
return ['source_key' => 'operations_replica', 'schema' => 'rpt', 'object' => $object, 'target' => $target, 'keys' => ['Id']];
|
|
}
|
|
|
|
private function company(int $id, string $code, string $name): array
|
|
{
|
|
return ['Id' => $id, 'unifiedSocialCreditCode' => $code, 'businessLicenseName' => $name, 'registeredCapital' => null, 'businessLicenseType' => null, 'IncorporationDate' => null, 'legalRepresentative' => null, 'registeredAddress' => null, 'businessScope' => null, 'accountSerialNumber' => null, 'companyStatus' => '0', 'financialManager' => null, 'supervisor' => null, 'taxCategoryAndType' => null];
|
|
}
|
|
}
|