CaiWuXiTong/tests/Feature/Business/InternalFlowReportPageTest.php
DoDo 27d0f6d9fe feat: 内部流转开票按标签顺延分配
内部开票额度按标签 1→2→3→4 顺延,下一标签按剩余进项需求占比接收,票不足时计入缺口。
2026-11-09 14:54:21 +08:00

179 lines
7.4 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('内部开票按标签 1→2→3→4 顺延')
->assertSeeText('票不足时计入剩余缺口')
->assertSee('data-internal-flow-supplier-input', false)
->assertSee('data-internal-flow-row-id="1"', 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('paginate')
->once()
->with(1, 100, ['company_name' => '示例甲', 'tag' => ''], null, 'asc', $projectionPayload)
->andReturn([
'data' => [[
'id' => 7,
'receipt_from_supplier' => 500000.0,
'internal_transfer_1' => 0.0,
'internal_transfer_2' => 250000.0,
'internal_transfer_3' => 0.0,
'receipt_total' => 500000.0,
'remaining_gap' => 460000.0,
]],
'total' => 1,
'summary' => [
'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('rows.0.internal_transfer_2', 250000)
->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('内部流转数据尚未导入');
}
}