CaiWuXiTong/tests/Unit/EcommerceFinance/InternalFlowProjectionTest.php
DoDo 0174a056ac feat: 联动内部流转预计销量并支持供应商收票
预计销量自动读取主体维度经营报表上月业绩;开票与进项成本按 20%/25%/80% 计算;供应商收票支持人工覆盖并跨导入保留。
2026-11-09 12:38:19 +08:00

73 lines
3.5 KiB
PHP

<?php
namespace Tests\Unit\EcommerceFinance;
use Carbon\CarbonImmutable;
use Mockery;
use Modules\EcommerceFinance\Repositories\BusinessInformationMirrorRepository;
use Modules\EcommerceFinance\Repositories\StoreReportRepository;
use Modules\EcommerceFinance\Services\InternalFlowProjection;
use Tests\TestCase;
class InternalFlowProjectionTest extends TestCase
{
public function testForecastUsesPreviousMonthIncomeAggregatedByEntity(): void
{
$stores = [
['erp_store_name' => '店铺A', 'company_name' => '原主体'],
['erp_store_name' => '店铺B', 'company_name' => '原主体'],
];
$reportStores = array_map(
static fn (array $store): array => $store + ['system_company_name' => $store['company_name']],
$stores,
);
$businessInformation = Mockery::mock(BusinessInformationMirrorRepository::class);
$businessInformation->shouldReceive('receivingAccountStores')->once()->andReturn($stores);
$storeReports = Mockery::mock(StoreReportRepository::class);
$storeReports->shouldReceive('rows')
->once()
->with($reportStores, 2026, [])
->andReturn([
['entity' => '示例甲有限公司', 'income_10' => 1000000],
['entity' => '示例甲有限公司', 'income_10' => 250000.5],
['entity' => '示例乙有限公司', 'income_10' => 0],
['entity' => '示例丙有限公司', 'income_10' => null],
['entity' => '', 'income_10' => 999999],
]);
$projection = new InternalFlowProjection($businessInformation, $storeReports);
$result = $projection->forMonth(CarbonImmutable::create(2026, 11, 9, 10, 0, 0, 'Asia/Shanghai'));
$this->assertSame('2026-11', $result['forecast_month']);
$this->assertSame('11月', $result['forecast_month_label']);
$this->assertSame('2026-10', $result['source_month']);
$this->assertSame('10月', $result['source_month_label']);
$this->assertEqualsWithDelta(1250000.5, $result['sales_by_company']['示例甲有限公司'], 0.000001);
$this->assertSame(0.0, $result['sales_by_company']['示例乙有限公司']);
$this->assertNull($result['sales_by_company']['示例丙有限公司']);
$this->assertArrayNotHasKey('', $result['sales_by_company']);
}
public function testJanuaryForecastReadsDecemberOfPreviousYear(): void
{
$stores = [['erp_store_name' => '店铺A', 'company_name' => '示例甲有限公司']];
$reportStores = [
$stores[0] + ['system_company_name' => $stores[0]['company_name']],
];
$businessInformation = Mockery::mock(BusinessInformationMirrorRepository::class);
$businessInformation->shouldReceive('receivingAccountStores')->once()->andReturn($stores);
$storeReports = Mockery::mock(StoreReportRepository::class);
$storeReports->shouldReceive('rows')
->once()
->with($reportStores, 2025, [])
->andReturn([['entity' => '示例甲有限公司', 'income_12' => 880000]]);
$projection = new InternalFlowProjection($businessInformation, $storeReports);
$result = $projection->forMonth(CarbonImmutable::create(2026, 1, 5, 12, 0, 0, 'Asia/Shanghai'));
$this->assertSame('2026-01', $result['forecast_month']);
$this->assertSame('2025-12', $result['source_month']);
$this->assertEqualsWithDelta(880000.0, $result['sales_by_company']['示例甲有限公司'], 0.000001);
}
}