CaiWuXiTong/tests/Unit/EcommerceFinance/ManagementExpensesPageDataTest.php
yueyang 54e43be89f feat: 管理费用改为整月筛选 (#807)
审批月份改为整月选择,默认上个月。
2026-11-02 09:09:03 +08:00

247 lines
10 KiB
PHP

<?php
namespace Tests\Unit\EcommerceFinance;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Http\Request;
use Illuminate\Support\Carbon;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;
use Modules\EcommerceFinance\View\ManagementExpensesPageData;
use Tests\TestCase;
class ManagementExpensesPageDataTest extends TestCase
{
private ManagementExpensesPageData $pageData;
protected function setUp(): void
{
parent::setUp();
Carbon::setTestNow('2026-11-02 12:00:00');
config([
'database.connections.business_mirror' => [
'driver' => 'sqlite',
'database' => ':memory:',
'prefix' => '',
],
'upstream_mirrors.connection' => 'business_mirror',
]);
DB::purge('business_mirror');
$this->createTables();
$this->seedRows();
$this->pageData = app(ManagementExpensesPageData::class);
}
protected function tearDown(): void
{
Carbon::setTestNow();
parent::tearDown();
}
public function test_page_groups_only_approved_paid_oa_rows_by_second_level_and_fee_ratio(): void
{
$data = $this->pageData->page(Request::create(
'/1/workspace/financial-operations/management-expenses',
'GET',
));
$this->assertSame(3, $data['rows']->total());
$this->assertSame(350.0, $data['summary']['amount_total']);
$this->assertSame(200.0, $data['summary']['in_fee_ratio_amount']);
$this->assertSame(100.0, $data['summary']['non_fee_ratio_amount']);
$this->assertSame(50.0, $data['summary']['unmapped_amount']);
$this->assertSame(3, $data['summary']['row_count']);
$this->assertSame('2026-10', $data['filters']['approved_month']);
$this->assertSame('2026年11月', $data['monthOptions']['2026-11']);
$this->assertSame('2026年1月', $data['monthOptions']['2026-01']);
$groups = collect($data['secondLevelSummary'])->keyBy(
static fn (array $row): string => $row['expense_category'] . '|' . $row['second_level'],
);
$this->assertSame(100.0, $groups['管理费用|办公费']['amount_total']);
$this->assertSame(1, $groups['管理费用|办公费']['approval_count']);
$this->assertSame(200.0, $groups['销售费用|技术服务费']['in_fee_ratio_amount']);
$this->assertSame(0.0, $groups['销售费用|技术服务费']['non_fee_ratio_amount']);
$this->assertSame(200.0, $groups['销售费用|技术服务费']['amount_total']);
$this->assertSame(50.0, $groups['未映射科目|未映射科目']['unmapped_amount']);
$this->assertCount(3, $data['secondLevelSummary']);
}
public function test_explicitly_cleared_approval_month_shows_all_months(): void
{
$data = $this->pageData->page(Request::create(
'/1/workspace/financial-operations/management-expenses',
'GET',
['approved_month' => ''],
));
$this->assertSame('', $data['filters']['approved_month']);
$this->assertSame(4, $data['rows']->total());
$this->assertSame(370.0, $data['summary']['amount_total']);
}
public function test_detail_template_filters_and_paginates_approved_paid_rows(): void
{
$data = $this->pageData->details(Request::create(
'/1/workspace/financial-operations/management-expenses/details',
'GET',
[
'expense_category' => '管理费用',
'second_level' => '办公费',
'per_page' => 50,
],
));
$this->assertSame(1, $data['pagination']['total']);
$this->assertSame(100.0, $data['summary']['amount_total']);
$this->assertSame(
['审批编号', '部门', '用途', '分类', '二级', '三级', '金额', '是否进费比', '是否分摊'],
array_values(ManagementExpensesPageData::DETAIL_COLUMNS),
);
$this->assertSame(
['5602.04'],
array_column($data['rows'], 'business_id'),
);
$this->assertSame('不进费比', $data['rows'][0]['fee_ratio']);
$this->assertSame('分摊', $data['rows'][0]['allocation']);
}
public function test_unmapped_account_is_visible_instead_of_being_silently_dropped(): void
{
$data = $this->pageData->details(Request::create(
'/1/workspace/financial-operations/management-expenses/details',
'GET',
['fee_ratio' => 'unmapped'],
));
$this->assertSame(1, $data['pagination']['total']);
$this->assertSame('未映射科目', $data['rows'][0]['expense_category']);
$this->assertSame(50.0, $data['rows'][0]['amount']);
}
public function test_workbook_mapping_snapshot_is_complete_and_unique(): void
{
$mapping = json_decode(
(string) file_get_contents(base_path('resources/data/oa_process_account_mapping.json')),
true,
512,
JSON_THROW_ON_ERROR,
);
$this->assertCount(191, $mapping);
$this->assertCount(191, array_unique(array_column($mapping, 'account_code')));
$this->assertSame(33, count(array_filter($mapping, static fn (array $row): bool => $row['in_fee_ratio'])));
$this->assertSame(125, count(array_filter($mapping, static fn (array $row): bool => $row['allocation'] !== null)));
$this->assertContains('分摊', array_column($mapping, 'allocation'));
$this->assertContains('核实进店铺', array_column($mapping, 'allocation'));
$this->assertContains('进店铺', array_column($mapping, 'allocation'));
}
private function createTables(): void
{
Schema::connection('business_mirror')->create(
'oa_process_account_mapping',
function (Blueprint $table): void {
$table->string('account_code', 64)->primary();
$table->string('account_name', 255);
$table->string('expense_category', 100);
$table->string('second_level', 100);
$table->string('third_level', 100);
$table->boolean('in_fee_ratio')->default(false);
$table->string('allocation', 100)->nullable();
$table->timestamps();
},
);
Schema::connection('business_mirror')->create(
'ding_process_detail_mirror',
function (Blueprint $table): void {
$table->bigIncrements('id');
$table->string('business_id', 32);
$table->string('process_instance_id', 100)->nullable();
$table->unsignedInteger('line_no');
$table->string('account_code', 64)->nullable();
$table->string('account_name', 255)->nullable();
$table->string('originator_department', 255)->nullable();
$table->string('originator_name', 100)->nullable();
$table->string('status', 20)->nullable();
$table->string('payment_source_state', 24)->nullable();
$table->string('cashier_status', 32)->nullable();
$table->text('purpose')->nullable();
$table->decimal('amount', 18, 2)->nullable();
$table->dateTime('approval_finished_at')->nullable();
$table->timestamps();
},
);
}
private function seedRows(): void
{
$now = now();
DB::connection('business_mirror')->table('oa_process_account_mapping')->insert([
[
'account_code' => '5602.04',
'account_name' => '管理费用_办公费',
'expense_category' => '管理费用',
'second_level' => '办公费',
'third_level' => '办公费用品',
'in_fee_ratio' => false,
'allocation' => '分摊',
'created_at' => $now,
'updated_at' => $now,
],
[
'account_code' => '5601.05.03',
'account_name' => '销售费用_营销费用_软件服务费',
'expense_category' => '销售费用',
'second_level' => '技术服务费',
'third_level' => '软件服务费',
'in_fee_ratio' => true,
'allocation' => null,
'created_at' => $now,
'updated_at' => $now,
],
]);
DB::connection('business_mirror')->table('ding_process_detail_mirror')->insert([
$this->row('5602.04', 1, 100, '已完成', 'completed', 'present', '2026-10-01 10:00:00'),
$this->row('5601.05.03', 1, 200, '已完成', 'completed', 'present', '2026-10-02 10:00:00'),
$this->row('5601.05.03', 1, 300, '审批中', 'completed', 'present', '2026-10-03 10:00:00'),
$this->row('5602.04', 1, 400, '审批中', 'pending', 'present', '2026-10-04 10:00:00'),
$this->row('9999.99', 1, 50, '已完成', 'completed', 'present', '2026-10-05 10:00:00'),
$this->row('5601.05.03', 1, 70, '已完成', 'not_applicable', 'not_applicable', '2026-10-06 10:00:00'),
$this->row('5602.04', 1, 25, '已完成', null, 'present', '2026-10-07 10:00:00'),
$this->row('5602.04', 1, 20, '已完成', 'completed', 'present', '2026-09-25 10:00:00'),
]);
}
/** @return array<string,mixed> */
private function row(
string $businessId,
int $lineNo,
float $amount,
string $status,
?string $cashierStatus,
string $paymentSourceState,
string $approvalFinishedAt,
): array {
return [
'business_id' => $businessId,
'process_instance_id' => 'process-' . $businessId,
'line_no' => $lineNo,
'account_code' => $businessId,
'account_name' => '流程科目',
'originator_department' => '财务中心',
'originator_name' => '测试申请人',
'status' => $status,
'payment_source_state' => $paymentSourceState,
'cashier_status' => $cashierStatus,
'purpose' => '测试用途',
'amount' => $amount,
'approval_finished_at' => $approvalFinishedAt,
'created_at' => now(),
'updated_at' => now(),
];
}
}