diff --git a/src/Api.php b/src/Api.php index 17c6e12..7056043 100644 --- a/src/Api.php +++ b/src/Api.php @@ -176,6 +176,21 @@ class Api ->map(fn ($membership) => new MembershipEntry($membership)); } + public function deleteMembership(int $memberId, Membership $membership): void + { + $this->assertLoggedIn(); + + try { + $this->delete("/ica/rest/nami/zugeordnete-taetigkeiten/filtered-for-navigation/gruppierung-mitglied/mitglied/{$memberId}/{$membership->id}", 'Deleting membership failed'); + } catch (NamiException $e) { + if (is_null($membership->id)) { + throw new NamiException('ID not given in membership'); + } + $membership->endsAt = today(); + $this->putMembership($memberId, $membership); + } + } + public function subactivitiesOf(int $activityId): Collection { $this->assertLoggedIn(); @@ -479,4 +494,17 @@ class Api return $response['data']; } + + private function delete(string $url, string $error): void + { + $response = $this->http()->delete($this->url.$url); + + if (null === $response->json()) { + $this->exception($error, $url, $response->json()); + } + + if (false === $response['success']) { + $this->exception($error, $url, $response->json()); + } + } } diff --git a/src/Data/Membership.php b/src/Data/Membership.php index 2a5bebf..3e632bc 100644 --- a/src/Data/Membership.php +++ b/src/Data/Membership.php @@ -39,7 +39,7 @@ class Membership extends DataTransferObject 'gruppierungId' => $this->groupId, 'id' => $this->id, 'aktivVon' => $this->startsAt->format('Y-m-d').'T00:00:00', - 'aktivBis' => $this->endsAt ? $this->endsAt->toDateTimeString() : null, + 'aktivBis' => $this->endsAt ? $this->endsAt->format('Y-m-d').'T00:00:00' : null, 'taetigkeitId' => $this->activityId, 'untergliederungId' => $this->subactivityId, ]; diff --git a/src/Fakes/Fake.php b/src/Fakes/Fake.php index a21c7ca..0707f5e 100644 --- a/src/Fakes/Fake.php +++ b/src/Fakes/Fake.php @@ -41,6 +41,14 @@ abstract class Fake ])); } + public function nullResponse(): PromiseInterface + { + return Http::response(json_encode([ + 'success' => true, + 'data' => null, + ])); + } + public function htmlResponse(): PromiseInterface { return Http::response(''); diff --git a/src/Fakes/MembershipFake.php b/src/Fakes/MembershipFake.php index 464e631..e03d358 100644 --- a/src/Fakes/MembershipFake.php +++ b/src/Fakes/MembershipFake.php @@ -125,6 +125,41 @@ class MembershipFake extends Fake }); } + public function updatesSuccessfully(int $memberId, ?int $membershipId): void + { + Http::fake(function ($request) use ($memberId, $membershipId) { + if ($request->url() === "https://nami.dpsg.de/ica/rest/nami/zugeordnete-taetigkeiten/filtered-for-navigation/gruppierung-mitglied/mitglied/{$memberId}/{$membershipId}" && 'PUT' === $request->method()) { + return $this->dataResponse(['id' => $membershipId]); + } + }); + } + + public function deletesSuccessfully(int $memberId, int $membershipId): void + { + Http::fake(function ($request) use ($memberId, $membershipId) { + if ($request->url() === "https://nami.dpsg.de/ica/rest/nami/zugeordnete-taetigkeiten/filtered-for-navigation/gruppierung-mitglied/mitglied/{$memberId}/{$membershipId}" && 'DELETE' === $request->method()) { + return $this->nullResponse(); + } + }); + } + + public function failsDeleting(int $memberId, ?int $membershipId): void + { + Http::fake(function ($request) use ($memberId, $membershipId) { + if ($request->url() === "https://nami.dpsg.de/ica/rest/nami/zugeordnete-taetigkeiten/filtered-for-navigation/gruppierung-mitglied/mitglied/{$memberId}/{$membershipId}" && 'DELETE' === $request->method()) { + return $this->errorResponse(''); + } + }); + } + + public function assertDeleted(int $memberId, int $membershipId): void + { + $url = "https://nami.dpsg.de/ica/rest/nami/zugeordnete-taetigkeiten/filtered-for-navigation/gruppierung-mitglied/mitglied/{$memberId}/{$membershipId}"; + Http::assertSent(function ($request) use ($url) { + return $request->url() === $url && 'DELETE' === $request->method(); + }); + } + public function assertCreated(int $memberId, array $payload): void { $url = "https://nami.dpsg.de/ica/rest/nami/zugeordnete-taetigkeiten/filtered-for-navigation/gruppierung-mitglied/mitglied/{$memberId}"; @@ -149,4 +184,24 @@ class MembershipFake extends Fake return true; }); } + + public function assertUpdated(int $memberId, array $payload): void + { + $url = "https://nami.dpsg.de/ica/rest/nami/zugeordnete-taetigkeiten/filtered-for-navigation/gruppierung-mitglied/mitglied/{$memberId}/{$payload['id']}"; + Http::assertSent(function ($request) use ($url, $payload) { + if ($request->url() !== $url || 'PUT' !== $request->method()) { + return false; + } + + if (data_get($request, 'id') !== $payload['id']) { + return false; + } + + if (data_get($request, 'aktivBis') !== data_get($payload, 'aktivBis')) { + return false; + } + + return true; + }); + } } diff --git a/tests/Unit/Api/MembershipTest.php b/tests/Unit/Api/MembershipTest.php index c6f673b..9e12721 100644 --- a/tests/Unit/Api/MembershipTest.php +++ b/tests/Unit/Api/MembershipTest.php @@ -96,4 +96,59 @@ class MembershipTest extends TestCase 'gruppierungId' => 1400, ]); } + + public function testItCanDeleteAMembership(): void + { + Carbon::setTestNow(Carbon::parse('2022-02-03 03:00:00')); + app(MembershipFake::class)->deletesSuccessfully(6, 133); + + $this->login()->deleteMembership(6, Membership::fromArray([ + 'id' => 133, + 'subactivityId' => 3, + 'activityId' => 2, + 'groupId' => 1400, + 'startsAt' => Carbon::parse('2022-02-03 00:00:00'), + 'endsAt' => null, + ])); + + app(MembershipFake::class)->assertDeleted(6, 133); + } + + public function testItSetsAMembershipsEndDateWhenDeletingFails(): void + { + Carbon::setTestNow(Carbon::parse('2022-02-03 03:00:00')); + app(MembershipFake::class)->failsDeleting(6, 133); + app(MembershipFake::class)->updatesSuccessfully(6, 133); + + $this->login()->deleteMembership(6, Membership::fromArray([ + 'id' => 133, + 'subactivityId' => 3, + 'activityId' => 2, + 'groupId' => 1400, + 'startsAt' => Carbon::parse('2022-02-03 00:00:00'), + 'endsAt' => null, + ])); + + app(MembershipFake::class)->assertUpdated(6, [ + 'aktivBis' => '2022-02-03T00:00:00', + 'id' => 133, + ]); + } + + public function testItDoesntUpdateMembershipWhenNoIdGiven(): void + { + $this->expectException(NamiException::class); + Carbon::setTestNow(Carbon::parse('2022-02-03 03:00:00')); + app(MembershipFake::class)->failsDeleting(6, null); + app(MembershipFake::class)->updatesSuccessfully(6, null); + + $this->login()->deleteMembership(6, Membership::fromArray([ + 'id' => null, + 'subactivityId' => 3, + 'activityId' => 2, + 'groupId' => 1400, + 'startsAt' => Carbon::parse('2022-02-03 00:00:00'), + 'endsAt' => null, + ])); + } }