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

173 lines
7.0 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
namespace Tests\Feature\Business;
use Illuminate\Support\Carbon;
use Mockery;
use Modules\EcommerceFinance\Repositories\InternalFlowReportRepository;
use Modules\EcommerceFinance\Services\InternalFlowProjection;
use Tests\Feature\FeatureTestCase;
class InternalFlowReportPageTest extends FeatureTestCase
{
protected function setUp(): void
{
parent::setUp();
Carbon::setTestNow('2026-11-09 12:00:00');
}
protected function tearDown(): void
{
Carbon::setTestNow();
parent::tearDown();
}
public function testInternalFlowReportPageRendersRowsWithQueryAndExportTools(): void
{
$projection = Mockery::mock(InternalFlowProjection::class);
$projection->shouldReceive('forMonth')->once()->andReturn([
'forecast_month' => '2026-11',
'forecast_month_label' => '11月',
'source_month' => '2026-10',
'source_month_label' => '10月',
'sales_by_company' => ['示例甲供应链有限公司' => 1200000.0],
]);
$this->app->instance(InternalFlowProjection::class, $projection);
$repository = Mockery::mock(InternalFlowReportRepository::class);
$repository->shouldReceive('ready')->once()->andReturn(true);
$repository->shouldReceive('paginate')->once()->andReturn([
'data' => [[
'id' => 1,
'sort_order' => 1,
'company_name' => '示例甲供应链有限公司',
'tag' => '1',
'projected_sales' => '1200000.000000',
'invoiced_to_buyer' => '240000.000000',
'internal_invoiced' => '300000.000000',
'required_input_cost' => '960000.000000',
'receipt_from_supplier' => '100000.000000',
'receipt_from_suofeiya' => null,
'receipt_from_gujia' => null,
'internal_transfer_1' => '0.000000',
'internal_transfer_2' => '0.000000',
'internal_transfer_3' => '0.000000',
'receipt_total' => '100000.000000',
'remaining_gap' => '860000.000000',
'invoicing_ratio' => '1',
]],
'total' => 1,
'summary' => [
'companies' => 1,
'projected_sales' => 1200000.0,
'receipt_total' => 100000.0,
'remaining_gap' => 860000.0,
'average_invoicing_ratio' => 100.0,
],
]);
$this->app->instance(InternalFlowReportRepository::class, $repository);
$this->loginAs()
->get(route('business.pages.show', [
'section' => 'store-management',
'page' => 'internal-flow-report',
]))
->assertOk()
->assertSeeText('内部流转报表')
->assertSeeText('按抬头、标签查询内部流转明细并导出')
->assertSeeText('示例甲供应链有限公司')
->assertSeeText('预计11月销量')
->assertSeeText('取自主体维度经营报表10月业绩')
->assertSeeText('买家开票按 20%、内部开票按 25%、所需进项成本按 80%')
->assertSee('data-internal-flow-supplier-input', false)
->assertSee('value="100000.00"', false)
->assertSeeText('收票-内部流转(来源)1')
->assertSeeText('剩余缺口')
->assertSeeText('开票比例')
->assertSeeText('公司数')
->assertSeeText('预计销量合计')
->assertSeeText('已收票合计')
->assertSeeText('剩余缺口合计')
->assertSeeText('平均开票比例')
->assertSee('data-directory-query-picker', false)
->assertSee('data-directory-query-export', false)
->assertSee('data-directory-query-field="company_name"', false)
->assertSee('data-directory-query-select="tag"', false)
->assertSeeText('筛选字段')
->assertSeeText('导出 Excel')
->assertSee('排序和字段操作', false)
->assertSee('sort=projected_sales', false);
}
public function testSupplierReceiptUpdateReturnsRecalculatedRowAndSummary(): void
{
$projectionPayload = [
'forecast_month' => '2026-11',
'forecast_month_label' => '11月',
'source_month' => '2026-10',
'source_month_label' => '10月',
'sales_by_company' => ['示例甲供应链有限公司' => 1200000.0],
];
$projection = Mockery::mock(InternalFlowProjection::class);
$projection->shouldReceive('forMonth')->once()->andReturn($projectionPayload);
$this->app->instance(InternalFlowProjection::class, $projection);
$repository = Mockery::mock(InternalFlowReportRepository::class);
$repository->shouldReceive('updateSupplierReceipt')
->once()
->with(7, 500000.0, (int) $this->user->id)
->andReturn('示例甲供应链有限公司');
$repository->shouldReceive('find')
->once()
->with(7, $projectionPayload)
->andReturn([
'id' => 7,
'receipt_from_supplier' => 500000.0,
'receipt_total' => 500000.0,
'remaining_gap' => 460000.0,
]);
$repository->shouldReceive('summary')
->once()
->with(['company_name' => '示例甲', 'tag' => ''], $projectionPayload)
->andReturn([
'companies' => 1,
'projected_sales' => 1200000.0,
'receipt_total' => 500000.0,
'remaining_gap' => 460000.0,
'average_invoicing_ratio' => 100.0,
]);
$this->app->instance(InternalFlowReportRepository::class, $repository);
$this->loginAs()
->patchJson(
route('business.internal-flow-report.supplier-receipt', ['record' => 7]),
[
'receipt_from_supplier' => '500000',
'company_name' => '示例甲',
'tag' => '',
],
)
->assertOk()
->assertJsonPath('ok', true)
->assertJsonPath('record.receipt_from_supplier', 500000)
->assertJsonPath('record.receipt_total', 500000)
->assertJsonPath('record.remaining_gap', 460000)
->assertJsonPath('summary.receipt_total', 500000);
}
public function testInternalFlowReportPageExplainsMissingDataset(): void
{
$repository = Mockery::mock(InternalFlowReportRepository::class);
$repository->shouldReceive('ready')->once()->andReturn(false);
$this->app->instance(InternalFlowReportRepository::class, $repository);
$this->loginAs()
->get(route('business.pages.show', [
'section' => 'store-management',
'page' => 'internal-flow-report',
]))
->assertOk()
->assertSeeText('内部流转数据尚未导入');
}
}