173 lines
7.0 KiB
PHP
173 lines
7.0 KiB
PHP
<?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('内部流转数据尚未导入');
|
||
}
|
||
}
|