115 lines
5.4 KiB
PHP
115 lines
5.4 KiB
PHP
<?php
|
|
|
|
namespace Tests\Unit\Auth;
|
|
|
|
use App\Services\Auth\SupplierPortalAccess;
|
|
use Mockery;
|
|
use Modules\EcommerceFinance\Repositories\SupplierManagementMirrorRepository;
|
|
use Modules\EcommerceFinance\Services\UpstreamReadOnlyQuery;
|
|
use Modules\EcommerceFinance\Services\UpstreamReadOnlyQueryFactory;
|
|
use Tests\TestCase;
|
|
|
|
class SupplierPortalAccessTest extends TestCase
|
|
{
|
|
public function test_exact_supplier_group_resolves_to_one_supplier(): void
|
|
{
|
|
$query = Mockery::mock(UpstreamReadOnlyQuery::class);
|
|
$query->shouldReceive('select')->twice()->andReturnUsing(function (string $sql, array $bindings): array {
|
|
UpstreamReadOnlyQuery::assertReadOnlySql($sql);
|
|
if (str_contains($sql, 'hr_employee')) {
|
|
$this->assertSame(['ding-supplier'], $bindings);
|
|
|
|
return [[
|
|
'userid' => 'ding-supplier',
|
|
'unionid' => 'union-supplier',
|
|
'active' => 1,
|
|
'dept_id_list' => '55248182',
|
|
]];
|
|
}
|
|
$this->assertContains('55248182', $bindings);
|
|
|
|
return [
|
|
['Id' => 55248182, 'parent_id' => 900, 'name' => '晨丰', 'depth' => 0],
|
|
['Id' => 900, 'parent_id' => 1, 'name' => '供应商', 'depth' => 1],
|
|
];
|
|
});
|
|
$factory = Mockery::mock(UpstreamReadOnlyQueryFactory::class);
|
|
$factory->shouldReceive('forSource')->once()->with('operations_replica')->andReturn($query);
|
|
$suppliers = Mockery::mock(SupplierManagementMirrorRepository::class);
|
|
$suppliers->shouldReceive('suppliersByNames')->once()
|
|
->with(['晨丰', '供应商'])
|
|
->andReturn([(object) ['Id' => 9, 'scmcode' => 'CF-001', 'scmname' => '晨丰']]);
|
|
|
|
$resolved = (new SupplierPortalAccess($factory, $suppliers))->resolve('ding-supplier', 'union-supplier');
|
|
|
|
$this->assertSame('晨丰', $resolved['supplier_name']);
|
|
$this->assertSame('CF-001', $resolved['supplier_code']);
|
|
$this->assertSame(55248182, $resolved['dingtalk_group_id']);
|
|
}
|
|
|
|
public function test_inactive_or_union_mismatched_employee_is_denied(): void
|
|
{
|
|
foreach ([
|
|
[['userid' => 'ding-supplier', 'unionid' => 'union-supplier', 'active' => 0, 'dept_id_list' => '1']],
|
|
[['userid' => 'ding-supplier', 'unionid' => 'different-union', 'active' => 1, 'dept_id_list' => '1']],
|
|
] as $employees) {
|
|
$query = Mockery::mock(UpstreamReadOnlyQuery::class);
|
|
$query->shouldReceive('select')->once()->with(Mockery::on(function (string $sql): bool {
|
|
UpstreamReadOnlyQuery::assertReadOnlySql($sql);
|
|
|
|
return str_contains($sql, 'hr_employee');
|
|
}), ['ding-supplier'])->andReturn($employees);
|
|
$factory = Mockery::mock(UpstreamReadOnlyQueryFactory::class);
|
|
$factory->shouldReceive('forSource')->andReturn($query);
|
|
$suppliers = Mockery::mock(SupplierManagementMirrorRepository::class);
|
|
$suppliers->shouldNotReceive('suppliersByNames');
|
|
|
|
$this->assertNull((new SupplierPortalAccess($factory, $suppliers))->resolve('ding-supplier', 'union-supplier'));
|
|
}
|
|
}
|
|
|
|
public function test_multiple_supplier_ancestors_are_ambiguous_and_denied(): void
|
|
{
|
|
$query = Mockery::mock(UpstreamReadOnlyQuery::class);
|
|
$query->shouldReceive('select')->twice()->andReturnUsing(function (string $sql): array {
|
|
UpstreamReadOnlyQuery::assertReadOnlySql($sql);
|
|
if (str_contains($sql, 'hr_employee')) {
|
|
return [['userid' => 'ding-supplier', 'unionid' => 'union-supplier', 'active' => 1, 'dept_id_list' => '10,20']];
|
|
}
|
|
|
|
return [
|
|
['Id' => 10, 'parent_id' => 1, 'name' => '晨丰', 'depth' => 0],
|
|
['Id' => 20, 'parent_id' => 1, 'name' => '鸣飞家具', 'depth' => 0],
|
|
];
|
|
});
|
|
$factory = Mockery::mock(UpstreamReadOnlyQueryFactory::class);
|
|
$factory->shouldReceive('forSource')->once()->andReturn($query);
|
|
$suppliers = Mockery::mock(SupplierManagementMirrorRepository::class);
|
|
$suppliers->shouldReceive('suppliersByNames')->once()->andReturn([
|
|
(object) ['Id' => 1, 'scmcode' => 'CF', 'scmname' => '晨丰'],
|
|
(object) ['Id' => 2, 'scmcode' => 'MF', 'scmname' => '鸣飞家具'],
|
|
]);
|
|
|
|
$this->assertNull((new SupplierPortalAccess($factory, $suppliers))->resolve('ding-supplier', 'union-supplier'));
|
|
}
|
|
|
|
public function test_organization_cycle_is_rejected(): void
|
|
{
|
|
$query = Mockery::mock(UpstreamReadOnlyQuery::class);
|
|
$query->shouldReceive('select')->twice()->andReturnUsing(function (string $sql): array {
|
|
UpstreamReadOnlyQuery::assertReadOnlySql($sql);
|
|
if (str_contains($sql, 'hr_employee')) {
|
|
return [['userid' => 'ding-supplier', 'unionid' => 'union-supplier', 'active' => 1, 'dept_id_list' => '30']];
|
|
}
|
|
|
|
return [['Id' => 30, 'parent_id' => 30, 'name' => '晨丰', 'depth' => 20]];
|
|
});
|
|
$factory = Mockery::mock(UpstreamReadOnlyQueryFactory::class);
|
|
$factory->shouldReceive('forSource')->once()->andReturn($query);
|
|
$suppliers = Mockery::mock(SupplierManagementMirrorRepository::class);
|
|
$suppliers->shouldNotReceive('suppliersByNames');
|
|
|
|
$this->assertNull((new SupplierPortalAccess($factory, $suppliers))->resolve('ding-supplier', 'union-supplier'));
|
|
}
|
|
}
|