256 lines
14 KiB
PHP
256 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\GenericBusinessMirrorRepository;
|
|
use Modules\EcommerceFinance\Repositories\InstallationDetailMirrorRepository;
|
|
use Modules\EcommerceFinance\Services\BusinessMirrorDatasetRegistry;
|
|
use Tests\TestCase;
|
|
|
|
class InstallationDetailMirrorRepositoryTest extends TestCase
|
|
{
|
|
private InstallationDetailMirrorRepository $repository;
|
|
|
|
protected function setUp(): void
|
|
{
|
|
parent::setUp();
|
|
config(['database.connections.business_mirror'=>['driver'=>'sqlite','database'=>':memory:','prefix'=>''], 'upstream_mirrors.connection'=>'business_mirror']);
|
|
DB::purge('business_mirror');
|
|
$definitions=[];
|
|
foreach ([InstallationDetailMirrorRepository::DATASET=>'fixture_install',InstallationDetailMirrorRepository::ITEM_DATASET=>'fixture_items'] as $key=>$table) {
|
|
$definitions[$key]=['source_key'=>'jiansun','schema'=>'dbo','object'=>explode('.',$key)[2],'target'=>$table,'keys'=>['Id']];
|
|
}
|
|
$definitions[InstallationDetailMirrorRepository::DATASET]['minimum_datetime'] = [
|
|
'column' => 'ShipTIme',
|
|
'value' => '2026-01-01 00:00:00',
|
|
];
|
|
config(['upstream_mirrors.datasets'=>$definitions]);
|
|
$schema=Schema::connection('business_mirror');
|
|
$schema->create('business_mirror_table_states',function(Blueprint $t){$t->string('dataset_key')->primary();$t->dateTime('initial_completed_at')->nullable();});
|
|
$schema->create('fixture_install',function(Blueprint $t){
|
|
$t->integer('Id');
|
|
foreach(['SourceGuid','OrderNum','ordernum_id','shop_name','shopcode','SubmitTime','ShipTIme','kfshTime','cwshTime','apistatus','kfsh','cwsh','BidStatus','costtaker','costWay','installComplete','Delete','installCompanyName','TypeDto'] as $c) $t->string($c)->nullable();
|
|
$t->integer('StatusId')->nullable()->default(0);
|
|
foreach(['installcost','settleAmount','acceptAmount'] as $c) $t->decimal($c,14,2)->default(0);
|
|
});
|
|
$schema->create('fixture_items',function(Blueprint $t){
|
|
$t->integer('Id');
|
|
$t->string('guid');
|
|
$t->string('shopproid');
|
|
$t->string('Sourceno')->nullable();
|
|
$t->dateTime('kfshTime')->nullable();
|
|
$t->decimal('settleItemAmount',14,2)->default(0);
|
|
$t->decimal('acceptItemAmount',14,2)->default(0);
|
|
});
|
|
foreach(array_keys($definitions) as $key) DB::connection('business_mirror')->table('business_mirror_table_states')->insert(['dataset_key'=>$key,'initial_completed_at'=>'2026-08-01']);
|
|
DB::connection('business_mirror')->table('fixture_install')->insert([
|
|
['Id'=>1,'SourceGuid'=>'A','OrderNum'=>'OLD','shop_name'=>'旧店','SubmitTime'=>'2026-08-01','ShipTIme'=>'2026-08-02','installcost'=>500],
|
|
['Id'=>2,'SourceGuid'=>'A','OrderNum'=>'NEW','shop_name'=>'测试店','shopcode'=>'SHOP-A','SubmitTime'=>'2026-08-20 23:59:59','ShipTIme'=>'2026-08-21','installcost'=>20],
|
|
['Id'=>3,'SourceGuid'=>'B','OrderNum'=>'OTHER','shop_name'=>'其他店','SubmitTime'=>'2026-08-20','ShipTIme'=>'2026-08-21','installcost'=>30],
|
|
['Id'=>4,'SourceGuid'=>'C','OrderNum'=>'NEXT','shop_name'=>'测试店','SubmitTime'=>'2026-08-21','ShipTIme'=>'2026-08-22','installcost'=>40],
|
|
['Id'=>5,'SourceGuid'=>'D','OrderNum'=>'PRE-2026','shop_name'=>'测试店','SubmitTime'=>'2026-08-21','ShipTIme'=>'2025-12-31 23:59:59','installcost'=>999],
|
|
['Id'=>6,'SourceGuid'=>'E','OrderNum'=>'NULL-SHIP','shop_name'=>'测试店','SubmitTime'=>'2026-08-21','ShipTIme'=>null,'installcost'=>999],
|
|
]);
|
|
DB::connection('business_mirror')->table('fixture_items')->insert([
|
|
['Id'=>1,'guid'=>'A','shopproid'=>'PRODUCT-A'],['Id'=>2,'guid'=>'A','shopproid'=>'PRODUCT-A'],
|
|
]);
|
|
$this->repository=new InstallationDetailMirrorRepository(new GenericBusinessMirrorRepository(app('db')),new BusinessMirrorDatasetRegistry());
|
|
}
|
|
|
|
public function test_filters_apply_to_deduplicated_list_count_and_summary(): void
|
|
{
|
|
$filters=['shop_name'=>'测试店'];
|
|
$page=$this->repository->paginate(2,1,$filters);
|
|
$this->assertSame(2,$page['total']);
|
|
$this->assertSame(2,$page['data'][0]['id']);
|
|
$this->assertSame(60.0,$this->repository->summary($filters)['requested']);
|
|
$filters['created_to']='2026-08-20';
|
|
$this->assertSame(1,$this->repository->paginate(1,50,$filters)['total']);
|
|
$this->assertSame(20.0,$this->repository->summary($filters)['requested']);
|
|
$this->assertSame(0,$this->repository->paginate(1,50,['shop_name'=>"' OR 1=1 --"])['total']);
|
|
$this->assertSame(1,$this->repository->paginate(1,50,['shop_code'=>'SHOP-A'])['total']);
|
|
}
|
|
|
|
public function test_product_filter_does_not_multiply_main_rows(): void
|
|
{
|
|
$filters=['product_id'=>'PRODUCT-A'];
|
|
$this->assertSame(1,$this->repository->paginate(1,50,$filters)['total']);
|
|
$this->assertSame(20.0,$this->repository->summary($filters)['requested']);
|
|
$this->assertSame('NEW',$this->repository->details('A')['data'][0]['transaction_no']);
|
|
$this->assertSame([],$this->repository->details('missing')['data']);
|
|
}
|
|
|
|
public function test_shipment_cutoff_hides_old_and_null_records_from_list_summary_and_details(): void
|
|
{
|
|
DB::connection('business_mirror')->table('fixture_items')->insert([
|
|
['Id'=>30,'guid'=>'D','shopproid'=>'OLD-PRODUCT'],
|
|
['Id'=>31,'guid'=>'E','shopproid'=>'NULL-PRODUCT'],
|
|
]);
|
|
|
|
$this->assertSame(3,$this->repository->paginate(1,50)['total']);
|
|
$this->assertSame(3,$this->repository->summary()['rows']);
|
|
$this->assertSame([],$this->repository->details('D')['data']);
|
|
$this->assertSame([],$this->repository->details('E')['data']);
|
|
}
|
|
|
|
public function test_status_filters_and_child_limit_are_explicit(): void
|
|
{
|
|
DB::connection('business_mirror')->table('fixture_install')->where('Id',2)->update(['kfsh'=>'1','Delete'=>'0','StatusId'=>2]);
|
|
$this->assertSame(1,$this->repository->paginate(1,50,['customer_review'=>'1','delete_status'=>'0','arranged_status'=>'1'])['total']);
|
|
$rows=[];for($i=1;$i<=101;$i++)$rows[]=['Id'=>$i+10,'guid'=>'B','shopproid'=>'P'.$i];
|
|
DB::connection('business_mirror')->table('fixture_items')->insert($rows);
|
|
$result=$this->repository->details('B');
|
|
$this->assertCount(100,$result['data']);
|
|
$this->assertTrue($result['has_more']);
|
|
}
|
|
|
|
public function test_unset_status_filters_include_null_values_and_render_explicit_labels(): void
|
|
{
|
|
DB::connection('business_mirror')->table('fixture_install')->where('Id',3)->update(['StatusId'=>null]);
|
|
|
|
foreach (['customer_review','finance_review','completed_status','delete_status','arranged_status'] as $key) {
|
|
$this->assertSame(3,$this->repository->paginate(1,50,[$key=>'0'])['total'],$key);
|
|
}
|
|
|
|
$other=$this->repository->paginate(1,50,['shop_name'=>'其他店'])['data'][0];
|
|
$this->assertSame('未审核',$other['customer_service_review']);
|
|
$this->assertSame('未审核',$other['finance_review']);
|
|
$this->assertSame('否',$other['completed_status']);
|
|
$this->assertSame('未安排',$other['arranged_status']);
|
|
|
|
DB::connection('business_mirror')->table('fixture_install')->where('Id',2)->update([
|
|
'kfsh'=>1,
|
|
'cwsh'=>1,
|
|
'installComplete'=>1,
|
|
'Delete'=>0,
|
|
'StatusId'=>1,
|
|
]);
|
|
foreach (['customer_review','finance_review','completed_status','arranged_status'] as $key) {
|
|
$this->assertSame(1,$this->repository->paginate(1,50,[$key=>'1'])['total'],$key);
|
|
}
|
|
}
|
|
|
|
public function test_fee_details_use_customer_review_time_and_latest_main_channel(): void
|
|
{
|
|
DB::connection('business_mirror')->table('fixture_install')->where('Id',1)->update(['installCompanyName'=>'旧公司']);
|
|
DB::connection('business_mirror')->table('fixture_install')->where('Id',2)->update(['installCompanyName'=>'万师傅','costWay'=>null]);
|
|
DB::connection('business_mirror')->table('fixture_install')->where('Id',3)->update(['installCompanyName'=>'鲁班到家','costWay'=>'银行转账']);
|
|
DB::connection('business_mirror')->table('fixture_install')->where('Id',4)->update(['installCompanyName'=>'万师傅']);
|
|
DB::connection('business_mirror')->table('fixture_items')->insert([
|
|
['Id'=>19,'guid'=>'A','shopproid'=>'P0','Sourceno'=>'A-0','kfshTime'=>'2026-08-15 10:00:00','settleItemAmount'=>90.00,'acceptItemAmount'=>80.00],
|
|
['Id'=>20,'guid'=>'A','shopproid'=>'P1','Sourceno'=>'A-1','kfshTime'=>'2026-09-01 09:00:00','settleItemAmount'=>60.10,'acceptItemAmount'=>40.00],
|
|
['Id'=>21,'guid'=>'A','shopproid'=>'P2','Sourceno'=>'A-1','kfshTime'=>'2026-09-30 18:00:00','settleItemAmount'=>39.90,'acceptItemAmount'=>0.00],
|
|
['Id'=>22,'guid'=>'B','shopproid'=>'P3','Sourceno'=>'B-1','kfshTime'=>'2026-09-15 10:00:00','settleItemAmount'=>80.00,'acceptItemAmount'=>70.00],
|
|
['Id'=>23,'guid'=>'C','shopproid'=>'P4','Sourceno'=>'C-1','kfshTime'=>'2026-10-01 00:00:00','settleItemAmount'=>500.00,'acceptItemAmount'=>500.00],
|
|
['Id'=>24,'guid'=>'D','shopproid'=>'OLD','Sourceno'=>'D-1','kfshTime'=>'2026-09-10 10:00:00','settleItemAmount'=>999.00,'acceptItemAmount'=>999.00],
|
|
['Id'=>25,'guid'=>'E','shopproid'=>'NULL','Sourceno'=>'E-1','kfshTime'=>'2026-09-10 10:00:00','settleItemAmount'=>999.00,'acceptItemAmount'=>999.00],
|
|
]);
|
|
|
|
$result=$this->repository->feeDetails([
|
|
'customer_review_from'=>'2026-09-01',
|
|
'customer_review_to'=>'2026-09-30',
|
|
]);
|
|
|
|
$this->assertTrue($result['ready']);
|
|
$this->assertSame([
|
|
['platform'=>'其他','store_name'=>'测试店','installation_company'=>'万师傅','payment_channel'=>'包安装','amount'=>100.0],
|
|
['platform'=>'其他','store_name'=>'其他店','installation_company'=>'鲁班到家','payment_channel'=>'不包安装','amount'=>80.0],
|
|
],$result['rows']);
|
|
$this->assertSame(180.0,$result['total']);
|
|
$this->assertSame(90.0,$result['previous_total']);
|
|
$this->assertSame('2026-08-01',$result['previous_from']);
|
|
$this->assertSame('2026-08-31',$result['previous_to']);
|
|
$this->assertSame(100.0,$result['change_rate']);
|
|
}
|
|
|
|
public function test_fee_details_classifies_platform_by_store_name_rules(): void
|
|
{
|
|
$stores = [
|
|
'阿里巴巴-测试店' => '淘系',
|
|
'天猫-测试店' => '淘系',
|
|
'新佰广1688' => '淘系',
|
|
'淘工厂-测试店' => '淘系',
|
|
'淘宝-测试店' => '淘系',
|
|
'抖音-测试店' => '抖音',
|
|
'拼多多-测试店' => '拼多多',
|
|
'唯品会MP-测试店' => '唯品会',
|
|
'唯品会-测试店' => '其他',
|
|
'得物-测试店' => '得物',
|
|
'京东-测试店' => '京东',
|
|
'京喜-测试店' => '京喜',
|
|
'其他平台店铺' => '其他',
|
|
];
|
|
$mainRows = [];
|
|
$itemRows = [];
|
|
$id = 100;
|
|
foreach (array_keys($stores) as $store) {
|
|
$guid = 'platform-' . $id;
|
|
$mainRows[] = [
|
|
'Id' => $id,
|
|
'SourceGuid' => $guid,
|
|
'OrderNum' => 'ORDER-' . $id,
|
|
'shop_name' => $store,
|
|
'SubmitTime' => '2026-09-01',
|
|
'ShipTIme' => '2026-09-02',
|
|
'installCompanyName' => '万师傅',
|
|
'costWay' => null,
|
|
];
|
|
$itemRows[] = [
|
|
'Id' => $id,
|
|
'guid' => $guid,
|
|
'shopproid' => 'PRODUCT-' . $id,
|
|
'kfshTime' => '2026-09-15 10:00:00',
|
|
'settleItemAmount' => 1,
|
|
];
|
|
$id++;
|
|
}
|
|
DB::connection('business_mirror')->table('fixture_install')->insert($mainRows);
|
|
DB::connection('business_mirror')->table('fixture_items')->insert($itemRows);
|
|
|
|
$result = $this->repository->feeDetails([
|
|
'customer_review_from' => '2026-09-01',
|
|
'customer_review_to' => '2026-09-30',
|
|
]);
|
|
$actual = collect($result['rows'])->pluck('platform', 'store_name')->all();
|
|
|
|
foreach ($stores as $store => $platform) {
|
|
$this->assertSame($platform, $actual[$store] ?? null, $store);
|
|
}
|
|
}
|
|
|
|
public function test_end_date_alone_is_valid_and_invalid_status_is_rejected(): void
|
|
{
|
|
request()->merge(['created_to'=>'2026-08-20']);
|
|
$this->assertSame(['created_to'=>'2026-08-20'],InstallationDetailMirrorRepository::requestFilters());
|
|
request()->merge(['arranged_status'=>'unexpected']);
|
|
$this->expectException(\Illuminate\Validation\ValidationException::class);
|
|
InstallationDetailMirrorRepository::requestFilters();
|
|
}
|
|
|
|
public function test_unified_time_scope_maps_to_the_selected_legacy_date_range(): void
|
|
{
|
|
request()->merge([
|
|
'time_scope' => 'finance_review',
|
|
'date_from' => '2026-08-01',
|
|
'date_to' => '2026-08-31',
|
|
'created_from' => '2026-07-01',
|
|
'created_to' => '2026-07-31',
|
|
'shop_name' => '测试店',
|
|
]);
|
|
|
|
$filters = InstallationDetailMirrorRepository::requestFilters();
|
|
|
|
$this->assertSame('finance_review', $filters['time_scope']);
|
|
$this->assertSame('2026-08-01', $filters['date_from']);
|
|
$this->assertSame('2026-08-31', $filters['date_to']);
|
|
$this->assertSame('2026-08-01', $filters['finance_review_from']);
|
|
$this->assertSame('2026-08-31', $filters['finance_review_to']);
|
|
$this->assertSame('测试店', $filters['shop_name']);
|
|
$this->assertArrayNotHasKey('created_from', $filters);
|
|
$this->assertArrayNotHasKey('created_to', $filters);
|
|
}
|
|
}
|