72 lines
4.5 KiB
PHP
72 lines
4.5 KiB
PHP
<?php
|
|
|
|
namespace Tests\Unit\Auth;
|
|
|
|
use App\Services\Auth\FinanceRoster;
|
|
use Mockery;
|
|
use Modules\EcommerceFinance\Services\UpstreamReadOnlyQuery;
|
|
use Modules\EcommerceFinance\Services\UpstreamReadOnlyQueryFactory;
|
|
use PHPUnit\Framework\Attributes\DataProvider;
|
|
use Tests\TestCase;
|
|
|
|
class FinanceRosterTest extends TestCase
|
|
{
|
|
#[DataProvider('rosterCases')]
|
|
public function test_roster_authorization(array $overrides, bool $expected): void
|
|
{
|
|
config(['dingtalk.finance_department_ids' => ['22848291', '994080505']]);
|
|
config(['dingtalk.super_admin_user_ids' => $overrides['designated_ids'] ?? []]);
|
|
$data = array_replace([
|
|
'flowers' => [['Id' => 123, 'name' => '测试员工', 'flowerName' => '测试花名', 'deptId' => '55248182', 'status' => '', 'empStatus' => '正式']],
|
|
'employees' => [['active' => 1, 'dept_id_list' => '[55248182]']],
|
|
'registrations' => [['employment_status' => '3', 'department_ids' => '55248182', 'main_department_id' => '55248182']],
|
|
'resignation' => null,
|
|
'ancestors' => [['Id' => '55248182', 'parent_id' => '22848291', 'depth' => 0], ['Id' => '22848291', 'parent_id' => '1', 'depth' => 1]],
|
|
], $overrides);
|
|
$query = Mockery::mock(UpstreamReadOnlyQuery::class);
|
|
$query->shouldReceive('select')->andReturnUsing(function ($sql, $bindings) use ($data) {
|
|
UpstreamReadOnlyQuery::assertReadOnlySql($sql);
|
|
if (str_contains($sql, 'WITH lineage')) {
|
|
$this->assertContains('55248182', $bindings);
|
|
return $data['ancestors'];
|
|
}
|
|
$this->assertSame(['ding-fixture-id'], $bindings);
|
|
return match (true) {
|
|
str_contains($sql, 'hr_flowerName_book') => $data['flowers'],
|
|
str_contains($sql, 'hr_employee_register') => $data['registrations'],
|
|
str_contains($sql, 'hr_employee') => $data['employees'],
|
|
};
|
|
});
|
|
$query->shouldReceive('first')->with(Mockery::on(function ($sql) {
|
|
UpstreamReadOnlyQuery::assertReadOnlySql($sql);
|
|
return str_contains($sql, 'hr_employee_dimission');
|
|
}), ['ding-fixture-id'])->andReturn($data['resignation']);
|
|
$factory = Mockery::mock(UpstreamReadOnlyQueryFactory::class);
|
|
$factory->shouldReceive('forSource')->with('operations_replica')->andReturn($query);
|
|
$result = (new FinanceRoster($factory))->findEligible('ding-fixture-id');
|
|
$this->assertSame($expected, $result !== null);
|
|
}
|
|
|
|
public static function rosterCases(): array
|
|
{
|
|
return [
|
|
'designated active administrator outside finance' => [['designated_ids' => ['ding-fixture-id'], 'ancestors' => [['Id' => '55248182', 'parent_id' => '1', 'depth' => 0]]], true],
|
|
'designation does not cover another identity' => [['designated_ids' => ['another-id'], 'ancestors' => [['Id' => '55248182', 'parent_id' => '1', 'depth' => 0]]], false],
|
|
'designated administrator still requires active employment' => [['designated_ids' => ['ding-fixture-id'], 'employees' => [['active' => 0]]], false],
|
|
'designated administrator cannot bypass resignation' => [['designated_ids' => ['ding-fixture-id'], 'resignation' => ['userid' => 'ding-fixture-id']], false],
|
|
'designated administrator needs roster identity' => [['designated_ids' => ['ding-fixture-id'], 'flowers' => []], false],
|
|
'finance descendant' => [[], true],
|
|
'second finance root' => [['ancestors' => [['Id' => '994080505', 'parent_id' => '994121400', 'depth' => 1]]], true],
|
|
'concurrent finance membership' => [['employees' => [['active' => 1, 'dept_id_list' => '[100,55248182]']]], true],
|
|
'not in roster' => [['flowers' => []], false],
|
|
'same department name outside allowed roots' => [['ancestors' => [['Id' => '123456', 'parent_id' => '1', 'depth' => 0]]], false],
|
|
'resignation beats active status' => [['resignation' => ['userid' => 'ding-fixture-id']], false],
|
|
'numeric resigned status' => [['registrations' => [['employment_status' => '5']]], false],
|
|
'disabled employee' => [['employees' => [['active' => 0]]], false],
|
|
'flower-only member' => [['employees' => [], 'registrations' => []], true],
|
|
'ambiguous roster identity' => [['flowers' => [['Id' => 1], ['Id' => 2]]], false],
|
|
'broken department cycle' => [['ancestors' => [['Id' => '22848291', 'parent_id' => '22848291', 'depth' => 20]]], false],
|
|
];
|
|
}
|
|
}
|