diff --git a/README.md b/README.md index a68b056b..2dcfeaa4 100755 --- a/README.md +++ b/README.md @@ -30,6 +30,9 @@ Please feel free to reach out * PHP ^8.1 * CURL PHP extension (must support TLSv1.2) +> **Breaking change:** this SDK release supports PHP 8.1 and above only. +> Support for PHP 7.4 and PHP 8.0 has been removed. +> If you are still running on PHP 7.4/8.0, please remain on an earlier SDK version until you can upgrade your runtime. ### Recommended (optional) - [Protobuf C extension](https://github.com/protocolbuffers/protobuf/tree/master/php) (PHP package will be used by default) @@ -42,13 +45,13 @@ Add the Yoti SDK dependency: ```json "require": { - "yoti/yoti-php-sdk" : "^4.5.0" + "yoti/yoti-php-sdk" : "^4.5.1" } ``` Or run this Composer command ```console -$ composer require yoti/yoti-php-sdk "^4.5.0" +$ composer require yoti/yoti-php-sdk "^4.5.1" ``` ## Setup diff --git a/composer.json b/composer.json index 91b4d313..d913b799 100755 --- a/composer.json +++ b/composer.json @@ -1,7 +1,7 @@ { "name": "yoti/yoti-php-sdk", "description": "Yoti SDK for quickly integrating your PHP backend with Yoti", - "version": "4.5.0", + "version": "4.5.1", "keywords": [ "yoti", "sdk" diff --git a/examples/doc-scan/app/Http/Controllers/HomeController.php b/examples/doc-scan/app/Http/Controllers/HomeController.php index 77d84441..53aec60f 100644 --- a/examples/doc-scan/app/Http/Controllers/HomeController.php +++ b/examples/doc-scan/app/Http/Controllers/HomeController.php @@ -152,6 +152,19 @@ public function show(Request $request, DocScanClient $client) ->withPrivacyPolicyUrl(config('app.url') . '/privacy-policy') ->withBiometricConsentFlow('EARLY') //->withBrandId('brand_id') + // Suppress specific screens to shorten the flow. + // Available screen identifiers: + // 'IDENTITY_DOCUMENT_EDUCATION' + // 'IDENTITY_DOCUMENT_REQUIREMENTS' + // 'SUPPLEMENTARY_DOCUMENT_REQUIREMENTS' + // 'ZOOM_LIVENESS_EDUCATION' + // 'STATIC_LIVENESS_EDUCATION' + // 'FACE_CAPTURE_EDUCATION' + // 'FLOW_COMPLETION' + // ->withSuppressedScreens(['IDENTITY_DOCUMENT_EDUCATION', 'IDENTITY_DOCUMENT_REQUIREMENTS']) + // Or add screens individually: + // ->withSuppressedScreen('IDENTITY_DOCUMENT_EDUCATION') + // ->withSuppressedScreen('IDENTITY_DOCUMENT_REQUIREMENTS') ->build() ) ->withRequiredDocument( diff --git a/examples/doc-scan/resources/views/partial/check.blade.php b/examples/doc-scan/resources/views/partial/check.blade.php index 651a6b22..062ddaeb 100644 --- a/examples/doc-scan/resources/views/partial/check.blade.php +++ b/examples/doc-scan/resources/views/partial/check.blade.php @@ -67,6 +67,12 @@ Result {{ $breakdown->getResult() }} + @if ($breakdown->getProcess()) + + Process + {{ $breakdown->getProcess() }} + + @endif @if (count($breakdown->getDetails()) > 0) Details diff --git a/examples/doc-scan/resources/views/success.blade.php b/examples/doc-scan/resources/views/success.blade.php index 63b0b486..612311ca 100644 --- a/examples/doc-scan/resources/views/success.blade.php +++ b/examples/doc-scan/resources/views/success.blade.php @@ -562,6 +562,23 @@ class="badge badge-primary">{{ $document->getIssuingCountry() }} @endif + @if (count($page->getExtractionImageIds()) > 0) +
+
+
+
Extraction Image IDs
+ +
+
+
+ @endif + @endforeach @@ -743,6 +760,23 @@ class="badge badge-primary">{{ $document->getIssuingCountry() }} @endif + @if (count($page->getExtractionImageIds()) > 0) +
+
+
+
Extraction Image IDs
+ +
+
+
+ @endif + @endforeach diff --git a/src/Constants.php b/src/Constants.php index 921b1fbe..51053dfe 100644 --- a/src/Constants.php +++ b/src/Constants.php @@ -37,7 +37,7 @@ class Constants public const SDK_IDENTIFIER = 'PHP'; /** Default SDK version */ - public const SDK_VERSION = '4.5.0'; + public const SDK_VERSION = '4.5.1'; /** Base url for connect page (user will be redirected to this page eg. baseurl/app-id) */ public const CONNECT_BASE_URL = 'https://www.yoti.com/connect'; diff --git a/src/DocScan/Session/Create/ApplicantProfile.php b/src/DocScan/Session/Create/ApplicantProfile.php new file mode 100644 index 00000000..0eb26dc0 --- /dev/null +++ b/src/DocScan/Session/Create/ApplicantProfile.php @@ -0,0 +1,95 @@ +fullName = $fullName; + $this->dateOfBirth = $dateOfBirth; + $this->namePrefix = $namePrefix; + $this->structuredPostalAddress = $structuredPostalAddress; + } + + /** + * @return stdClass + */ + public function jsonSerialize(): stdClass + { + return (object) Json::withoutNullValues([ + 'full_name' => $this->fullName, + 'date_of_birth' => $this->dateOfBirth, + 'name_prefix' => $this->namePrefix, + 'structured_postal_address' => $this->structuredPostalAddress, + ]); + } + + /** + * @return string|null + */ + public function getFullName(): ?string + { + return $this->fullName; + } + + /** + * @return string|null + */ + public function getDateOfBirth(): ?string + { + return $this->dateOfBirth; + } + + /** + * @return string|null + */ + public function getNamePrefix(): ?string + { + return $this->namePrefix; + } + + /** + * @return StructuredPostalAddress|null + */ + public function getStructuredPostalAddress(): ?StructuredPostalAddress + { + return $this->structuredPostalAddress; + } +} diff --git a/src/DocScan/Session/Create/ApplicantProfileBuilder.php b/src/DocScan/Session/Create/ApplicantProfileBuilder.php new file mode 100644 index 00000000..e0c85d3d --- /dev/null +++ b/src/DocScan/Session/Create/ApplicantProfileBuilder.php @@ -0,0 +1,81 @@ +fullName = $fullName; + return $this; + } + + /** + * @param string $dateOfBirth + * @return $this + */ + public function withDateOfBirth(string $dateOfBirth): self + { + $this->dateOfBirth = $dateOfBirth; + return $this; + } + + /** + * @param string $namePrefix + * @return $this + */ + public function withNamePrefix(string $namePrefix): self + { + $this->namePrefix = $namePrefix; + return $this; + } + + /** + * @param StructuredPostalAddress $structuredPostalAddress + * @return $this + */ + public function withStructuredPostalAddress(StructuredPostalAddress $structuredPostalAddress): self + { + $this->structuredPostalAddress = $structuredPostalAddress; + return $this; + } + + /** + * @return ApplicantProfile + */ + public function build(): ApplicantProfile + { + return new ApplicantProfile( + $this->fullName, + $this->dateOfBirth, + $this->namePrefix, + $this->structuredPostalAddress + ); + } +} diff --git a/src/DocScan/Session/Create/ResourceCreationContainer.php b/src/DocScan/Session/Create/ResourceCreationContainer.php new file mode 100644 index 00000000..ebbbd776 --- /dev/null +++ b/src/DocScan/Session/Create/ResourceCreationContainer.php @@ -0,0 +1,43 @@ +applicantProfile = $applicantProfile; + } + + /** + * @return stdClass + */ + public function jsonSerialize(): stdClass + { + return (object) Json::withoutNullValues([ + 'applicant_profile' => $this->applicantProfile, + ]); + } + + /** + * @return ApplicantProfile|null + */ + public function getApplicantProfile(): ?ApplicantProfile + { + return $this->applicantProfile; + } +} diff --git a/src/DocScan/Session/Create/ResourceCreationContainerBuilder.php b/src/DocScan/Session/Create/ResourceCreationContainerBuilder.php new file mode 100644 index 00000000..9ea9e394 --- /dev/null +++ b/src/DocScan/Session/Create/ResourceCreationContainerBuilder.php @@ -0,0 +1,33 @@ +applicantProfile = $applicantProfile; + return $this; + } + + /** + * @return ResourceCreationContainer + */ + public function build(): ResourceCreationContainer + { + return new ResourceCreationContainer( + $this->applicantProfile + ); + } +} diff --git a/src/DocScan/Session/Create/SessionSpecification.php b/src/DocScan/Session/Create/SessionSpecification.php index e080e5d0..060245d7 100644 --- a/src/DocScan/Session/Create/SessionSpecification.php +++ b/src/DocScan/Session/Create/SessionSpecification.php @@ -90,6 +90,11 @@ class SessionSpecification implements JsonSerializable */ private $importToken; + /** + * @var ResourceCreationContainer|null + */ + private $resources; + /** * @param int|null $clientSessionTokenTtl * @param string|null $sessionDeadline @@ -107,6 +112,7 @@ class SessionSpecification implements JsonSerializable * @param object|null $advancedIdentityProfileRequirements * @param bool|null $createIdentityProfilePreview * @param ImportToken|null $importToken + * @param ResourceCreationContainer|null $resources */ public function __construct( ?int $clientSessionTokenTtl, @@ -124,7 +130,8 @@ public function __construct( ?object $identityProfileRequirements = null, ?object $advancedIdentityProfileRequirements = null, ?bool $createIdentityProfilePreview = null, - ?ImportToken $importToken = null + ?ImportToken $importToken = null, + ?ResourceCreationContainer $resources = null ) { $this->clientSessionTokenTtl = $clientSessionTokenTtl; $this->sessionDeadline = $sessionDeadline; @@ -142,6 +149,7 @@ public function __construct( $this->advancedIdentityProfileRequirements = $advancedIdentityProfileRequirements; $this->createIdentityProfilePreview = $createIdentityProfilePreview; $this->importToken = $importToken; + $this->resources = $resources; } /** @@ -166,6 +174,7 @@ public function jsonSerialize(): stdClass 'advanced_identity_profile_requirements' => $this->getAdvancedIdentityProfileRequirements(), 'create_identity_profile_preview' => $this->getCreateIdentityProfilePreview(), 'import_token' => $this->getImportToken(), + 'resources' => $this->getResources(), ]); } @@ -295,4 +304,12 @@ public function getImportToken(): ?ImportToken { return $this->importToken; } + + /** + * @return ResourceCreationContainer|null + */ + public function getResources(): ?ResourceCreationContainer + { + return $this->resources; + } } diff --git a/src/DocScan/Session/Create/SessionSpecificationBuilder.php b/src/DocScan/Session/Create/SessionSpecificationBuilder.php index 5afc9c0c..2348a16e 100644 --- a/src/DocScan/Session/Create/SessionSpecificationBuilder.php +++ b/src/DocScan/Session/Create/SessionSpecificationBuilder.php @@ -88,6 +88,11 @@ class SessionSpecificationBuilder */ private $importToken; + /** + * @var ResourceCreationContainer|null + */ + private $resources; + /** * @var bool */ @@ -292,6 +297,19 @@ public function withImportToken($importToken): self return $this; } + /** + * Sets the resources for the session + * + * @param ResourceCreationContainer $resources + * + * @return $this + */ + public function withResources(ResourceCreationContainer $resources): self + { + $this->resources = $resources; + return $this; + } + /** * @return SessionSpecification */ @@ -314,6 +332,7 @@ public function build(): SessionSpecification $this->advancedIdentityProfileRequirements, $this->createIdentityProfilePreview, $this->importToken, + $this->resources, ); } } diff --git a/src/DocScan/Session/Create/StructuredPostalAddress.php b/src/DocScan/Session/Create/StructuredPostalAddress.php new file mode 100644 index 00000000..bb915e4f --- /dev/null +++ b/src/DocScan/Session/Create/StructuredPostalAddress.php @@ -0,0 +1,163 @@ +addressFormat = $addressFormat; + $this->buildingNumber = $buildingNumber; + $this->addressLine1 = $addressLine1; + $this->townCity = $townCity; + $this->postalCode = $postalCode; + $this->countryIso = $countryIso; + $this->country = $country; + $this->formattedAddress = $formattedAddress; + } + + /** + * @return stdClass + */ + public function jsonSerialize(): stdClass + { + return (object) Json::withoutNullValues([ + 'address_format' => $this->addressFormat, + 'building_number' => $this->buildingNumber, + 'address_line1' => $this->addressLine1, + 'town_city' => $this->townCity, + 'postal_code' => $this->postalCode, + 'country_iso' => $this->countryIso, + 'country' => $this->country, + 'formatted_address' => $this->formattedAddress, + ]); + } + + /** + * @return int|null + */ + public function getAddressFormat(): ?int + { + return $this->addressFormat; + } + + /** + * @return string|null + */ + public function getBuildingNumber(): ?string + { + return $this->buildingNumber; + } + + /** + * @return string|null + */ + public function getAddressLine1(): ?string + { + return $this->addressLine1; + } + + /** + * @return string|null + */ + public function getTownCity(): ?string + { + return $this->townCity; + } + + /** + * @return string|null + */ + public function getPostalCode(): ?string + { + return $this->postalCode; + } + + /** + * @return string|null + */ + public function getCountryIso(): ?string + { + return $this->countryIso; + } + + /** + * @return string|null + */ + public function getCountry(): ?string + { + return $this->country; + } + + /** + * @return string|null + */ + public function getFormattedAddress(): ?string + { + return $this->formattedAddress; + } +} diff --git a/src/DocScan/Session/Create/StructuredPostalAddressBuilder.php b/src/DocScan/Session/Create/StructuredPostalAddressBuilder.php new file mode 100644 index 00000000..3750c25f --- /dev/null +++ b/src/DocScan/Session/Create/StructuredPostalAddressBuilder.php @@ -0,0 +1,145 @@ +addressFormat = $addressFormat; + return $this; + } + + /** + * @param string $buildingNumber + * @return $this + */ + public function withBuildingNumber(string $buildingNumber): self + { + $this->buildingNumber = $buildingNumber; + return $this; + } + + /** + * @param string $addressLine1 + * @return $this + */ + public function withAddressLine1(string $addressLine1): self + { + $this->addressLine1 = $addressLine1; + return $this; + } + + /** + * @param string $townCity + * @return $this + */ + public function withTownCity(string $townCity): self + { + $this->townCity = $townCity; + return $this; + } + + /** + * @param string $postalCode + * @return $this + */ + public function withPostalCode(string $postalCode): self + { + $this->postalCode = $postalCode; + return $this; + } + + /** + * @param string $countryIso + * @return $this + */ + public function withCountryIso(string $countryIso): self + { + $this->countryIso = $countryIso; + return $this; + } + + /** + * @param string $country + * @return $this + */ + public function withCountry(string $country): self + { + $this->country = $country; + return $this; + } + + /** + * @param string $formattedAddress + * @return $this + */ + public function withFormattedAddress(string $formattedAddress): self + { + $this->formattedAddress = $formattedAddress; + return $this; + } + + /** + * @return StructuredPostalAddress + */ + public function build(): StructuredPostalAddress + { + return new StructuredPostalAddress( + $this->addressFormat, + $this->buildingNumber, + $this->addressLine1, + $this->townCity, + $this->postalCode, + $this->countryIso, + $this->country, + $this->formattedAddress + ); + } +} diff --git a/src/DocScan/Session/Retrieve/ApplicantProfileResourceResponse.php b/src/DocScan/Session/Retrieve/ApplicantProfileResourceResponse.php new file mode 100644 index 00000000..35dc108b --- /dev/null +++ b/src/DocScan/Session/Retrieve/ApplicantProfileResourceResponse.php @@ -0,0 +1,70 @@ + $applicantProfile + * @throws DateTimeException + */ + public function __construct(array $applicantProfile) + { + parent::__construct($applicantProfile); + + if (isset($applicantProfile['media'])) { + $this->media = new MediaResponse($applicantProfile['media']); + } + + $this->createdAt = isset($applicantProfile['created_at']) + ? DateTime::stringToDateTime($applicantProfile['created_at']) : null; + + $this->lastUpdated = isset($applicantProfile['last_updated']) + ? DateTime::stringToDateTime($applicantProfile['last_updated']) : null; + } + + /** + * @return MediaResponse|null + */ + public function getMedia(): ?MediaResponse + { + return $this->media; + } + + /** + * @return \DateTime|null + */ + public function getCreatedAt(): ?\DateTime + { + return $this->createdAt; + } + + /** + * @return \DateTime|null + */ + public function getLastUpdated(): ?\DateTime + { + return $this->lastUpdated; + } +} diff --git a/src/DocScan/Session/Retrieve/BreakdownResponse.php b/src/DocScan/Session/Retrieve/BreakdownResponse.php index 8e9ba9c3..410e635c 100644 --- a/src/DocScan/Session/Retrieve/BreakdownResponse.php +++ b/src/DocScan/Session/Retrieve/BreakdownResponse.php @@ -16,6 +16,11 @@ class BreakdownResponse */ private $result; + /** + * @var string|null + */ + private $process; + /** * @var DetailsResponse[] */ @@ -29,6 +34,7 @@ public function __construct(array $breakdown) { $this->subCheck = $breakdown['sub_check'] ?? null; $this->result = $breakdown['result'] ?? null; + $this->process = $breakdown['process'] ?? null; if (isset($breakdown['details'])) { foreach ($breakdown['details'] as $detail) { @@ -53,6 +59,14 @@ public function getResult(): ?string return $this->result; } + /** + * @return string|null + */ + public function getProcess(): ?string + { + return $this->process; + } + /** * @return DetailsResponse[] */ diff --git a/src/DocScan/Session/Retrieve/PageResponse.php b/src/DocScan/Session/Retrieve/PageResponse.php index 163b9ecf..62805cd0 100644 --- a/src/DocScan/Session/Retrieve/PageResponse.php +++ b/src/DocScan/Session/Retrieve/PageResponse.php @@ -21,6 +21,11 @@ class PageResponse */ private $frames = []; + /** + * @var string[] + */ + private $extractionImageIds = []; + /** * PageInfo constructor. * @param array $page @@ -38,6 +43,10 @@ public function __construct(array $page) $this->frames[] = new FrameResponse($frame); } } + + $this->extractionImageIds = isset($page['extraction_image_ids']) && is_array($page['extraction_image_ids']) + ? $page['extraction_image_ids'] + : []; } /** @@ -63,4 +72,12 @@ public function getFrames(): array { return $this->frames; } + + /** + * @return string[] + */ + public function getExtractionImageIds(): array + { + return $this->extractionImageIds; + } } diff --git a/src/DocScan/Session/Retrieve/ResourceContainer.php b/src/DocScan/Session/Retrieve/ResourceContainer.php index 5cc26097..dd0d07c3 100644 --- a/src/DocScan/Session/Retrieve/ResourceContainer.php +++ b/src/DocScan/Session/Retrieve/ResourceContainer.php @@ -31,6 +31,11 @@ class ResourceContainer */ private $shareCodes = []; + /** + * @var ApplicantProfileResourceResponse[] + */ + private $applicantProfiles = []; + /** * ResourceContainer constructor. * @param array $resources @@ -56,6 +61,10 @@ public function __construct(array $resources) if (isset($resources['share_codes'])) { $this->shareCodes = $this->parseShareCodes($resources['share_codes']); } + + if (isset($resources['applicant_profiles'])) { + $this->applicantProfiles = $this->parseApplicantProfiles($resources['applicant_profiles']); + } } /** @@ -178,6 +187,14 @@ public function getShareCodes(): array return $this->shareCodes; } + /** + * @return ApplicantProfileResourceResponse[] + */ + public function getApplicantProfiles(): array + { + return $this->applicantProfiles; + } + /** * @param array> $shareCodes * @return ShareCodeResourceResponse[] @@ -191,6 +208,19 @@ private function parseShareCodes(array $shareCodes): array return $parsedShareCodes; } + /** + * @param array> $applicantProfiles + * @return ApplicantProfileResourceResponse[] + */ + private function parseApplicantProfiles(array $applicantProfiles): array + { + $parsedApplicantProfiles = []; + foreach ($applicantProfiles as $applicantProfile) { + $parsedApplicantProfiles[] = new ApplicantProfileResourceResponse($applicantProfile); + } + return $parsedApplicantProfiles; + } + /** * @param string $class * @return mixed[] diff --git a/src/DocScan/Session/Retrieve/TaskRecommendationReasonResponse.php b/src/DocScan/Session/Retrieve/TaskRecommendationReasonResponse.php new file mode 100644 index 00000000..c365b7cc --- /dev/null +++ b/src/DocScan/Session/Retrieve/TaskRecommendationReasonResponse.php @@ -0,0 +1,44 @@ + $reason + */ + public function __construct(array $reason) + { + $this->value = $reason['value'] ?? null; + $this->detail = $reason['detail'] ?? null; + } + + /** + * @return string|null + */ + public function getValue(): ?string + { + return $this->value; + } + + /** + * @return string|null + */ + public function getDetail(): ?string + { + return $this->detail; + } +} diff --git a/src/DocScan/Session/Retrieve/TaskRecommendationResponse.php b/src/DocScan/Session/Retrieve/TaskRecommendationResponse.php new file mode 100644 index 00000000..9e4ffa72 --- /dev/null +++ b/src/DocScan/Session/Retrieve/TaskRecommendationResponse.php @@ -0,0 +1,47 @@ + $recommendation + */ + public function __construct(array $recommendation) + { + $this->value = $recommendation['value'] ?? null; + + if (isset($recommendation['reason'])) { + $this->reason = new TaskRecommendationReasonResponse($recommendation['reason']); + } + } + + /** + * @return string|null + */ + public function getValue(): ?string + { + return $this->value; + } + + /** + * @return TaskRecommendationReasonResponse|null + */ + public function getReason(): ?TaskRecommendationReasonResponse + { + return $this->reason; + } +} diff --git a/src/DocScan/Session/Retrieve/TaskResponse.php b/src/DocScan/Session/Retrieve/TaskResponse.php index e824cc51..324d8266 100644 --- a/src/DocScan/Session/Retrieve/TaskResponse.php +++ b/src/DocScan/Session/Retrieve/TaskResponse.php @@ -5,6 +5,7 @@ namespace Yoti\DocScan\Session\Retrieve; use Yoti\DocScan\Constants; +use Yoti\Exception\DateTimeException; use Yoti\Util\DateTime; class TaskResponse @@ -44,9 +45,15 @@ class TaskResponse */ private $generatedMedia = []; + /** + * @var TaskRecommendationResponse|null + */ + private $recommendation; + /** * TaskResponse constructor. * @param array $task + * @throws DateTimeException */ public function __construct(array $task) { @@ -67,6 +74,10 @@ public function __construct(array $task) if (isset($task['generated_media'])) { $this->generatedMedia = $this->parseGeneratedMedia($task['generated_media']); } + + if (isset($task['recommendation'])) { + $this->recommendation = new TaskRecommendationResponse($task['recommendation']); + } } /** @@ -161,6 +172,14 @@ public function getGeneratedMedia(): array return $this->generatedMedia; } + /** + * @return TaskRecommendationResponse|null + */ + public function getRecommendation(): ?TaskRecommendationResponse + { + return $this->recommendation; + } + /** * @return GeneratedCheckResponse[] */ diff --git a/tests/DocScan/Session/Create/ApplicantProfileBuilderTest.php b/tests/DocScan/Session/Create/ApplicantProfileBuilderTest.php new file mode 100644 index 00000000..bb000cf3 --- /dev/null +++ b/tests/DocScan/Session/Create/ApplicantProfileBuilderTest.php @@ -0,0 +1,142 @@ +withFullName(self::SOME_FULL_NAME) + ->build(); + + $this->assertEquals(self::SOME_FULL_NAME, $profile->getFullName()); + } + + /** + * @test + * @covers ::build + * @covers ::withDateOfBirth + * @covers \Yoti\DocScan\Session\Create\ApplicantProfile::__construct + * @covers \Yoti\DocScan\Session\Create\ApplicantProfile::getDateOfBirth + */ + public function shouldBuildWithDateOfBirth() + { + $profile = (new ApplicantProfileBuilder()) + ->withDateOfBirth(self::SOME_DATE_OF_BIRTH) + ->build(); + + $this->assertEquals(self::SOME_DATE_OF_BIRTH, $profile->getDateOfBirth()); + } + + /** + * @test + * @covers ::build + * @covers ::withNamePrefix + * @covers \Yoti\DocScan\Session\Create\ApplicantProfile::__construct + * @covers \Yoti\DocScan\Session\Create\ApplicantProfile::getNamePrefix + */ + public function shouldBuildWithNamePrefix() + { + $profile = (new ApplicantProfileBuilder()) + ->withNamePrefix(self::SOME_NAME_PREFIX) + ->build(); + + $this->assertEquals(self::SOME_NAME_PREFIX, $profile->getNamePrefix()); + } + + /** + * @test + * @covers ::build + * @covers ::withStructuredPostalAddress + * @covers \Yoti\DocScan\Session\Create\ApplicantProfile::__construct + * @covers \Yoti\DocScan\Session\Create\ApplicantProfile::getStructuredPostalAddress + */ + public function shouldBuildWithStructuredPostalAddress() + { + $address = (new StructuredPostalAddressBuilder()) + ->withBuildingNumber('74') + ->withPostalCode('E143RN') + ->build(); + + $profile = (new ApplicantProfileBuilder()) + ->withStructuredPostalAddress($address) + ->build(); + + $this->assertEquals('74', $profile->getStructuredPostalAddress()->getBuildingNumber()); + $this->assertEquals('E143RN', $profile->getStructuredPostalAddress()->getPostalCode()); + } + + /** + * @test + * @covers ::build + * @covers \Yoti\DocScan\Session\Create\ApplicantProfile::jsonSerialize + */ + public function shouldCorrectlySerializeWithAllProperties() + { + $address = (new StructuredPostalAddressBuilder()) + ->withAddressFormat(1) + ->withBuildingNumber('74') + ->withAddressLine1('AddressLine1') + ->withTownCity('CityName') + ->withPostalCode('E143RN') + ->withCountryIso('GBR') + ->withCountry('United Kingdom') + ->build(); + + $profile = (new ApplicantProfileBuilder()) + ->withFullName(self::SOME_FULL_NAME) + ->withDateOfBirth(self::SOME_DATE_OF_BIRTH) + ->withNamePrefix(self::SOME_NAME_PREFIX) + ->withStructuredPostalAddress($address) + ->build(); + + $json = json_encode($profile); + + $this->assertStringContainsString('"full_name":"John Doe"', $json); + $this->assertStringContainsString('"date_of_birth":"1988-11-02"', $json); + $this->assertStringContainsString('"name_prefix":"Mr"', $json); + $this->assertStringContainsString('"structured_postal_address"', $json); + $this->assertStringContainsString('"building_number":"74"', $json); + $this->assertStringContainsString('"country_iso":"GBR"', $json); + } + + /** + * @test + * @covers ::build + * @covers \Yoti\DocScan\Session\Create\ApplicantProfile::jsonSerialize + */ + public function shouldSerializeWithoutNullValues() + { + $profile = (new ApplicantProfileBuilder()) + ->withFullName(self::SOME_FULL_NAME) + ->build(); + + $this->assertJsonStringEqualsJsonString( + json_encode([ + 'full_name' => self::SOME_FULL_NAME, + ]), + json_encode($profile) + ); + } +} diff --git a/tests/DocScan/Session/Create/ResourceCreationContainerBuilderTest.php b/tests/DocScan/Session/Create/ResourceCreationContainerBuilderTest.php new file mode 100644 index 00000000..4ad23b4d --- /dev/null +++ b/tests/DocScan/Session/Create/ResourceCreationContainerBuilderTest.php @@ -0,0 +1,93 @@ +withFullName('John Doe') + ->withDateOfBirth('1988-11-02') + ->build(); + + $container = (new ResourceCreationContainerBuilder()) + ->withApplicantProfile($applicantProfile) + ->build(); + + $this->assertEquals($applicantProfile, $container->getApplicantProfile()); + $this->assertEquals('John Doe', $container->getApplicantProfile()->getFullName()); + $this->assertEquals('1988-11-02', $container->getApplicantProfile()->getDateOfBirth()); + } + + /** + * @test + * @covers ::build + * @covers \Yoti\DocScan\Session\Create\ResourceCreationContainer::jsonSerialize + */ + public function shouldCorrectlySerializeApplicantProfile() + { + $address = (new StructuredPostalAddressBuilder()) + ->withAddressFormat(1) + ->withBuildingNumber('74') + ->withAddressLine1('AddressLine1') + ->withTownCity('CityName') + ->withPostalCode('E143RN') + ->withCountryIso('GBR') + ->withCountry('United Kingdom') + ->build(); + + $applicantProfile = (new ApplicantProfileBuilder()) + ->withFullName('John Doe') + ->withDateOfBirth('1988-11-02') + ->withNamePrefix('Mr') + ->withStructuredPostalAddress($address) + ->build(); + + $container = (new ResourceCreationContainerBuilder()) + ->withApplicantProfile($applicantProfile) + ->build(); + + $json = json_encode($container); + + $this->assertStringContainsString('"applicant_profile"', $json); + $this->assertStringContainsString('"full_name":"John Doe"', $json); + $this->assertStringContainsString('"date_of_birth":"1988-11-02"', $json); + $this->assertStringContainsString('"name_prefix":"Mr"', $json); + $this->assertStringContainsString('"building_number":"74"', $json); + $this->assertStringContainsString('"country_iso":"GBR"', $json); + } + + /** + * @test + * @covers ::build + * @covers \Yoti\DocScan\Session\Create\ResourceCreationContainer::jsonSerialize + */ + public function shouldSerializeWithoutNullValues() + { + $container = (new ResourceCreationContainerBuilder()) + ->build(); + + $this->assertJsonStringEqualsJsonString( + json_encode(new \stdClass()), + json_encode($container) + ); + } +} diff --git a/tests/DocScan/Session/Create/SessionSpecificationBuilderTest.php b/tests/DocScan/Session/Create/SessionSpecificationBuilderTest.php index 266e47e4..f1d274b2 100644 --- a/tests/DocScan/Session/Create/SessionSpecificationBuilderTest.php +++ b/tests/DocScan/Session/Create/SessionSpecificationBuilderTest.php @@ -9,6 +9,7 @@ use Yoti\DocScan\Session\Create\IbvOptions; use Yoti\DocScan\Session\Create\ImportToken; use Yoti\DocScan\Session\Create\NotificationConfig; +use Yoti\DocScan\Session\Create\ResourceCreationContainer; use Yoti\DocScan\Session\Create\SdkConfig; use Yoti\DocScan\Session\Create\SessionSpecificationBuilder; use Yoti\DocScan\Session\Create\Task\RequestedTask; @@ -73,6 +74,11 @@ class SessionSpecificationBuilderTest extends TestCase */ private $importTokenMock; + /** + * @var ResourceCreationContainer + */ + private $resourcesMock; + public function setup(): void { $this->sdkConfigMock = $this->createMock(SdkConfig::class); @@ -94,6 +100,11 @@ public function setup(): void $this->importTokenMock = $this->createMock(ImportToken::class); + $this->resourcesMock = $this->createMock(ResourceCreationContainer::class); + $this->resourcesMock + ->method('jsonSerialize') + ->willReturn((object)['applicant_profile' => (object)['full_name' => 'John Doe']]); + $this->subject = (object)[1 => 'some']; $this->identityProfileRequirements = (object)[ @@ -605,4 +616,58 @@ public function shouldReturnCorrectJsonStringWithAdvancedIdentityProfileRequirem json_encode($sessionSpecification) ); } + + /** + * @test + * @covers \Yoti\DocScan\Session\Create\SessionSpecification::getResources + * @covers \Yoti\DocScan\Session\Create\SessionSpecification::__construct + * @covers \Yoti\DocScan\Session\Create\SessionSpecificationBuilder::withResources + * @covers \Yoti\DocScan\Session\Create\SessionSpecificationBuilder::build + */ + public function shouldBuildWithResources() + { + $sessionSpecificationResult = (new SessionSpecificationBuilder()) + ->withResources($this->resourcesMock) + ->build(); + + $this->assertEquals($this->resourcesMock, $sessionSpecificationResult->getResources()); + } + + /** + * @test + * @covers \Yoti\DocScan\Session\Create\SessionSpecification::getResources + * @covers \Yoti\DocScan\Session\Create\SessionSpecification::__construct + * @covers \Yoti\DocScan\Session\Create\SessionSpecificationBuilder::build + */ + public function shouldNotImplicitlySetAValueForResources() + { + $sessionSpecificationResult = (new SessionSpecificationBuilder()) + ->build(); + + $this->assertNull($sessionSpecificationResult->getResources()); + } + + /** + * @test + * @covers \Yoti\DocScan\Session\Create\SessionSpecification::jsonSerialize + * @covers \Yoti\DocScan\Session\Create\SessionSpecificationBuilder::withResources + * @covers \Yoti\DocScan\Session\Create\SessionSpecificationBuilder::build + */ + public function shouldReturnCorrectJsonStringWithResources() + { + $sessionSpecification = (new SessionSpecificationBuilder()) + ->withResources($this->resourcesMock) + ->build(); + + $this->assertJsonStringEqualsJsonString( + json_encode([ + 'requested_checks' => [], + 'requested_tasks' => [], + 'required_documents' => [], + 'create_identity_profile_preview' => false, + 'resources' => $this->resourcesMock, + ]), + json_encode($sessionSpecification) + ); + } } diff --git a/tests/DocScan/Session/Create/StructuredPostalAddressBuilderTest.php b/tests/DocScan/Session/Create/StructuredPostalAddressBuilderTest.php new file mode 100644 index 00000000..ad4f6a80 --- /dev/null +++ b/tests/DocScan/Session/Create/StructuredPostalAddressBuilderTest.php @@ -0,0 +1,121 @@ +withAddressFormat(self::SOME_ADDRESS_FORMAT) + ->withBuildingNumber(self::SOME_BUILDING_NUMBER) + ->withAddressLine1(self::SOME_ADDRESS_LINE_1) + ->withTownCity(self::SOME_TOWN_CITY) + ->withPostalCode(self::SOME_POSTAL_CODE) + ->withCountryIso(self::SOME_COUNTRY_ISO) + ->withCountry(self::SOME_COUNTRY) + ->withFormattedAddress(self::SOME_FORMATTED_ADDRESS) + ->build(); + + $this->assertEquals(self::SOME_ADDRESS_FORMAT, $address->getAddressFormat()); + $this->assertEquals(self::SOME_BUILDING_NUMBER, $address->getBuildingNumber()); + $this->assertEquals(self::SOME_ADDRESS_LINE_1, $address->getAddressLine1()); + $this->assertEquals(self::SOME_TOWN_CITY, $address->getTownCity()); + $this->assertEquals(self::SOME_POSTAL_CODE, $address->getPostalCode()); + $this->assertEquals(self::SOME_COUNTRY_ISO, $address->getCountryIso()); + $this->assertEquals(self::SOME_COUNTRY, $address->getCountry()); + $this->assertEquals(self::SOME_FORMATTED_ADDRESS, $address->getFormattedAddress()); + } + + /** + * @test + * @covers ::build + * @covers \Yoti\DocScan\Session\Create\StructuredPostalAddress::jsonSerialize + */ + public function shouldCorrectlySerialize() + { + $address = (new StructuredPostalAddressBuilder()) + ->withAddressFormat(self::SOME_ADDRESS_FORMAT) + ->withBuildingNumber(self::SOME_BUILDING_NUMBER) + ->withAddressLine1(self::SOME_ADDRESS_LINE_1) + ->withTownCity(self::SOME_TOWN_CITY) + ->withPostalCode(self::SOME_POSTAL_CODE) + ->withCountryIso(self::SOME_COUNTRY_ISO) + ->withCountry(self::SOME_COUNTRY) + ->withFormattedAddress(self::SOME_FORMATTED_ADDRESS) + ->build(); + + $this->assertJsonStringEqualsJsonString( + json_encode([ + 'address_format' => self::SOME_ADDRESS_FORMAT, + 'building_number' => self::SOME_BUILDING_NUMBER, + 'address_line1' => self::SOME_ADDRESS_LINE_1, + 'town_city' => self::SOME_TOWN_CITY, + 'postal_code' => self::SOME_POSTAL_CODE, + 'country_iso' => self::SOME_COUNTRY_ISO, + 'country' => self::SOME_COUNTRY, + 'formatted_address' => self::SOME_FORMATTED_ADDRESS, + ]), + json_encode($address) + ); + } + + /** + * @test + * @covers ::build + * @covers \Yoti\DocScan\Session\Create\StructuredPostalAddress::jsonSerialize + */ + public function shouldSerializeWithoutNullValues() + { + $address = (new StructuredPostalAddressBuilder()) + ->withBuildingNumber(self::SOME_BUILDING_NUMBER) + ->withPostalCode(self::SOME_POSTAL_CODE) + ->build(); + + $this->assertJsonStringEqualsJsonString( + json_encode([ + 'building_number' => self::SOME_BUILDING_NUMBER, + 'postal_code' => self::SOME_POSTAL_CODE, + ]), + json_encode($address) + ); + } +} diff --git a/tests/DocScan/Session/Retrieve/ApplicantProfileResourceResponseTest.php b/tests/DocScan/Session/Retrieve/ApplicantProfileResourceResponseTest.php new file mode 100644 index 00000000..645deaf2 --- /dev/null +++ b/tests/DocScan/Session/Retrieve/ApplicantProfileResourceResponseTest.php @@ -0,0 +1,81 @@ + self::SOME_ID, + 'source' => [ + 'type' => self::SOME_SOURCE_TYPE, + ], + 'media' => [ + 'id' => self::SOME_MEDIA_ID, + 'type' => self::SOME_MEDIA_TYPE, + 'created' => self::SOME_CREATED_AT, + 'last_updated' => self::SOME_LAST_UPDATED, + ], + 'created_at' => self::SOME_CREATED_AT, + 'last_updated' => self::SOME_LAST_UPDATED, + 'tasks' => [], + ]; + + $result = new ApplicantProfileResourceResponse($input); + + $this->assertEquals(self::SOME_ID, $result->getId()); + $this->assertNotNull($result->getSource()); + $this->assertInstanceOf(MediaResponse::class, $result->getMedia()); + $this->assertEquals(self::SOME_MEDIA_ID, $result->getMedia()->getId()); + $this->assertEquals(self::SOME_MEDIA_TYPE, $result->getMedia()->getType()); + $this->assertEquals( + DateTime::stringToDateTime(self::SOME_CREATED_AT), + $result->getCreatedAt() + ); + $this->assertEquals( + DateTime::stringToDateTime(self::SOME_LAST_UPDATED), + $result->getLastUpdated() + ); + $this->assertCount(0, $result->getTasks()); + } + + /** + * @test + * @covers ::__construct + */ + public function shouldNotThrowExceptionWhenMissingValues() + { + $result = new ApplicantProfileResourceResponse([]); + + $this->assertNull($result->getId()); + $this->assertNull($result->getMedia()); + $this->assertNull($result->getCreatedAt()); + $this->assertNull($result->getLastUpdated()); + $this->assertCount(0, $result->getTasks()); + } +} diff --git a/tests/DocScan/Session/Retrieve/BreakdownResponseTest.php b/tests/DocScan/Session/Retrieve/BreakdownResponseTest.php index dc92d2fd..7d2c9a30 100644 --- a/tests/DocScan/Session/Retrieve/BreakdownResponseTest.php +++ b/tests/DocScan/Session/Retrieve/BreakdownResponseTest.php @@ -25,11 +25,15 @@ class BreakdownResponseTest extends TestCase ], ]; + private const SOME_PROCESS = 'AUTOMATED'; + private const SOME_EXPERT_REVIEW_PROCESS = 'EXPERT_REVIEW'; + /** * @test * @covers ::__construct * @covers ::getSubCheck * @covers ::getResult + * @covers ::getProcess * @covers ::getDetails * @covers \Yoti\DocScan\Session\Retrieve\DetailsResponse::__construct * @covers \Yoti\DocScan\Session\Retrieve\DetailsResponse::getName @@ -40,6 +44,7 @@ public function shouldBuildCorrectly() $input = [ 'sub_check' => self::SOME_SUB_CHECK, 'result' => self::SOME_RESULT, + 'process' => self::SOME_PROCESS, 'details' => self::SOME_DETAILS, ]; @@ -47,6 +52,7 @@ public function shouldBuildCorrectly() $this->assertEquals(self::SOME_SUB_CHECK, $result->getSubCheck()); $this->assertEquals(self::SOME_RESULT, $result->getResult()); + $this->assertEquals(self::SOME_PROCESS, $result->getProcess()); $details = $result->getDetails(); for ($i = 0; $i < count(self::SOME_DETAILS); $i++) { @@ -61,6 +67,7 @@ public function shouldBuildCorrectly() * @covers ::__construct * @covers ::getSubCheck * @covers ::getResult + * @covers ::getProcess * @covers ::getDetails */ public function shouldNotThrowExceptionWhenValuesAreMissing() @@ -71,6 +78,19 @@ public function shouldNotThrowExceptionWhenValuesAreMissing() $this->assertNull($result->getSubCheck()); $this->assertNull($result->getResult()); + $this->assertNull($result->getProcess()); $this->assertCount(0, $result->getDetails()); } + + /** + * @test + * @covers ::__construct + * @covers ::getProcess + */ + public function shouldExposeExpertReviewProcessValue() + { + $result = new BreakdownResponse(['process' => self::SOME_EXPERT_REVIEW_PROCESS]); + + $this->assertEquals(self::SOME_EXPERT_REVIEW_PROCESS, $result->getProcess()); + } } diff --git a/tests/DocScan/Session/Retrieve/PageResponseTest.php b/tests/DocScan/Session/Retrieve/PageResponseTest.php index 91306f12..063e0628 100644 --- a/tests/DocScan/Session/Retrieve/PageResponseTest.php +++ b/tests/DocScan/Session/Retrieve/PageResponseTest.php @@ -53,7 +53,26 @@ public function testGetFrames() ]); $this->assertCount(2, $pageResponse->getFrames()); - $this->containsOnlyInstancesOf(FrameResponse::class, $pageResponse->getFrames()); + $this->assertContainsOnlyInstancesOf(FrameResponse::class, $pageResponse->getFrames()); + } + + /** + * @covers ::__construct + * @covers ::getExtractionImageIds + */ + public function testGetExtractionImageIds() + { + $extractionImageIds = [ + '066a9372-0a52-4fe4-a026-866f8aee6fcb', + '9b0c9c0a-ff30-41ed-815b-d95d63271d45', + ]; + + $pageResponse = new PageResponse([ + 'extraction_image_ids' => $extractionImageIds, + ]); + + $this->assertCount(2, $pageResponse->getExtractionImageIds()); + $this->assertEquals($extractionImageIds, $pageResponse->getExtractionImageIds()); } /** @@ -67,5 +86,6 @@ public function shouldNotThrowExceptionWhenMissingValues() $this->assertNull($result->getCaptureMethod()); $this->assertNull($result->getMedia()); $this->assertEquals([], $result->getFrames()); + $this->assertEquals([], $result->getExtractionImageIds()); } } diff --git a/tests/DocScan/Session/Retrieve/ResourceContainerTest.php b/tests/DocScan/Session/Retrieve/ResourceContainerTest.php index 48dba28d..f73beb81 100644 --- a/tests/DocScan/Session/Retrieve/ResourceContainerTest.php +++ b/tests/DocScan/Session/Retrieve/ResourceContainerTest.php @@ -4,6 +4,7 @@ namespace Yoti\Test\DocScan\Session\Retrieve; +use Yoti\DocScan\Session\Retrieve\ApplicantProfileResourceResponse; use Yoti\DocScan\Session\Retrieve\ResourceContainer; use Yoti\DocScan\Session\Retrieve\ShareCodeResourceResponse; use Yoti\DocScan\Session\Retrieve\StaticLivenessResourceResponse; @@ -53,7 +54,10 @@ public function shouldBuildCorrectly() 'share_codes' => [ ['id' => 'share-code-1'], ['id' => 'share-code-2'], - ] + ], + 'applicant_profiles' => [ + ['id' => 'applicant-profile-1'], + ], ]; $result = new ResourceContainer($input); @@ -65,6 +69,7 @@ public function shouldBuildCorrectly() $this->assertCount(2, $result->getSupplementaryDocuments()); $this->assertCount(1, $result->getFaceCapture()); $this->assertCount(2, $result->getShareCodes()); + $this->assertCount(1, $result->getApplicantProfiles()); } /** @@ -78,6 +83,7 @@ public function shouldNotThrowExceptionWhenMissingValues() $this->assertCount(0, $result->getIdDocuments()); $this->assertCount(0, $result->getLivenessCapture()); $this->assertCount(0, $result->getShareCodes()); + $this->assertCount(0, $result->getApplicantProfiles()); } /** @@ -175,4 +181,42 @@ public function shouldParseShareCodes(): void $this->assertEquals('share-code-1', $result->getShareCodes()[0]->getId()); $this->assertEquals('share-code-2', $result->getShareCodes()[1]->getId()); } + + /** + * @test + * @covers ::parseApplicantProfiles + * @covers ::getApplicantProfiles + */ + public function shouldParseApplicantProfiles(): void + { + $input = [ + 'applicant_profiles' => [ + [ + 'id' => '3fa85f64-5717-4562-b3fc-2c963f66afa6', + 'source' => ['type' => 'END_USER'], + 'media' => [ + 'id' => 'media-id-123', + 'type' => 'IMAGE', + 'created' => '2021-06-11T11:39:24Z', + 'last_updated' => '2021-06-11T11:39:24Z', + ], + 'created_at' => '2021-06-11T11:39:24Z', + 'last_updated' => '2021-06-11T11:39:24Z', + 'tasks' => [], + ], + ], + ]; + + $result = new ResourceContainer($input); + + $this->assertCount(1, $result->getApplicantProfiles()); + $this->assertContainsOnlyInstancesOf( + ApplicantProfileResourceResponse::class, + $result->getApplicantProfiles() + ); + $this->assertEquals( + '3fa85f64-5717-4562-b3fc-2c963f66afa6', + $result->getApplicantProfiles()[0]->getId() + ); + } } diff --git a/tests/DocScan/Session/Retrieve/TaskRecommendationReasonResponseTest.php b/tests/DocScan/Session/Retrieve/TaskRecommendationReasonResponseTest.php new file mode 100644 index 00000000..80c0a74c --- /dev/null +++ b/tests/DocScan/Session/Retrieve/TaskRecommendationReasonResponseTest.php @@ -0,0 +1,48 @@ + self::SOME_VALUE, + 'detail' => self::SOME_DETAIL, + ]; + + $result = new TaskRecommendationReasonResponse($input); + + $this->assertEquals(self::SOME_VALUE, $result->getValue()); + $this->assertEquals(self::SOME_DETAIL, $result->getDetail()); + } + + /** + * @test + * @covers ::__construct + */ + public function shouldNotThrowExceptionWhenMissingValues() + { + $result = new TaskRecommendationReasonResponse([]); + + $this->assertNull($result->getValue()); + $this->assertNull($result->getDetail()); + } +} diff --git a/tests/DocScan/Session/Retrieve/TaskRecommendationResponseTest.php b/tests/DocScan/Session/Retrieve/TaskRecommendationResponseTest.php new file mode 100644 index 00000000..46c265b9 --- /dev/null +++ b/tests/DocScan/Session/Retrieve/TaskRecommendationResponseTest.php @@ -0,0 +1,55 @@ + self::SOME_VALUE, + 'reason' => [ + 'value' => self::SOME_REASON_VALUE, + 'detail' => self::SOME_REASON_DETAIL, + ], + ]; + + $result = new TaskRecommendationResponse($input); + + $this->assertEquals(self::SOME_VALUE, $result->getValue()); + $this->assertInstanceOf(TaskRecommendationReasonResponse::class, $result->getReason()); + $this->assertEquals(self::SOME_REASON_VALUE, $result->getReason()->getValue()); + $this->assertEquals(self::SOME_REASON_DETAIL, $result->getReason()->getDetail()); + } + + /** + * @test + * @covers ::__construct + */ + public function shouldNotThrowExceptionWhenMissingValues() + { + $result = new TaskRecommendationResponse([]); + + $this->assertNull($result->getValue()); + $this->assertNull($result->getReason()); + } +} diff --git a/tests/DocScan/Session/Retrieve/TaskResponseTest.php b/tests/DocScan/Session/Retrieve/TaskResponseTest.php index 2b63366b..b3483119 100644 --- a/tests/DocScan/Session/Retrieve/TaskResponseTest.php +++ b/tests/DocScan/Session/Retrieve/TaskResponseTest.php @@ -7,6 +7,8 @@ use Yoti\DocScan\Session\Retrieve\GeneratedCheckResponse; use Yoti\DocScan\Session\Retrieve\GeneratedMedia; use Yoti\DocScan\Session\Retrieve\GeneratedTextDataCheckResponse; +use Yoti\DocScan\Session\Retrieve\TaskRecommendationReasonResponse; +use Yoti\DocScan\Session\Retrieve\TaskRecommendationResponse; use Yoti\DocScan\Session\Retrieve\TaskResponse; use Yoti\Test\TestCase; use Yoti\Util\DateTime; @@ -25,6 +27,9 @@ class TaskResponseTest extends TestCase private const SOME_UNKNOWN_TYPE = 'someUnknownType'; private const ID_DOCUMENT_TEXT_DATA_CHECK = 'ID_DOCUMENT_TEXT_DATA_CHECK'; private const SUPPLEMENTARY_DOCUMENT_TEXT_DATA_CHECK = 'SUPPLEMENTARY_DOCUMENT_TEXT_DATA_CHECK'; + private const SOME_RECOMMENDATION_VALUE = 'MUST_TRY_AGAIN'; + private const SOME_RECOMMENDATION_REASON_VALUE = 'USER_ERROR'; + private const SOME_RECOMMENDATION_REASON_DETAIL = 'NO_DOCUMENT'; /** * @var TaskResponse @@ -57,6 +62,13 @@ public function setup(): void [], [], ], + 'recommendation' => [ + 'value' => self::SOME_RECOMMENDATION_VALUE, + 'reason' => [ + 'value' => self::SOME_RECOMMENDATION_REASON_VALUE, + 'detail' => self::SOME_RECOMMENDATION_REASON_DETAIL, + ], + ], ]); } @@ -185,5 +197,22 @@ public function shouldNotThrowExceptionWhenAllMissingValuesExceptType() $this->assertNull($result->getLastUpdated()); $this->assertCount(0, $result->getGeneratedChecks()); $this->assertCount(0, $result->getGeneratedMedia()); + $this->assertNull($result->getRecommendation()); + } + + /** + * @test + * @covers ::__construct + * @covers ::getRecommendation + */ + public function shouldReturnRecommendation() + { + $recommendation = $this->taskResponse->getRecommendation(); + + $this->assertInstanceOf(TaskRecommendationResponse::class, $recommendation); + $this->assertEquals(self::SOME_RECOMMENDATION_VALUE, $recommendation->getValue()); + $this->assertInstanceOf(TaskRecommendationReasonResponse::class, $recommendation->getReason()); + $this->assertEquals(self::SOME_RECOMMENDATION_REASON_VALUE, $recommendation->getReason()->getValue()); + $this->assertEquals(self::SOME_RECOMMENDATION_REASON_DETAIL, $recommendation->getReason()->getDetail()); } }