152 lines
7.0 KiB
PHP
152 lines
7.0 KiB
PHP
<?php
|
|
|
|
namespace Tests\Unit\EcommerceFinance;
|
|
|
|
use App\Business\UpstreamBusinessInformation;
|
|
use Illuminate\Database\Schema\Blueprint;
|
|
use Illuminate\Support\Facades\DB;
|
|
use Illuminate\Support\Facades\Schema;
|
|
use Mockery;
|
|
use Modules\EcommerceFinance\Repositories\BusinessInformationMirrorRepository;
|
|
use Modules\EcommerceFinance\Repositories\InstallationDetailMirrorRepository;
|
|
use Modules\EcommerceFinance\Repositories\StoreReportRepository;
|
|
use Modules\EcommerceFinance\Services\UpstreamQueryCacheFactory;
|
|
use Tests\TestCase;
|
|
|
|
class StoreReportRepositoryTest extends TestCase
|
|
{
|
|
private string $databasePath;
|
|
private StoreReportRepository $repository;
|
|
|
|
protected function setUp(): void
|
|
{
|
|
parent::setUp();
|
|
$this->databasePath = tempnam(sys_get_temp_dir(), 'store-report-');
|
|
config(['database.connections.bills_sqlite' => [
|
|
'driver' => 'sqlite',
|
|
'database' => $this->databasePath,
|
|
'prefix' => '',
|
|
'foreign_key_constraints' => false,
|
|
]]);
|
|
DB::purge('bills_sqlite');
|
|
$schema = Schema::connection('bills_sqlite');
|
|
$schema->create('store_lifecycles', function (Blueprint $table): void {
|
|
$table->increments('id');
|
|
$table->string('erp_store_name');
|
|
$table->string('company_name')->nullable();
|
|
$table->string('effective_at')->nullable();
|
|
$table->string('expires_at')->nullable();
|
|
});
|
|
$schema->create('bills', function (Blueprint $table): void {
|
|
$table->increments('id');
|
|
$table->string('store_name');
|
|
$table->string('occurred_at')->nullable();
|
|
$table->decimal('income', 18, 2)->default(0);
|
|
});
|
|
$this->repository = new StoreReportRepository(app('db'));
|
|
}
|
|
|
|
protected function tearDown(): void
|
|
{
|
|
DB::purge('bills_sqlite');
|
|
if (is_file($this->databasePath)) {
|
|
unlink($this->databasePath);
|
|
}
|
|
parent::tearDown();
|
|
}
|
|
|
|
public function test_lifecycle_boundaries_split_monthly_and_period_income_without_double_counting(): void
|
|
{
|
|
$db = DB::connection('bills_sqlite');
|
|
$db->table('store_lifecycles')->insert([
|
|
['erp_store_name' => '店铺A', 'company_name' => '主体甲', 'effective_at' => '2026-05-01', 'expires_at' => '2026-07-01'],
|
|
['erp_store_name' => '店铺A', 'company_name' => '主体乙', 'effective_at' => '2026-07-01', 'expires_at' => null],
|
|
]);
|
|
$db->table('bills')->insert([
|
|
['store_name' => '店铺A', 'occurred_at' => '2026-04-30 23:59:59', 'income' => 9],
|
|
['store_name' => '店铺A', 'occurred_at' => '2026-05-01 00:00:00', 'income' => 100],
|
|
['store_name' => '店铺A', 'occurred_at' => '2026-06-30 23:59:59', 'income' => 60],
|
|
['store_name' => '店铺A', 'occurred_at' => '2026-07-01 00:00:00', 'income' => 70],
|
|
['store_name' => '店铺A', 'occurred_at' => '2026-08-01 00:00:00', 'income' => 80],
|
|
['store_name' => '店铺A', 'occurred_at' => '2027-01-01 00:00:00', 'income' => 5],
|
|
]);
|
|
|
|
$rows = $this->repository->rows([
|
|
['erp_store_name' => '店铺A', 'company_name' => '旧主体', 'store_status' => '3'],
|
|
]);
|
|
|
|
$this->assertCount(2, $rows);
|
|
$this->assertSame(['主体甲', '主体乙'], array_column($rows, 'entity'));
|
|
$this->assertSame(['2026-05-01', '2026-07-01'], array_column($rows, 'effective_at'));
|
|
$this->assertSame(['2026-07-01', '2999-01-01'], array_column($rows, 'invalid_at'));
|
|
$this->assertSame([160.0, 155.0], array_column($rows, 'period_sales'));
|
|
$this->assertSame([100.0, 0.0], array_column($rows, 'sales_05'));
|
|
$this->assertSame([0.0, 70.0], array_column($rows, 'sales_07'));
|
|
$this->assertSame(['关店中', '关店中'], array_column($rows, 'status'));
|
|
}
|
|
|
|
public function test_missing_lifecycle_uses_upstream_company_and_default_period(): void
|
|
{
|
|
$db = DB::connection('bills_sqlite');
|
|
$db->table('bills')->insert([
|
|
['store_name' => '无生命周期店铺', 'occurred_at' => '2026-05-03 12:00:00', 'income' => 25.5],
|
|
]);
|
|
|
|
$rows = $this->repository->rows([
|
|
['erp_store_name' => '无生命周期店铺', 'company_name' => '公司表主体', 'store_status' => '0'],
|
|
]);
|
|
|
|
$this->assertCount(1, $rows);
|
|
$this->assertSame('公司表主体', $rows[0]['entity']);
|
|
$this->assertSame('2026-05-01', $rows[0]['effective_at']);
|
|
$this->assertSame('2999-01-01', $rows[0]['invalid_at']);
|
|
$this->assertSame(25.5, $rows[0]['period_sales']);
|
|
$this->assertSame(25.5, $rows[0]['sales_05']);
|
|
$this->assertSame('开店中', $rows[0]['status']);
|
|
}
|
|
|
|
public function test_shop_state_mapping_keeps_opening_closing_and_closed_labels(): void
|
|
{
|
|
$rows = $this->repository->rows([
|
|
['erp_store_name' => '开店中店铺', 'store_status' => '0'],
|
|
['erp_store_name' => '关店中店铺', 'store_status' => '3'],
|
|
['erp_store_name' => '已关店店铺', 'store_status' => '6'],
|
|
]);
|
|
|
|
$this->assertSame(['开店中', '关店中', '关店'], array_column($rows, 'status'));
|
|
}
|
|
|
|
public function test_upstream_business_information_exposes_expanded_rows_for_store_report(): void
|
|
{
|
|
DB::connection('bills_sqlite')->table('store_lifecycles')->insert([
|
|
['erp_store_name' => '店铺A', 'company_name' => '主体甲', 'effective_at' => '2026-05-01', 'expires_at' => '2026-07-01'],
|
|
['erp_store_name' => '店铺A', 'company_name' => '主体乙', 'effective_at' => '2026-07-01', 'expires_at' => null],
|
|
]);
|
|
DB::connection('bills_sqlite')->table('bills')->insert([
|
|
['store_name' => '店铺A', 'occurred_at' => '2026-06-30 23:59:59', 'income' => 60],
|
|
['store_name' => '店铺A', 'occurred_at' => '2026-07-01 00:00:00', 'income' => 70],
|
|
]);
|
|
|
|
$mirror = Mockery::mock(BusinessInformationMirrorRepository::class);
|
|
$mirror->shouldReceive('ready')->with('store-information.read')->andReturnTrue();
|
|
$mirror->shouldReceive('allStores')->once()->andReturn([[
|
|
'erp_store_name' => '店铺A',
|
|
'company_name' => '公司表主体',
|
|
'store_status' => '3',
|
|
]]);
|
|
|
|
$service = new UpstreamBusinessInformation(
|
|
Mockery::mock(UpstreamQueryCacheFactory::class),
|
|
$mirror,
|
|
Mockery::mock(InstallationDetailMirrorRepository::class),
|
|
$this->repository,
|
|
);
|
|
$paginator = $service->paginate('store-management', 'store-report', 50);
|
|
|
|
$this->assertSame(2, $paginator->total());
|
|
$this->assertSame(['主体甲', '主体乙'], array_map(static fn (object $row): string => $row->entity, $paginator->items()));
|
|
$this->assertSame([60.0, 70.0], array_map(static fn (object $row): float => $row->period_sales, $paginator->items()));
|
|
$this->assertSame(['关店中', '关店中'], array_map(static fn (object $row): string => $row->status, $paginator->items()));
|
|
}
|
|
}
|