feat: import work hours from SaaS and exchange signed time sheet
This commit is contained in:
1 parent
7cf39850e6
commit
1a7c272414
73 files changed
+10488
-72
No files matched your search
@@ -0,0 +1,128 @@
|
||||
<?php
|
||||
|
||||
namespace App\Tests\Saas;
|
||||
|
||||
use App\Saas\Model\EmployeeDirectory;
|
||||
use App\Saas\ResponseParser;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
class EmployeeDirectoryTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* The point of the projection: the roster answers with a per-employee api key next to a
|
||||
* birthday, a personnel number and an RFID token, and the result of this is cached to the
|
||||
* filesystem. None of it may get that far.
|
||||
*/
|
||||
public function testTheProjectionKeepsNoCredentialsOrPersonalData(): void
|
||||
{
|
||||
$directory = (new ResponseParser())->parseEmployees($this->roster());
|
||||
$serialised = json_encode($directory->toCacheable(), JSON_THROW_ON_ERROR);
|
||||
|
||||
$this->assertStringNotContainsString('s3cr3t', $serialised, 'The api key must not survive.');
|
||||
$this->assertStringNotContainsString('apiKey', $serialised);
|
||||
$this->assertStringNotContainsString('1990', $serialised, 'The birthday must not survive.');
|
||||
$this->assertStringNotContainsString('RFID', $serialised);
|
||||
$this->assertStringNotContainsString('personnelNumber', $serialised);
|
||||
}
|
||||
|
||||
public function testItReadsTheFieldsWeActuallyUse(): void
|
||||
{
|
||||
$directory = (new ResponseParser())->parseEmployees($this->roster());
|
||||
$theo = $directory->find('[email protected]');
|
||||
|
||||
$this->assertNotNull($theo);
|
||||
$this->assertSame('Operations', $theo->getDepartment());
|
||||
$this->assertSame('aaaaaaaa-894a-4e63-9c8d-5777e6afdc91', $theo->getUuid());
|
||||
$this->assertFalse($theo->hasLeft());
|
||||
}
|
||||
|
||||
public function testADateOfSeparationMarksSomeoneAsGone(): void
|
||||
{
|
||||
$directory = (new ResponseParser())->parseEmployees($this->roster());
|
||||
|
||||
$this->assertTrue($directory->find('[email protected]')->hasLeft());
|
||||
}
|
||||
|
||||
/**
|
||||
* Both systems have the address typed in by hand, so the one place they have to agree on
|
||||
* it cannot be case-sensitive.
|
||||
*/
|
||||
public function testLookupIgnoresCaseAndSurroundingSpace(): void
|
||||
{
|
||||
$directory = (new ResponseParser())->parseEmployees($this->roster());
|
||||
|
||||
$this->assertTrue($directory->has('[email protected]'));
|
||||
$this->assertTrue($directory->has(' [email protected] '));
|
||||
$this->assertFalse($directory->has('[email protected]'));
|
||||
$this->assertFalse($directory->has(null));
|
||||
}
|
||||
|
||||
public function testAnEntryWithoutAnAddressIsDropped(): void
|
||||
{
|
||||
$directory = (new ResponseParser())->parseEmployees([
|
||||
['mainDepartment' => 'Operations', 'email' => ''],
|
||||
['mainDepartment' => 'Operations'],
|
||||
'not an entry',
|
||||
]);
|
||||
|
||||
$this->assertTrue($directory->isEmpty());
|
||||
}
|
||||
|
||||
public function testItSurvivesTheCacheRoundTrip(): void
|
||||
{
|
||||
$directory = (new ResponseParser())->parseEmployees($this->roster());
|
||||
$restored = EmployeeDirectory::fromCacheable($directory->toCacheable());
|
||||
|
||||
$this->assertSame($directory->count(), $restored->count());
|
||||
$this->assertSame('Operations', $restored->find('[email protected]')->getDepartment());
|
||||
$this->assertTrue($restored->find('[email protected]')->hasLeft());
|
||||
}
|
||||
|
||||
/**
|
||||
* An unreachable roster produces an empty one, and the importer reads that as "no roster"
|
||||
* rather than "nobody is registered".
|
||||
*/
|
||||
public function testAnEmptyDirectoryIsRecognisable(): void
|
||||
{
|
||||
$this->assertTrue(EmployeeDirectory::fromEmployees([])->isEmpty());
|
||||
}
|
||||
|
||||
private function roster(): array
|
||||
{
|
||||
return [
|
||||
[
|
||||
'personnelNumber' => '4711',
|
||||
'mainDepartment' => 'Standard-Abteilung',
|
||||
'email' => '[email protected]',
|
||||
'givenName' => 'Admin',
|
||||
'lastName' => 'Hausmanagement',
|
||||
'birthday' => '1990-05-01',
|
||||
'joinDate' => '2021-00-01',
|
||||
'dateOfSeparation' => null,
|
||||
'RFID' => 'abc',
|
||||
'uuid' => 'bbbbbbbb-0000-0000-0000-000000000000',
|
||||
'apiKey' => 's3cr3t-admin',
|
||||
],
|
||||
[
|
||||
'personnelNumber' => '',
|
||||
'mainDepartment' => 'Operations',
|
||||
'email' => '[email protected]',
|
||||
'givenName' => 'Theo',
|
||||
'lastName' => 'Test',
|
||||
'birthday' => null,
|
||||
'joinDate' => '2021-10-22',
|
||||
'dateOfSeparation' => null,
|
||||
'RFID' => '',
|
||||
'uuid' => 'aaaaaaaa-894a-4e63-9c8d-5777e6afdc91',
|
||||
'apiKey' => 's3cr3t-theo',
|
||||
],
|
||||
[
|
||||
'mainDepartment' => 'Operations',
|
||||
'email' => '[email protected]',
|
||||
'dateOfSeparation' => '2025-05-31',
|
||||
'uuid' => 'cccccccc-0000-0000-0000-000000000000',
|
||||
'apiKey' => 's3cr3t-ex',
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user