diff --git a/src/Bovin/Dto/PresumedExitDto.php b/src/Bovin/Dto/PresumedExitDto.php new file mode 100644 index 0000000..638434e --- /dev/null +++ b/src/Bovin/Dto/PresumedExitDto.php @@ -0,0 +1,15 @@ + $presumedExits + */ + public function __construct( + public StandardResponseDto $standardResponse, + public int $nbBovins, + public array $presumedExits, + public ?object $rawSoapResponse, + ) {} +} diff --git a/src/Bovin/Mapper/PresumedExitsMapper.php b/src/Bovin/Mapper/PresumedExitsMapper.php new file mode 100644 index 0000000..babaacb --- /dev/null +++ b/src/Bovin/Mapper/PresumedExitsMapper.php @@ -0,0 +1,46 @@ +standardResponseMapper->map($soapResponse->ReponseStandard ?? null); + $nbBovins = $this->toNullableInt($soapResponse->ReponseSpecifique->NbBovins ?? null) ?? 0; + + $presumedExits = []; + + if (is_object($unzippedMessage)) { + $exitsNode = $unzippedMessage->SortiesPresumees->SortiePresumee ?? null; + foreach ($this->normalizeToList($exitsNode) as $exitNode) { + if (!is_object($exitNode)) { + continue; + } + $presumedExits[] = new PresumedExitDto( + bovin: $this->mapBovinRef($exitNode->Bovin ?? null), + exitDate: $this->toNullableDate($exitNode->DateSortie ?? null), + ); + } + } + + return new PresumedExitsDto( + standardResponse: $standardResponse, + nbBovins: $nbBovins, + presumedExits: $presumedExits, + rawSoapResponse: $soapResponse, + ); + } +} diff --git a/tests/Unit/Bovin/Mapper/PresumedExitsMapperTest.php b/tests/Unit/Bovin/Mapper/PresumedExitsMapperTest.php new file mode 100644 index 0000000..7f08f01 --- /dev/null +++ b/tests/Unit/Bovin/Mapper/PresumedExitsMapperTest.php @@ -0,0 +1,72 @@ +ReponseStandard = new stdClass(); + $soapResponse->ReponseStandard->Resultat = true; + $soapResponse->ReponseSpecifique = new stdClass(); + $soapResponse->ReponseSpecifique->NbBovins = 2; + + $message = new stdClass(); + $message->SortiesPresumees = new stdClass(); + $message->SortiesPresumees->SortiePresumee = [ + $this->makeExit('FR111', '2026-02-15'), + $this->makeExit('FR222', null), + ]; + + $dto = new PresumedExitsMapper(new StandardResponseMapper())->map($soapResponse, $message); + + self::assertInstanceOf(PresumedExitsDto::class, $dto); + self::assertSame(2, $dto->nbBovins); + self::assertCount(2, $dto->presumedExits); + self::assertSame('FR111', $dto->presumedExits[0]->bovin?->nationalNumber); + self::assertEquals(new DateTimeImmutable('2026-02-15'), $dto->presumedExits[0]->exitDate); + self::assertNull($dto->presumedExits[1]->exitDate); + } + + public function testMapWithoutMessageReturnsEmpty(): void + { + $soapResponse = new stdClass(); + $soapResponse->ReponseStandard = new stdClass(); + $soapResponse->ReponseStandard->Resultat = true; + $soapResponse->ReponseSpecifique = new stdClass(); + $soapResponse->ReponseSpecifique->NbBovins = 0; + + $dto = new PresumedExitsMapper(new StandardResponseMapper())->map($soapResponse, null); + + self::assertSame(0, $dto->nbBovins); + self::assertSame([], $dto->presumedExits); + } + + private function makeExit(string $nationalNumber, ?string $exitDate): object + { + $node = new stdClass(); + $node->Bovin = new stdClass(); + $node->Bovin->CodePays = 'FR'; + $node->Bovin->NumeroNational = $nationalNumber; + if (null !== $exitDate) { + $node->DateSortie = $exitDate; + } + + return $node; + } +}