diff --git a/lib/GaletteObjectsLend/Controllers/Crud/ObjectsController.php b/lib/GaletteObjectsLend/Controllers/Crud/ObjectsController.php index 1177705..c0aeccc 100644 --- a/lib/GaletteObjectsLend/Controllers/Crud/ObjectsController.php +++ b/lib/GaletteObjectsLend/Controllers/Crud/ObjectsController.php @@ -778,7 +778,7 @@ public function doReturn(Request $request, Response $response, int $id): Respons $object = $service->getObject($id); try { - $service->giveBack($object, (int)($post['status'] ?? 0)); + $service->giveBack($object, (int)($post['status'] ?? 0), trim($post['comments'] ?? '')); } catch (LendException $e) { $this->flash->addMessage('error_detected', $e->getMessage()); return $response diff --git a/lib/GaletteObjectsLend/Controllers/MainController.php b/lib/GaletteObjectsLend/Controllers/MainController.php index 658ba2d..7dc69d3 100644 --- a/lib/GaletteObjectsLend/Controllers/MainController.php +++ b/lib/GaletteObjectsLend/Controllers/MainController.php @@ -45,7 +45,8 @@ public function preferences(Request $request, Response $response): Response $params = [ 'page_title' => _T('ObjectsLend preferences', 'objectslend'), - 'type_cotis_options' => $ctypes->getList(), + //a rent is not a membership fee + 'type_cotis_options' => $ctypes->getList(false), 'lendsprefs' => (new LendPreferences($this->preferences))->toArray(), 'sample_data' => !(new SampleData($this->zdb))->hasObjects() ]; @@ -75,6 +76,18 @@ public function storePreferences(Request $request, Response $response): Response $stored = true; $errors = []; + + //a membership fee would extend the membership, and needs an end date + $type_id = $post[LendPreferences::GENERATED_CONTRIBUTION_TYPE_ID] ?? null; + if ( + isset($post[LendPreferences::AUTO_GENERATE_CONTRIBUTION]) + && !isset((new ContributionsTypes($this->zdb))->getList(false)[(int)$type_id]) + ) { + $stored = false; + $errors[] = _T("Generated contributions must be of a donation type.", "objectslend"); + unset($post[LendPreferences::GENERATED_CONTRIBUTION_TYPE_ID]); + } + foreach (array_keys(LendPreferences::getSchema()) as $name) { if (isset($booleans[$name])) { $value = (int)isset($post[$name]); diff --git a/lib/GaletteObjectsLend/Entity/LendRent.php b/lib/GaletteObjectsLend/Entity/LendRent.php index 3f0dd6e..50c83ac 100644 --- a/lib/GaletteObjectsLend/Entity/LendRent.php +++ b/lib/GaletteObjectsLend/Entity/LendRent.php @@ -231,13 +231,13 @@ public function getComments(): string } /** - * Set comments + * Set comments, cut to the column size * * @param string $comments Comments */ public function setComments(string $comments): self { - $this->comments = $comments; + $this->comments = mb_substr($comments, 0, 200); return $this; } diff --git a/lib/GaletteObjectsLend/LendService.php b/lib/GaletteObjectsLend/LendService.php index 9ff36f5..f20a3a9 100644 --- a/lib/GaletteObjectsLend/LendService.php +++ b/lib/GaletteObjectsLend/LendService.php @@ -189,10 +189,11 @@ public function take( * * @param LendObject $object Object, loaded with getObject() * @param int $status_id In stock status + * @param string $comments Comment on the closed rent * * @throws LendException */ - public function giveBack(LendObject $object, int $status_id): LendRent + public function giveBack(LendObject $object, int $status_id, string $comments = ''): LendRent { if (!$this->canGiveBack($object)) { $this->refuse( @@ -214,7 +215,7 @@ public function giveBack(LendObject $object, int $status_id): LendRent } return $this->inTransaction( - fn() => $this->openRent($object, $status_id, null, '') + fn() => $this->openRent($object, $status_id, null, $comments) ); } @@ -378,6 +379,20 @@ private function storeContribution( float $amount, ?int $payment_type ): Contribution { + //a membership fee would extend the membership, and needs an end date + $type_id = $this->lendsprefs->getContributionTypeId(); + $ctype = new ContributionsTypes($this->zdb); + if (!$ctype->load($type_id) || $ctype->isExtension()) { + Analog::log( + 'Unable to generate contribution for object #' . $object->getId() + . ': contribution type #' . $type_id . ' is not a donation one.', + Analog::ERROR + ); + throw new LendException( + _T("Generated contributions must be of a donation type, check plugin preferences.", "objectslend") + ); + } + $info = str_replace( [ '{NAME}', @@ -402,7 +417,7 @@ private function storeContribution( $values = [ 'montant_cotis' => $amount, - ContributionsTypes::PK => $this->lendsprefs->getContributionTypeId(), + ContributionsTypes::PK => $type_id, 'date_enreg' => date("Y-m-d"), 'date_debut_cotis' => date("Y-m-d"), 'type_paiement_cotis' => $payment_type, diff --git a/tests/GaletteObjectsLend/Controllers/tests/units/MainController.php b/tests/GaletteObjectsLend/Controllers/tests/units/MainController.php index a9d26c1..c8c42e6 100644 --- a/tests/GaletteObjectsLend/Controllers/tests/units/MainController.php +++ b/tests/GaletteObjectsLend/Controllers/tests/units/MainController.php @@ -123,6 +123,37 @@ public function testStoreInvalidPreference(): void $this->flash_data = []; } + /** + * Generated contributions cannot be membership fees + */ + public function testStoreMembershipFeeContributionType(): void + { + $this->logSuperAdmin(); + $this->assertTrue($this->preferences->setValue(LendPreferences::GENERATED_CONTRIBUTION_TYPE_ID, 5, $this->login)); + + //only donation types are offered + $test_response = $this->app->handle($this->createRequest(route_name: 'objectslend_preferences')); + $body = (string)$test_response->getBody(); + $this->assertStringContainsString('data-value="5"', $body); + $this->assertStringNotContainsString('data-value="1"', $body); + + $request = $this->createRequest(route_name: 'store_objectlend_preferences', method: 'POST') + ->withParsedBody([ + LendPreferences::AUTO_GENERATE_CONTRIBUTION => '1', + LendPreferences::GENERATED_CONTRIBUTION_TYPE_ID => '1', + LendPreferences::THUMB_MAX_WIDTH => '210', + ]); + $test_response = $this->app->handle($request); + $this->assertSame(302, $test_response->getStatusCode()); + $this->expectFlashData(['error_detected' => ['Generated contributions must be of a donation type.']]); + + $this->preferences->load(); + $lendsprefs = new LendPreferences($this->preferences); + $this->assertSame(5, $lendsprefs->getContributionTypeId()); + //other values are stored + $this->assertSame(210, $lendsprefs->getThumbWidth()); + } + /** * Preferences are for admins only */ diff --git a/tests/GaletteObjectsLend/Controllers/tests/units/ObjectsController.php b/tests/GaletteObjectsLend/Controllers/tests/units/ObjectsController.php index b9695de..c0995e0 100644 --- a/tests/GaletteObjectsLend/Controllers/tests/units/ObjectsController.php +++ b/tests/GaletteObjectsLend/Controllers/tests/units/ObjectsController.php @@ -374,6 +374,27 @@ public function testMemberReturnOwnObject(): void $this->assertCount(2, $this->getRents()); } + /** + * Comment of the return form goes on the closed rent, cut to its column size + */ + public function testReturnComments(): void + { + $this->setPrefs(true); + $this->logSuperAdmin(); + $this->lendObject($this->getMemberOne()->id); + + $test_response = $this->app->handle($this->returnRequest(['comments' => ' Back, all good '])); + $this->assertSame(301, $test_response->getStatusCode()); + $closed = array_values(array_filter($this->getRents(), fn($rent) => $rent->getDateEnd() !== '')); + $this->assertCount(1, $closed); + $this->assertSame('Back, all good', $closed[0]->getComments()); + + $this->lendObject($this->getMemberOne()->id); + $this->app->handle($this->returnRequest(['comments' => str_repeat('é', 250)])); + $comments = array_map(fn($rent) => $rent->getComments(), $this->getRents()); + $this->assertContains(str_repeat('é', 200), $comments); + } + /** * Giving back requires an "in stock" status, and a lent object */ diff --git a/tests/GaletteObjectsLend/tests/units/LendService.php b/tests/GaletteObjectsLend/tests/units/LendService.php index 60e0ed8..3bae95c 100644 --- a/tests/GaletteObjectsLend/tests/units/LendService.php +++ b/tests/GaletteObjectsLend/tests/units/LendService.php @@ -183,6 +183,39 @@ public function testTakeRollsBackOnContributionError(): void $this->assertTrue($service->isAvailable($object)); } + /** + * Test nothing is stored when generated contribution would be a membership fee + */ + public function testTakeRefusesMembershipFeeContributionType(): void + { + $this->assertTrue($this->preferences->setValue(LendPreferences::GENERATED_CONTRIBUTION_TYPE_ID, 1, $this->login)); + $member = $this->getMemberOne(); + $this->logSuperAdmin(); + $service = $this->getService(); + + try { + $service->take( + $service->getObject($this->object_id), + $this->lent_status, + member_id: $member->id + ); + $this->fail('Take should have failed'); + } catch (LendException $e) { + $this->assertSame( + 'Generated contributions must be of a donation type, check plugin preferences.', + $e->getMessage() + ); + } + $this->expectLogEntry( + Analog::ERROR, + 'Unable to generate contribution for object #' . $this->object_id . ': contribution type #1 is not a donation one.' + ); + + $this->assertSame(0, $this->countContributions()); + $this->assertCount(0, (new \GaletteObjectsLend\Repository\Rents($this->zdb))->getForObject($this->object_id)); + $this->assertTrue($service->isAvailable($service->getObject($this->object_id))); + } + /** * Test status change refuses unknown and inactive statuses */