同一钉钉联系人可绑定多家供应商,并提供厂家选择、切换和逐厂家授权校验。 Co-authored-by: 苏木 <594326199@qq.com> Co-committed-by: 苏木 <594326199@qq.com>
168 lines
7.4 KiB
PHP
168 lines
7.4 KiB
PHP
<?php
|
|
|
|
namespace Tests\Unit\Auth;
|
|
|
|
use App\Models\Auth\SupplierPortalIdentity;
|
|
use App\Models\Auth\SupplierPortalSupplier;
|
|
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_resolve_to_all_suppliers(): 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' => '鸣飞家具'],
|
|
]);
|
|
|
|
$access = new SupplierPortalAccess($factory, $suppliers);
|
|
|
|
$this->assertSame(
|
|
['晨丰', '鸣飞家具'],
|
|
array_column($access->resolveAll('ding-supplier', 'union-supplier'), 'supplier_name'),
|
|
);
|
|
}
|
|
|
|
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'));
|
|
}
|
|
|
|
public function test_binding_multiple_suppliers_keeps_all_and_prunes_only_removed_ones(): void
|
|
{
|
|
$user = user_model_class()::query()->firstOrFail();
|
|
$companyId = (int) $user->companies()->firstOrFail()->id;
|
|
$access = new SupplierPortalAccess(
|
|
Mockery::mock(UpstreamReadOnlyQueryFactory::class),
|
|
Mockery::mock(SupplierManagementMirrorRepository::class),
|
|
);
|
|
|
|
$access->bindMany($user, $companyId, [
|
|
[
|
|
'supplier_name' => '晨丰',
|
|
'supplier_code' => 'CF-001',
|
|
'dingtalk_group_id' => 10,
|
|
'dingtalk_group_name' => '晨丰',
|
|
],
|
|
[
|
|
'supplier_name' => '鸣飞家具',
|
|
'supplier_code' => 'MF-001',
|
|
'dingtalk_group_id' => 20,
|
|
'dingtalk_group_name' => '鸣飞家具',
|
|
],
|
|
]);
|
|
|
|
$this->assertSame(2, SupplierPortalSupplier::query()->where('user_id', $user->id)->count());
|
|
$this->assertSame(1, SupplierPortalIdentity::query()->where('user_id', $user->id)->count());
|
|
|
|
$access->bindMany($user, $companyId, [[
|
|
'supplier_name' => '鸣飞家具',
|
|
'supplier_code' => 'MF-001',
|
|
'dingtalk_group_id' => 20,
|
|
'dingtalk_group_name' => '鸣飞家具',
|
|
]]);
|
|
|
|
$this->assertDatabaseMissing('supplier_portal_suppliers', [
|
|
'company_id' => $companyId,
|
|
'user_id' => $user->id,
|
|
'supplier_name' => '晨丰',
|
|
]);
|
|
$this->assertDatabaseHas('supplier_portal_suppliers', [
|
|
'company_id' => $companyId,
|
|
'user_id' => $user->id,
|
|
'supplier_name' => '鸣飞家具',
|
|
]);
|
|
}
|
|
}
|