diff --git a/FEATURES/98009 b/FEATURES/98009 new file mode 100644 index 0000000000000000000000000000000000000000..54f6ecbdba06d2f192d9c76d448b8e0cf016a403 --- /dev/null +++ b/FEATURES/98009 @@ -0,0 +1,10 @@ + '98009' => + ['Label' => $this->_('Intégration des Types d\'abonnements avec les dates d\'abonnements en provenance de l\'étalon Nanook et dans les critères de filtre utilisateurs'), + 'Desc' => '', + 'Image' => '', + 'Video' => '', + 'Category' => '', + 'Right' => function($feature_description, $user) {return true;}, + 'Wiki' => '', + 'Test' => '', + 'Date' => '2023-01-06'], \ No newline at end of file diff --git a/VERSIONS_WIP/98009 b/VERSIONS_WIP/98009 new file mode 100644 index 0000000000000000000000000000000000000000..91f616f3eef389a91258e238f2df8e52b7b0371e --- /dev/null +++ b/VERSIONS_WIP/98009 @@ -0,0 +1 @@ + - fonctionnalité #98009 : Administration Utilisateurs : gestion des critères de tarifs présents dans l'étalon Nanook \ No newline at end of file diff --git a/cosmogramme/cosmozend/application/modules/cosmo/controllers/MembershipController.php b/cosmogramme/cosmozend/application/modules/cosmo/controllers/MembershipController.php new file mode 100644 index 0000000000000000000000000000000000000000..ed83ed8ae39cf61f8f526c7bb61ea83cd7edb229 --- /dev/null +++ b/cosmogramme/cosmozend/application/modules/cosmo/controllers/MembershipController.php @@ -0,0 +1,27 @@ +<?php +/** + * Copyright (c) 2012-2017, Agence Française Informatique (AFI). All rights reserved. + * + * BOKEH is free software; you can redistribute it and/or modify + * it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE as published by + * the Free Software Foundation. + * + * There are special exceptions to the terms and conditions of the AGPL as it + * is applied to this software (see README file). + * + * BOKEH is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU AFFERO GENERAL PUBLIC LICENSE for more details. + * + * You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE + * along with BOKEH; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + + +class Cosmo_MembershipController extends ZendAfi_Controller_Action { + public function getPlugins() :array { + return [ZendAfi_Controller_Plugin_ResourceDefinition_Membership::class]; + } +} diff --git a/cosmogramme/cosmozend/application/modules/cosmo/views/scripts/membership/index.phtml b/cosmogramme/cosmozend/application/modules/cosmo/views/scripts/membership/index.phtml new file mode 100644 index 0000000000000000000000000000000000000000..e55db27f575d0ff61962ae0e0e817dbf72a3da3a --- /dev/null +++ b/cosmogramme/cosmozend/application/modules/cosmo/views/scripts/membership/index.phtml @@ -0,0 +1,4 @@ +<?php +echo $this->tag('h1', $this->titre); + +echo $this->renderTable(new Class_TableDescription_CosmoMembership('membership'), $this->memberships); diff --git a/cosmogramme/cosmozend/tests/application/modules/cosmo/controllers/IntegrationControllerTest.php b/cosmogramme/cosmozend/tests/application/modules/cosmo/controllers/IntegrationControllerTest.php index 89338ca32a335fa7f4edcb10d3d00fa71d0d2162..7804d67d56b3f16d03c1d3e7814f011a2833dd74 100644 --- a/cosmogramme/cosmozend/tests/application/modules/cosmo/controllers/IntegrationControllerTest.php +++ b/cosmogramme/cosmozend/tests/application/modules/cosmo/controllers/IntegrationControllerTest.php @@ -217,6 +217,18 @@ abstract class Cosmo_IntegrationControllerGenerateActionTestCase extends CosmoCo '0|2|Bande dessinée|f', '0|3|Biographie|f'])) + ->touch('tarifs.txt') + ->filePutContents('tarifs.txt', + implode("\n", + [ + 'ID|LIBELLE|ACTIF', + '0|Tous les sites|1', + '21|Hem 30 €|1', + '22|Bibliothécaire 15 €|1', + '23|Hors Hem 45 €|1', + '24|Enfant seul Gratuit (ex 515)|1', + '25|Groupe|1', + '26|Vacancier 2 €|1'])) ->cd('/www/monbokeh') ; @@ -344,7 +356,7 @@ class Cosmo_IntegrationControllerGenerateActionNanookPostTest /** @test */ public function shouldNotHaveError() { - $this->assertNotXPath('//font[@color="red"]', $this->_response->getBody()); + $this->assertNotXPath('//font[@color="red"]'); } @@ -613,6 +625,7 @@ abstract class Cosmo_IntegrationControllerWaitingFilesTestCase extends CosmoCont ->touch('transferts/ccpl34/etalon/annexes.txt') ->touch('transferts/ccpl34/etalon/sections.txt') ->touch('transferts/ccpl34/etalon/emplacements.txt') + ->touch('transferts/ccpl34/etalon/tarifs.txt') ->touch('transferts/ccpl34/lunel/20190116220001_records_tot.mrc', diff --git a/cosmogramme/cosmozend/tests/application/modules/cosmo/controllers/MembershipControllerTest.php b/cosmogramme/cosmozend/tests/application/modules/cosmo/controllers/MembershipControllerTest.php new file mode 100644 index 0000000000000000000000000000000000000000..282011a1c07fa71532f1b82d8f7b06e2664df676 --- /dev/null +++ b/cosmogramme/cosmozend/tests/application/modules/cosmo/controllers/MembershipControllerTest.php @@ -0,0 +1,79 @@ +<?php +/** + * Copyright (c) 2012-2017, Agence Française Informatique (AFI). All rights reserved. + * + * BOKEH is free software; you can redistribute it and/or modify + * it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE as published by + * the Free Software Foundation. + * + * There are special exceptions to the terms and conditions of the AGPL as it + * is applied to this software (see README file). + * + * BOKEH is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU AFFERO GENERAL PUBLIC LICENSE for more details. + * + * You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE + * along with BOKEH; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + + +abstract class MembershipControllerTestCase extends CosmoControllerTestCase { + public function setUp() { + parent::setUp(); + + $this->fixture(Class_Membership::class, + ['id' => 1, + 'code' => 1, + 'libelle' => 'Abonnement Abonné Adulte Interne', + 'enabled' => 1]); + + $this->fixture(Class_Membership::class, + ['id' => 2, + 'code' => 2, + 'libelle' => 'Abonnement Abonné Jeune Interne', + 'enabled' => 0]); + } +} + + + + +class MembershipControllerIndexTest extends MembershipControllerTestCase { + public function setUp() { + parent::setUp(); + $this->dispatch('/cosmo/membership'); + } + + + /** @test */ + public function membershipPageTitleShouldContainsListeDesMemberships() { + $this->assertXPathContentContains('//h1', 'Parcourir les types d\'abonnement'); + } + + + /** @test */ + public function firstMembershipLineFirstColumnShouldContains1() { + $this->assertXPathContentContains('//table//tr[1]//td[1]', '1'); + } + + + /** @test */ + public function firstmembershipLineSecondColumnShouldContainsMembershipAbonneAdulteInterne() { + $this->assertXPathContentContains('//table//tr[1]//td[2]', 'Abonnement Abonné Adulte Interne'); + } + + + /** @test */ + public function firstmembershipLineThirdColumnShouldContains1() { + $this->assertXPathContentContains('//table//tr[1]//td[3]', '1'); + } + + + /** @test */ + public function secondMembershipLineSecondColumnShouldContainsAbonneJeuneInterne() { + $this->assertXPathContentContains('//table//tr[2]//td', 'Abonnement Abonné Jeune Interne'); + } +} diff --git a/cosmogramme/php/_menu.php b/cosmogramme/php/_menu.php index a64b70cb57f66500a59c2c942813ed66dfe400bc..2337aa82d19eb9c938b356599942d53aa2a6f64a 100644 --- a/cosmogramme/php/_menu.php +++ b/cosmogramme/php/_menu.php @@ -96,6 +96,7 @@ else ?> <div class="menu_section">Autorités et codifications</div> <?php + ligneMenu("Types d'abonnement","../cosmozend/cosmo/membership"); ligneMenu("Sections","../cosmozend/cosmo/section"); ligneMenu("Genres","../cosmozend/cosmo/genre"); ligneMenu("Emplacements", '../cosmozend/cosmo/emplacement'); diff --git a/cosmogramme/sql/patch/patch_447.php b/cosmogramme/sql/patch/patch_447.php new file mode 100644 index 0000000000000000000000000000000000000000..b5dfbde253279492a02cd7bf4d46b88f327e5e16 --- /dev/null +++ b/cosmogramme/sql/patch/patch_447.php @@ -0,0 +1,42 @@ +<?php + +(new Class_Migration_AbonnementsUtilisateurs())->run(); + +$adapter = Zend_Db_Table_Abstract::getDefaultAdapter(); + +try { + $adapter->query('CREATE TABLE if not exists `membership` ( ' + . '`id` int(11) unsigned not null auto_increment,' + . '`code` varchar(255) not null,' + . '`libelle` varchar(255) not null default \'\',' + . '`enabled` boolean default 0,' + . '`date_created` datetime not null default current_timestamp,' + . '`date_maj` datetime null default null,' + . 'primary key (`id`),' + . 'unique key (`code`),' + . 'key (`libelle`)' + . ') engine=MyISAM default charset=utf8'); +} +catch(Exception $e){ +} + +try{ + $adapter + ->query('CREATE TABLE if not exists `user_membership` ( ' + . '`id` int(11) unsigned not null auto_increment primary key,' + . '`user_id` int(11) unsigned not null DEFAULT 0,' + . '`membership_id` int(11) unsigned not null DEFAULT 0,' + . '`start_date` date not null,' + . '`end_date` date not null' + . ') engine=MyISAM default charset=utf8'); +} +catch(Exception $e){ +} + + +try { + $adapter->query('drop TABLE if exists `tarif`;'); + $adapter->query('drop TABLE if exists `user_tarif`;'); +} +catch(Exception $e){ +} diff --git a/cosmogramme/tests/php/classes/AbonneIntegrationTest.php b/cosmogramme/tests/php/classes/AbonneIntegrationTest.php index 28be431c49df41c40b0a92632810320692135ade..4f92d79e6f5170919b69a32686524515df2a96d9 100644 --- a/cosmogramme/tests/php/classes/AbonneIntegrationTest.php +++ b/cosmogramme/tests/php/classes/AbonneIntegrationTest.php @@ -34,7 +34,8 @@ abstract class AbonneIntegrationTestCase extends ModelTestCase { ['id' => 2, 'id_bib' => 2]); - $this->abon_config = new Class_Cosmogramme_Integration_Record_Patron($this->getIntegration()); + $this->abon_config = new Class_Cosmogramme_Integration_Record_Patron($this->getIntegration(), + fn($message) => $message); } public function getIntegration() { diff --git a/library/Class/Bib/PortalBorrowers.php b/library/Class/Bib/PortalBorrowers.php index 2d1c4672738565cbb4dddaa235c74d9e1ecfa593..0ea3c67c7855e26c07c5d0880bb2f859eb3d0cdd 100644 --- a/library/Class/Bib/PortalBorrowers.php +++ b/library/Class/Bib/PortalBorrowers.php @@ -23,8 +23,6 @@ class Class_Bib_PortalBorrowers { use Trait_Translator, Trait_TimeSource, Trait_GetterByAttributeName, Trait_Loggable; - const FR_DATE_FORMAT = 'd/m/Y'; - const SQL_DATE_FORMAT = 'Y-m-d'; const ACCEPT_TOKEN = 'oui'; const DENY_TOKEN = 'non'; @@ -298,7 +296,7 @@ class Class_Bib_PortalBorrowers { $date_fin = $this->getTimeSource()->asDateTime() ->modify('+' . $this->_subscriptionDelay(). ' days'); - $user->setDateFin($date_fin->format(static::SQL_DATE_FORMAT)); + $user->setDateFin($date_fin->format(Class_TimeSource::SQL_DATE_FORMAT)); if ($line[static::BIRTH_POS]) { $naissance = $this->_dateFrToSql($line[static::BIRTH_POS]); @@ -315,8 +313,8 @@ class Class_Bib_PortalBorrowers { protected function _dateFrToSql(string $date) : string { - return DateTime::createFromFormat(static::FR_DATE_FORMAT, $date) - ->format(static::SQL_DATE_FORMAT); + return DateTime::createFromFormat(Class_TimeSource::FR_DATE_FORMAT, $date) + ->format(Class_TimeSource::SQL_DATE_FORMAT); } @@ -341,7 +339,7 @@ class Class_Bib_PortalBorrowers { if ( ! trim($birthdate)) return $errors; - if ( ! $this->_isDateFormatValid($birthdate)) + if ( ! $this->_isDateFormatValid($birthdate, Class_TimeSource::FR_DATE_FORMAT)) $errors [] = $this->_('la colonne "Date de naissance (format jj/mm/aaaa)" doit être valide et au format jj/mm/aaaa.'); return $errors; @@ -365,12 +363,6 @@ class Class_Bib_PortalBorrowers { } - protected function _isDateFormatValid(string $date) : bool { - $d = DateTime::createFromFormat(static::FR_DATE_FORMAT, $date); - return $d && $d->format(static::FR_DATE_FORMAT) == $date; - } - - protected function _isInternalIdValid(string $id, array $errors) : array { if ( ! trim($id)) { $errors [] = $this->_('la colonne "ID Bokeh (ne pas modifier !)" NE DOIT PAS ÊTRE MODIFIÉE.'); @@ -443,7 +435,7 @@ class Class_Bib_PortalBorrowers { public function getUserBirthdate(Class_Users $user) : string { // guard against SQL default date value return (($date = $user->getNaissance()) && '0000-00-00' !== $date) - ? date(static::FR_DATE_FORMAT, strtotime($date)) + ? date(Class_TimeSource::FR_DATE_FORMAT, strtotime($date)) : ''; } diff --git a/library/Class/Cosmogramme/Generator.php b/library/Class/Cosmogramme/Generator.php index 484b1d4a27540c37c28b52b0467d6f86f57bf221..cab4f858498ae9a51c68531b15ed1cedb251729a 100644 --- a/library/Class/Cosmogramme/Generator.php +++ b/library/Class/Cosmogramme/Generator.php @@ -42,7 +42,8 @@ class Class_Cosmogramme_Generator { && $this->_generateSections() && $this->_generateLocations() && $this->_generateKinds() - && $this->_generateDewey(); + && $this->_generateDewey() + && $this->_generateMemberships(); $this->log('<br><h2>'. $this->_('Traitement terminé.') .'</h2>'); @@ -146,6 +147,12 @@ class Class_Cosmogramme_Generator { } + protected function _generateMemberships() :bool { + $memberships = $this->getLandingDirectory()->getMembershipsOf($this->_params['path_ftp']); + return (new Class_Cosmogramme_Generator_MembershipsTask($this, $this->_params))->run($memberships); + } + + protected function _generateDewey() { $this->logTitle($this->_('7 - Création des classes Dewey')); if ($this->isUpdate()) { @@ -290,4 +297,4 @@ class Class_Cosmogramme_GeneratorProfilesPergameValidator [102, 'Prêts Pergame', Class_IntProfilDonnees::FT_LOANS], [103, 'Réservations Pergame', Class_IntProfilDonnees::FT_HOLDS]]; } -} \ No newline at end of file +} diff --git a/library/Class/Cosmogramme/Generator/AbstractTask.php b/library/Class/Cosmogramme/Generator/AbstractTask.php index ca88a3596497dc07ab3117a36e36018e61e35782..6a46ba252317efb22ec6bdba67bbd102375171ae 100644 --- a/library/Class/Cosmogramme/Generator/AbstractTask.php +++ b/library/Class/Cosmogramme/Generator/AbstractTask.php @@ -47,7 +47,7 @@ abstract class Class_Cosmogramme_Generator_AbstractTask { } - public function run($datas) { + public function run($datas) :bool { if (!$datas) { $this->logError($this->_('Étalon des %s vide', $this->_name)); return false; @@ -62,7 +62,7 @@ abstract class Class_Cosmogramme_Generator_AbstractTask { foreach($datas as $data) $html .= $this->_runOne($data); - $this->log('<div class="liste"><table class="blank">' . $html . '</table></div>'); + $this->log('<div class="liste"><table class="blank"><caption>'.$this->_name.'</caption>'. $html . '</table></div>'); $this->_removeDeleted(); return true; @@ -89,7 +89,7 @@ abstract class Class_Cosmogramme_Generator_AbstractTask { } - protected function _getOrCreate($elems) { + protected function _getOrCreate(array $elems) : object { $model_class = $this->_model_class; $label = $this->getLabel($elems); $code = $this->getCode($elems); @@ -119,12 +119,12 @@ abstract class Class_Cosmogramme_Generator_AbstractTask { } - protected function getLabel($elems) { + protected function getLabel(array $elems) :string { return trim($elems[1]); } - protected function getCode($elems) { + protected function getCode(array $elems) :string { return strtolower($elems[0]); } @@ -217,7 +217,7 @@ abstract class Class_Cosmogramme_Generator_AbstractTask { } - protected function _prepare($datas) { + protected function _prepare(array $datas) :array { return $datas; } @@ -237,4 +237,4 @@ abstract class Class_Cosmogramme_Generator_AbstractTask { ? static::$_db_adapter : Zend_Db_Table::getDefaultAdapter(); } -} \ No newline at end of file +} diff --git a/library/Class/Cosmogramme/Generator/BranchesTask.php b/library/Class/Cosmogramme/Generator/BranchesTask.php index 44863ef2d57f141d540a97976f5ae393c94560ce..1ba3733b56c785ca54e925fff0a55ce036dd506b 100644 --- a/library/Class/Cosmogramme/Generator/BranchesTask.php +++ b/library/Class/Cosmogramme/Generator/BranchesTask.php @@ -29,7 +29,7 @@ class Class_Cosmogramme_Generator_BranchesTask $_table = 'codif_annexe', $_model_class = 'Class_CodifAnnexe'; - protected function _getOrCreate($elems) { + protected function _getOrCreate(array $elems) :object { if (!$model = Class_CodifAnnexe::findFirstBy(['id_origine' => $elems[0]])) $model = Class_CodifAnnexe::newInstance(['id_bib' => $elems[0], 'id_origine' => $elems[0], @@ -39,7 +39,7 @@ class Class_Cosmogramme_Generator_BranchesTask } - protected function getCode($elems) { + protected function getCode(array $elems) :string { return $this->_('Site n° %s', $elems[0]); } @@ -57,4 +57,4 @@ class Class_Cosmogramme_Generator_BranchesTask protected function getItemValueFor($model) { return $model->getCode(); } -} \ No newline at end of file +} diff --git a/library/Class/Cosmogramme/Generator/KindsTask.php b/library/Class/Cosmogramme/Generator/KindsTask.php index 78c23611f203aab6fbc1aeb0a973e4f0367d29fa..05cb194c1d3449b09c9551ad883a6cd04c1facac 100644 --- a/library/Class/Cosmogramme/Generator/KindsTask.php +++ b/library/Class/Cosmogramme/Generator/KindsTask.php @@ -32,12 +32,12 @@ class Class_Cosmogramme_Generator_KindsTask extends Class_Cosmogramme_Generator_ } - protected function getLabel($elems) { + protected function getLabel(array $elems):string { return trim($elems[2]); } - protected function getCode($elems) { + protected function getCode(array $elems):string { return trim($elems[1]); } diff --git a/library/Class/Cosmogramme/Generator/LibrariesTask.php b/library/Class/Cosmogramme/Generator/LibrariesTask.php index 6fc4e48165b853490acb8ba8c0765835bfbae5f5..6274f0ba4e197b4a5945b1434370b94a17d248a0 100644 --- a/library/Class/Cosmogramme/Generator/LibrariesTask.php +++ b/library/Class/Cosmogramme/Generator/LibrariesTask.php @@ -30,7 +30,7 @@ class Class_Cosmogramme_Generator_LibrariesTask extends Class_Cosmogramme_Genera } - protected function _prepare($libraries) { + protected function _prepare(array $libraries) : array { $this->_disableDeletedLibraries($libraries); return $libraries; } @@ -46,7 +46,7 @@ class Class_Cosmogramme_Generator_LibrariesTask extends Class_Cosmogramme_Genera } - protected function _getOrCreate($elems) { + protected function _getOrCreate(array $elems) :object { if (!$bib = Class_Cosmogramme_Generator_FixedIdBib::findFirstBy(['id_site' => $elems[0]])) $bib = Class_Cosmogramme_Generator_FixedIdBib::newInstance(['ville' => $this->_params['path_ftp']]); @@ -115,4 +115,4 @@ class Class_Cosmogramme_Generator_LibrariesTask extends Class_Cosmogramme_Genera protected function _removeDeleted() { } -} \ No newline at end of file +} diff --git a/library/Class/Cosmogramme/Generator/MembershipsTask.php b/library/Class/Cosmogramme/Generator/MembershipsTask.php new file mode 100644 index 0000000000000000000000000000000000000000..9c9d6b475ee96539ac0286bb0fbc8d7b66f58e47 --- /dev/null +++ b/library/Class/Cosmogramme/Generator/MembershipsTask.php @@ -0,0 +1,68 @@ +<?php +/** + * Copyright (c) 2012-2014, Agence Française Informatique (AFI). All rights reserved. + * + * BOKEH is free software; you can redistribute it and/or modify + * it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE as published by + * the Free Software Foundation. + * + * There are special exceptions to the terms and conditions of the AGPL as it + * is applied to this software (see README file). + * + * BOKEH is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU AFFERO GENERAL PUBLIC LICENSE for more details. + * + * You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE + * along with BOKEH; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +class Class_Cosmogramme_Generator_MembershipsTask extends Class_Cosmogramme_Generator_AbstractTask { + protected + $_index = 8, + $_name = 'memberships', + $_table = 'membership', + $_model_class = Class_Membership::class; + + protected function _prepare(array $datas) :array{ + array_shift($datas); + return $datas; + } + + + protected function getCode(array $elems) :string { + return trim($elems[0] ?? ''); + } + + + protected function getLabel(array $elems) : string { + return trim($elems[1] ?? ''); + } + + + protected function getEnabled(array $elems) :string { + return trim($elems[2] ?? 0); + } + + + protected function _getOrCreate(array $elems):object { + $label = $this->getLabel($elems); + $code = $this->getCode($elems); + + $membership = Class_Membership::findOrCreate($code, $label); + + $membership + ->setEnabled((bool)$this->getEnabled($elems)) + ->setDateMaj($this->_date_time); + + return $membership; + } + + + protected function _removeDeleted() { + $this + ->_directQuery('delete from ' . $this->_table . ' where date(date_maj) != "' . $this->_date . '"'); + } +} diff --git a/library/Class/Cosmogramme/Generator/PlannedIntegrationsTask.php b/library/Class/Cosmogramme/Generator/PlannedIntegrationsTask.php index e700d9567c7a9ec3f6da3ff562095f819f641b37..970f83112e49b409f6830db738e1d231a9129b43 100644 --- a/library/Class/Cosmogramme/Generator/PlannedIntegrationsTask.php +++ b/library/Class/Cosmogramme/Generator/PlannedIntegrationsTask.php @@ -34,7 +34,7 @@ class Class_Cosmogramme_Generator_PlannedIntegrationsTask } - protected function _getOrCreate($elems) { + protected function _getOrCreate(array $elems):object { $id_bib = $elems[0]; Class_IntMajAuto::deleteBy(['id_bib' => $id_bib]); @@ -244,4 +244,4 @@ class Class_Cosmogramme_GeneratorPlannedPergame extends Class_Cosmogramme_Genera $_records_profile = 100, $_users_profile = 101, $_holds = true; -} \ No newline at end of file +} diff --git a/library/Class/Cosmogramme/Integration/PhasePatrons.php b/library/Class/Cosmogramme/Integration/PhasePatrons.php index 8948ad76b923735495130ba2d6cce7f00ee563ee..7f566bd983f69ae8207265693cd5dddb13a9bd26 100644 --- a/library/Class/Cosmogramme/Integration/PhasePatrons.php +++ b/library/Class/Cosmogramme/Integration/PhasePatrons.php @@ -38,7 +38,8 @@ class Class_Cosmogramme_Integration_PhasePatrons extends Class_Cosmogramme_Integ public function importPatronRecord($data, $integration) { - $patron = new Class_Cosmogramme_Integration_Record_Patron($integration); + $patron = new Class_Cosmogramme_Integration_Record_Patron($integration, + fn($message) => $this->_logInfo($message)); return $patron->import($integration->isFormatXml() ? $data : $this->mapRecordColumns($integration, $data), diff --git a/library/Class/Cosmogramme/Integration/Record/Patron.php b/library/Class/Cosmogramme/Integration/Record/Patron.php index ec5d2449a05e92230fbcff32603e74c5bb440afb..dc2e30eeccb2e3f00049eaae3a0fbc19c4abcb18 100644 --- a/library/Class/Cosmogramme/Integration/Record/Patron.php +++ b/library/Class/Cosmogramme/Integration/Record/Patron.php @@ -21,13 +21,17 @@ class Class_Cosmogramme_Integration_Record_Patron { + use Trait_TimeSource; + protected $_integration, $_champs, + $_log_callback, $_known_fields; - public function __construct($integration) { + public function __construct($integration, Closure $log_callback) { $this->_integration = $integration; + $this->_log_callback = $log_callback; $this->_known_fields = new Class_IntProfilDonnees_PatronFields; } @@ -141,12 +145,20 @@ class Class_Cosmogramme_Integration_Record_Patron { protected function saveOrUpdateInDB($data){ + $subscription = ''; + if (isset($data[Class_IntProfilDonnees_PatronFields::ABONNEMENTS])) { + $subscription = $data[Class_IntProfilDonnees_PatronFields::ABONNEMENTS]; + unset($data[Class_IntProfilDonnees_PatronFields::ABONNEMENTS]); + } $new_user = Class_Users::newInstance($data); $finder = new Class_User_DoubleFinder($new_user); $user = $finder->find() ? $finder->getDouble() : $new_user; + if ($subscription) + $data = $this->_prepareUserMemberships($subscription, $data, $user); + $user ->updateAttributes($data) ->setStatut(0) @@ -156,4 +168,50 @@ class Class_Cosmogramme_Integration_Record_Patron { return $this; } + + + protected function _prepareUserMemberships(string $subscription,array $data, Class_Users $user) : array { + + $data[Class_IntProfilDonnees_PatronFields::USER_MEMBERSHIPS] = $this->_decodeDataAbonnements($subscription, $user); + + return $data; + } + + + protected function _decodeDataAbonnements(string $data, Class_Users $user) :array { + $array_memberships = explode(';',$data); + $user_memberships=[]; + + foreach (array_chunk($array_memberships,3) as $user_membership_as_array) + if ($user_membership_decoded = $this->_decodeUserMembership($user_membership_as_array, $user)) + $user_memberships[] = $user_membership_decoded; + + return $user_memberships; + } + + + protected function _decodeUserMembership(array $user_membership_array, Class_Users $user) : ?Class_User_Membership { + $log_callback = $this->_log_callback; + + if (!$membership = Class_Membership::findFirstBy(['code' => $membership_id = array_shift($user_membership_array)])){ + $log_callback('membership '.$membership_id.' introuvable dans la table Membership'); + return null; + } + + if (!$this->_isDateFormatValid($date_debut = array_shift($user_membership_array), Class_TimeSource::SQL_DATE_FORMAT)){ + $log_callback('date de début '. $date_debut .' invalide pour le membership '.$membership_id); + return null; + } + + if (!$this->_isDateFormatValid($date_fin = array_shift($user_membership_array), Class_TimeSource::SQL_DATE_FORMAT)){ + $log_callback('date de fin '. $date_fin .' invalide pour le membership '.$membership_id); + return null; + } + + return Class_User_Membership::findOrCreate( $user, + $membership, + $date_debut, + $date_fin + ); + } } diff --git a/library/Class/Cosmogramme/LandingDirectory.php b/library/Class/Cosmogramme/LandingDirectory.php index c60e0da9dcd45cb3bac8340011abafa3333235f9..a4caa2e66df4b2aa3cb2c0c10492a51945a32ff0 100644 --- a/library/Class/Cosmogramme/LandingDirectory.php +++ b/library/Class/Cosmogramme/LandingDirectory.php @@ -33,7 +33,8 @@ class Class_Cosmogramme_LandingDirectory { $_required_files = ['libraries' => 'annexes.txt', 'kinds' => 'genres.txt', 'sections' => 'sections.txt', - 'locations' => 'emplacements.txt']; + 'locations' => 'emplacements.txt', + 'tarifs' => 'tarifs.txt']; public function __construct() { @@ -123,26 +124,31 @@ class Class_Cosmogramme_LandingDirectory { } - public function getLibrariesOf($subdir) { + public function getLibrariesOf(string $subdir) :array { return $this->getFileNamed('libraries', $subdir); } - public function getSectionsOf($subdir) { + public function getSectionsOf(string $subdir) :array { return $this->getFileNamed('sections', $subdir); } - public function getLocationsOf($subdir) { + public function getLocationsOf(string $subdir) :array { return $this->getFileNamed('locations', $subdir); } - public function getKindsOf($subdir) { + public function getKindsOf(string $subdir) :array { return $this->getFileNamed('kinds', $subdir); } + public function getMembershipsOf(string $subdir) :array { + return $this->getFileNamed('tarifs', $subdir); + } + + protected function getFileNamed($name, $subdir) { $file = $this->_getStandardFilePath($subdir, $this->_required_files[$name]); return $this->getFileSystem()->fileGetContentAsArray($file); diff --git a/library/Class/IntMajAuto.php b/library/Class/IntMajAuto.php index 37192eb385911d04f82bb75360722aedbf836ae9..20cc33bbe73a10aa21d1872c3d0c3277eeac93c7 100644 --- a/library/Class/IntMajAuto.php +++ b/library/Class/IntMajAuto.php @@ -133,4 +133,15 @@ class Class_IntMajAuto extends Storm_Model_Abstract { ? Class_IntProfilDonnees_OaiFormats::metadataFormatFor($this) : ''; } + + + public static function getPatronConfigurations() { + return array_unique((new Storm_Collection(Class_IntMajAuto::findAllBy([]))) + ->select( fn($maj_auto) + => $maj_auto->getIntBib()->isNanook() + && (Class_IntProfilDonnees::FT_PATRONS == $maj_auto->getProfilDonnees()->getTypeFichier()) + ) + ->collect(fn($maj_auto) => $maj_auto->getProfilDonnees()) + ->getArrayCopy()); + } } diff --git a/library/Class/IntProfilDonnees.php b/library/Class/IntProfilDonnees.php index de194ff6d3773db3abf8093c9d5245cb57ad5c03..e5ac320ac45ebb0c088dadd2d3eacc96cafde34d 100644 --- a/library/Class/IntProfilDonnees.php +++ b/library/Class/IntProfilDonnees.php @@ -1417,4 +1417,12 @@ class Class_IntProfilDonnees extends Storm_Model_Abstract { public function isAsciiDosEncoded() { return static::ENCODING_ASCII_DOS === $this->getAccents(); } + + + public function getAttributsAsArray() :array { + $a = unserialize($this->getAttributs()); + if (!is_array($a)) + return []; + return $a; + } } diff --git a/library/Class/IntProfilDonnees/PatronFields.php b/library/Class/IntProfilDonnees/PatronFields.php index e52a2a101c4e8469dd6c11555986ce567c844b81..1b368c4bd951ef8a9b981a5eaa08283f8f7cfabc 100644 --- a/library/Class/IntProfilDonnees/PatronFields.php +++ b/library/Class/IntProfilDonnees/PatronFields.php @@ -36,6 +36,8 @@ class Class_IntProfilDonnees_PatronFields { ID_IN_ILS = 'ID_SIGB', CARD_NUMBER = 'NUM_CARTE', LIBRARY_CODE = 'LIBRARY_CODE', + ABONNEMENTS = 'ABONNEMENTS', + USER_MEMBERSHIPS = 'USER_MEMBERSHIPS', IGNORE = 'NULL'; public function options() { @@ -51,6 +53,7 @@ class Class_IntProfilDonnees_PatronFields { static::ID_IN_ILS => $this->_('Identifiant interne dans le sigb'), static::CARD_NUMBER => $this->_('Numéro de carte (si différent id abonné)'), static::LIBRARY_CODE => $this->_('Code de la bibliothèque / annexe de rattachement'), + static::ABONNEMENTS => $this->_('Liste des abonnements souscrits par l\'utilisateur'), static::IGNORE => $this->_('ignorer ce champ')]; } diff --git a/library/Class/Membership.php b/library/Class/Membership.php new file mode 100644 index 0000000000000000000000000000000000000000..f4c435f84b5d3cc7e53c43b5abcf5a60bd050181 --- /dev/null +++ b/library/Class/Membership.php @@ -0,0 +1,71 @@ +<?php +/** + * Copyright (c) 2012-2022, Agence Française Informatique (AFI). All rights reserved. + * + * BOKEH is free software; you can redistribute it and/or modify + * it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE as published by + * the Free Software Foundation. + * + * There are special exceptions to the terms and conditions of the AGPL as it + * is applied to this software (see README file). + * + * BOKEH is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU AFFERO GENERAL PUBLIC LICENSE for more details. + * + * You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE + * along with BOKEH; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + + +class MembershipLoader extends Storm_Model_Loader { + protected + $_used_memberships_cache; + + public function findOrCreate(string $code, + string $libelle) : Class_Membership { + $params = ['code' => $code ?? 0]; + if ($libelle) + $params['libelle'] = $libelle; + + return Class_Membership::findFirstBy($params) ?? Class_Membership::newInstance($params); + } + + + public function getMultiOptions() :array{ + $options = []; + if (!$memberships = Class_Membership::findAllBy(['order' => 'libelle'])) + return []; + + foreach ($memberships as $type_abonnement) + $options[$type_abonnement->getId()] = $type_abonnement->getLibelle(); + + return $options; + } +} + + + + +class Class_Membership extends Storm_Model_Abstract { + protected + $_table_name = 'membership', + $_loader_class = 'MembershipLoader', + + $_has_many =[ + 'user_memberships' => ['model' => Class_User_Membership::class, + 'role' => 'membership', + 'dependents' => 'delete'], + + 'users' => ['through' => 'user_memberships'], + ], + + + $_default_attribute_values = ['id' => 0, + 'code' => '', + 'libelle' => '', + 'enabled' => 0, + 'date_maj' => '']; +} diff --git a/library/Class/Migration/AbonnementsUtilisateurs.php b/library/Class/Migration/AbonnementsUtilisateurs.php new file mode 100644 index 0000000000000000000000000000000000000000..ae2f3715fc200d214d9bd9c7575e8d771fcb3f1d --- /dev/null +++ b/library/Class/Migration/AbonnementsUtilisateurs.php @@ -0,0 +1,55 @@ +<?php +/** + * Copyright (c) 2012-2022, Agence Française Informatique (AFI). All rights reserved. + * + * BOKEH is free software; you can redistribute it and/or modify + * it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE as published by + * the Free Software Foundation. + * + * There are special exceptions to the terms and conditions of the AGPL as it + * is applied to this software (see README file). + * + * BOKEH is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU AFFERO GENERAL PUBLIC LICENSE for more details. + * + * You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE + * along with BOKEH; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + + +class Class_Migration_AbonnementsUtilisateurs { + public function run() :string { + if (!Class_IntBib::isSingleNanook()) + return ''; + + $count=0; + foreach (Class_IntMajAuto::getPatronConfigurations() as $configuration){ + $this->_processAttributs($configuration); + $count++; + } + return $count. " configurations modifiées"; + } + + protected function _processAttributs($configuration){ + $attributs = unserialize($configuration->getAttributs()); + + $edited_attr = array_map(function($attribute){ + return (is_array($attribute) && isset($attribute['champs'])) + ? $this->_addAbonnement($attribute) + : $attribute; + }, + $attributs); + $configuration->setAttributs($edited_attr); + $configuration->save(); + } + + protected function _addAbonnement($attribute){ + if (false === strpos($attribute['champs'], ";ABONNEMENTS" )) + $attribute['champs'] .= ";ABONNEMENTS" ; + return $attribute; + } + +} diff --git a/library/Class/RendezVous/SearchCriteria/Location.php b/library/Class/RendezVous/SearchCriteria/Location.php index 50036b0aef53f417b19650bb41bba940d62b200f..f94f7adc1cba71251107981c20eceeee6735dafc 100644 --- a/library/Class/RendezVous/SearchCriteria/Location.php +++ b/library/Class/RendezVous/SearchCriteria/Location.php @@ -37,15 +37,16 @@ class Class_RendezVous_SearchCriteria_Location extends Class_SearchCriteria_Abst } - public function acceptSearchVisitor($visitor) { + public function acceptSearchVisitor($visitor) :Class_SearchCriteria_Abstract { if (!$this->_element->isValid($this->_value)) - return; + return $this; if (static::NONE == $this->_value) { $visitor->addWhereParam('location_id is null or location_id=0'); - return; + return $this; } parent::acceptSearchVisitor($visitor); + return $this; } } diff --git a/library/Class/SearchCriteria.php b/library/Class/SearchCriteria.php index 01f9915ba840574ac0968d10b029057088e9eb45..52d0b398285ed33e49381e40b23cfdfe1f675b0c 100644 --- a/library/Class/SearchCriteria.php +++ b/library/Class/SearchCriteria.php @@ -20,7 +20,7 @@ */ -abstract class Class_SearchCriteria { +abstract class Class_SearchCriteria { use Trait_Translator; const PAGE_NO_LIMIT = -1; @@ -198,7 +198,7 @@ abstract class Class_SearchCriteria { } - public function modelMatch($model) { + public function modelMatch($model) :bool { return (new Storm_Collection($this->_criteria)) ->detect(function($each) use($model) { diff --git a/library/Class/SearchCriteria/Abstract.php b/library/Class/SearchCriteria/Abstract.php index dd5a69c2630ba8ed34503cdf1c8f23ce2323cb00..e399644ca2d33db86fb8b89d46748512d3aa0800 100644 --- a/library/Class/SearchCriteria/Abstract.php +++ b/library/Class/SearchCriteria/Abstract.php @@ -65,11 +65,12 @@ abstract class Class_SearchCriteria_Abstract { } - public function acceptSearchVisitor($visitor) { + public function acceptSearchVisitor($visitor) :Class_SearchCriteria_Abstract { if ($this->_isAllValues()) - return; + return $this; $visitor->addParam($this->_name, $this->_value); + return $this; } @@ -77,14 +78,14 @@ abstract class Class_SearchCriteria_Abstract { } - public function modelMatch($model) { + public function modelMatch($model) :bool { return $this->_isAllValues() ? true : $model->callGetterByAttributeName($this->_name) == $this->_value; } - public function shouldFilter($search_criteria) { + public function shouldFilter($search_criteria) :bool{ return true; } diff --git a/library/Class/SearchCriteria/CustomField.php b/library/Class/SearchCriteria/CustomField.php index 2b8e0baeb698fe0dfaaa6c2a701e4c13b64905d8..3f912d915d737ba42fe2a61fa7556742cbb201e7 100644 --- a/library/Class/SearchCriteria/CustomField.php +++ b/library/Class/SearchCriteria/CustomField.php @@ -73,19 +73,22 @@ abstract class Class_SearchCriteria_CustomField extends Class_SearchCriteria_Abs } - public function acceptSearchVisitor($visitor) { + public function acceptSearchVisitor($visitor) :Class_SearchCriteria_Abstract { if (!$this->_shouldSearch()) - return; + return $this; $params = array_merge($this->_findAllByValueParams(), ['custom_field_id' => $this->_field->getId()]); $values = new Storm_Model_Collection(Class_CustomField_Value::findAllBy($params)); - if (!$values->isEmpty()) - return $visitor->addWhereParam('id in (' . implode(',', $values->collect('model_id')->getArrayCopy()) . ')'); + if (!$values->isEmpty()){ + $visitor->addWhereParam('id in (' . implode(',', $values->collect('model_id')->getArrayCopy()) . ')'); + return $this; + } $visitor->hasNoResult(); + return $this; } diff --git a/library/Class/SearchCriteria/CustomField/DateRange.php b/library/Class/SearchCriteria/CustomField/DateRange.php index 85f6ff9282c9bcebf925c9bbf13ba1687ecfd906..18e19a555f242f13e3b7b62b8b831ad6a49710c4 100644 --- a/library/Class/SearchCriteria/CustomField/DateRange.php +++ b/library/Class/SearchCriteria/CustomField/DateRange.php @@ -55,7 +55,7 @@ class Class_SearchCriteria_CustomField_DateRange extends Class_SearchCriteria_Cu - public function addWhereParam($param) { + public function addWhereParam($param) : self{ $this->_where_params[] = str_replace($this->_name, static::CAST_VALUE_TO_DATE, $param); return $this; } diff --git a/library/Class/SearchCriteria/DateRange.php b/library/Class/SearchCriteria/DateRange.php index 703e3f71139ada248ffba33be1383d0e8730389c..907e507ba41fd0b5621d33a5593f91e800db3105 100644 --- a/library/Class/SearchCriteria/DateRange.php +++ b/library/Class/SearchCriteria/DateRange.php @@ -32,12 +32,12 @@ class Class_SearchCriteria_DateRange extends Class_SearchCriteria_Range { } - public function isValidDate($value) { + public function isValidDate($value) :bool { return (new ZendAfi_Validate_DateFormat())->isValid($value); } - public function modelMatch($model) { + public function modelMatch($model) :bool { if ($this->_isAllValues()) return true; @@ -59,7 +59,7 @@ class Class_SearchCriteria_DateRange extends Class_SearchCriteria_Range { - public function acceptSearchVisitor($visitor) { + public function acceptSearchVisitor($visitor) :Class_SearchCriteria_Abstract { if ($this->_value_start) $visitor->addWhereParam(sprintf('left(%s, 10) >= "%s"', $this->_name, @@ -69,12 +69,13 @@ class Class_SearchCriteria_DateRange extends Class_SearchCriteria_Range { $visitor->addWhereParam(sprintf('left(%s, 10) <= "%s"', $this->_name, $this->_sqlFormat($this->_value_end))); + return $this; } - protected function _filterValue($value) { + protected function _filterValue($value) { if ($value === null || $value === '') return $value; diff --git a/library/Class/SearchCriteria/MultiCheckbox.php b/library/Class/SearchCriteria/MultiCheckbox.php index 2c2d28f4bb55f4c624de7f1f15f7d9e0665a0a9d..847094836407679672dbfec80bbc11a9879b94f9 100644 --- a/library/Class/SearchCriteria/MultiCheckbox.php +++ b/library/Class/SearchCriteria/MultiCheckbox.php @@ -26,11 +26,12 @@ class Class_SearchCriteria_MultiCheckbox extends Class_SearchCriteria_Abstract { protected $_value = Class_SearchCriteria_Abstract::ALL_VALUES; - public function acceptSearchVisitor($visitor) { + public function acceptSearchVisitor($visitor) :Class_SearchCriteria_Abstract { if (!$this->_value || $this->_isAllValues()) - return; + return $this; - return $visitor->addWhereParam($this->_matchValuesInField( $this->_name, $this->_value)); + $visitor->addWhereParam($this->_matchValuesInField( $this->_name, $this->_value)); + return $this; } @@ -66,18 +67,12 @@ class Class_SearchCriteria_MultiCheckbox extends Class_SearchCriteria_Abstract { } - protected function _getCheckboxName() { - return $this->_checkbox_name - ? $this->_checkbox_name - : $this->_name ; - } - public function buildElement() { return new ZendAfi_Form_Element_CochesSuggestion($this->getName(), ['label' => $this->_getLabel(), 'value' => $this->_value, 'name' => $this->getName(), - 'rubrique' => $this->_getCheckboxName()]); + 'rubrique' => $this->_name]); } } diff --git a/library/Class/SearchCriteria/NumRange.php b/library/Class/SearchCriteria/NumRange.php index f7973f58bf09951fc3ba6d34a16a418b323a442a..66dd83c618fcbfedff505a9d2b39e2303661895b 100644 --- a/library/Class/SearchCriteria/NumRange.php +++ b/library/Class/SearchCriteria/NumRange.php @@ -57,7 +57,7 @@ class Class_SearchCriteria_NumRange extends Class_SearchCriteria_Range { } - public function modelMatch($model) { + public function modelMatch($model) :bool { if ($this->_isAllValues()) return true; diff --git a/library/Class/SearchCriteria/Order.php b/library/Class/SearchCriteria/Order.php index c6e125f8be05373c450f059d7740c0c097597d02..d4930a9c42f630a5dbd74bee0b170cbe468d7ff7 100644 --- a/library/Class/SearchCriteria/Order.php +++ b/library/Class/SearchCriteria/Order.php @@ -31,17 +31,18 @@ class Class_SearchCriteria_Order extends Class_SearchCriteria_Abstract { } - public function acceptSearchVisitor($visitor) { + public function acceptSearchVisitor($visitor) :Class_SearchCriteria_Abstract { if (!$this->_value) - return; + return $this; $visitor->addParam('order', false !== strpos($this->_value, ',') ? explode(',', $this->_value) : $this->_value); + return $this; } - public function modelMatch($model) { + public function modelMatch($model) :bool { return true; } } diff --git a/library/Class/SearchCriteria/Range.php b/library/Class/SearchCriteria/Range.php index e256f7ab46215b5d4e13aa0339bd83f421214e0a..6b74f9e5ff6f0bf486e787abd5aba5d4fe1fc1b0 100644 --- a/library/Class/SearchCriteria/Range.php +++ b/library/Class/SearchCriteria/Range.php @@ -80,12 +80,13 @@ class Class_SearchCriteria_Range extends Class_SearchCriteria_Abstract { } - public function acceptSearchVisitor($visitor) { + public function acceptSearchVisitor($visitor) :Class_SearchCriteria_Abstract { if ($this->_value_start) $visitor->addWhereParam($this->_name . ' >= "' . $this->_sqlFormat($this->_value_start) . '"'); if ($this->_value_end) $visitor->addWhereParam($this->_name . ' <= "' . $this->_sqlFormat($this->_value_end) . '"'); + return $this; } diff --git a/library/Class/SearchCriteria/SelectYesNo.php b/library/Class/SearchCriteria/SelectYesNo.php index 21ea90a5fb7a4d8d9e77fdd012adb06e58a01100..25a940b8b659f8727a4515f3524768a04a2480db 100644 --- a/library/Class/SearchCriteria/SelectYesNo.php +++ b/library/Class/SearchCriteria/SelectYesNo.php @@ -34,16 +34,19 @@ class Class_SearchCriteria_SelectYesNo extends Class_SearchCriteria_Select { } - public function acceptSearchVisitor($visitor) { + public function acceptSearchVisitor($visitor) :Class_SearchCriteria_Abstract { if ($this->_isAllValues()) - return; + return $this; - if (!$ids = call_user_func([$this->_linked_model, 'findAllUserIds'])) - return $this->_reactToNoLinkedData($visitor); + if (!$ids = call_user_func([$this->_linked_model, 'findAllUserIds'])){ + $this->_reactToNoLinkedData($visitor); + return $this; + } $ids = implode(',', $ids); $operator = (static::NO == $this->_value) ? 'not in' : 'in'; $visitor->addWhereParam('id_user ' . $operator . ' (' . $ids . ')'); + return $this; } @@ -54,7 +57,7 @@ class Class_SearchCriteria_SelectYesNo extends Class_SearchCriteria_Select { } - public function modelMatch($model) { + public function modelMatch($model) :bool { if ($this->_isAllValues()) return true; diff --git a/library/Class/SearchCriteria/TextLike.php b/library/Class/SearchCriteria/TextLike.php index 0a0209ec48ad257ff891592757f8cecb4be8c12c..9ed264a6adca81ec5366b74003690c87b0044576 100644 --- a/library/Class/SearchCriteria/TextLike.php +++ b/library/Class/SearchCriteria/TextLike.php @@ -35,10 +35,11 @@ class Class_SearchCriteria_TextLike extends Class_SearchCriteria_Abstract { } - public function acceptSearchVisitor($visitor) { + public function acceptSearchVisitor($visitor) :Class_SearchCriteria_Abstract { if (!$this->_value) - return; + return $this; $visitor->addWhereParam($this->_name . ' like "%' . $this->_value . '%"'); + return $this; } } diff --git a/library/Class/Systeme/ModulesMenu.php b/library/Class/Systeme/ModulesMenu.php index a16d26bfb24c9dc5b60cd477675cce3a99d251a8..6b253445257465fa6785f4333165bd185c580c39 100644 --- a/library/Class/Systeme/ModulesMenu.php +++ b/library/Class/Systeme/ModulesMenu.php @@ -197,10 +197,7 @@ class Class_Systeme_ModulesMenu extends Class_Systeme_ModulesAbstract { ->setLabel($entry->getLibelle()) ->setForm($entry->getForm()); - usort($entries, function($a, $b) - { - return strtolower($a->getLabel()) > strtolower($b->getLabel()); - }); + usort($entries, fn($a, $b) => strtolower($a->getLabel()) <=> strtolower($b->getLabel())); return $entries; } diff --git a/library/Class/TableDescription/CosmoMembership.php b/library/Class/TableDescription/CosmoMembership.php new file mode 100644 index 0000000000000000000000000000000000000000..562464c5329a934213bc4022b0b1220053c1525b --- /dev/null +++ b/library/Class/TableDescription/CosmoMembership.php @@ -0,0 +1,29 @@ +<?php +/** + * Copyright (c) 2012-2019, Agence Française Informatique (AFI). All rights reserved. + * + * BOKEH is free software; you can redistribute it and/or modify + * it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE as published by + * the Free Software Foundation. + * + * There are special exceptions to the terms and conditions of the AGPL as it + * is applied to this software (see README file). + * + * BOKEH is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU AFFERO GENERAL PUBLIC LICENSE for more details. + * + * You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE + * along with BOKEH; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + + +class Class_TableDescription_CosmoMembership extends Class_TableDescription { + public function init() { + $this->addColumn($this->_('Code'), 'code') + ->addColumn($this->_('Libellé'), 'libelle') + ->addColumn($this->_('Actif'), 'enabled'); + } +} diff --git a/library/Class/TimeSource.php b/library/Class/TimeSource.php index d5563f95be80f188318e80cbcf4f4a0f80f04d1e..8d39e30299c04e1a95a17dbcac4b0b6ed9a576d9 100644 --- a/library/Class/TimeSource.php +++ b/library/Class/TimeSource.php @@ -25,6 +25,8 @@ */ class Class_TimeSource { const DAY_AND_HOURS_FORMAT = 'Y-m-d H:i:s'; + const FR_DATE_FORMAT='d/m/Y'; + const SQL_DATE_FORMAT='Y-m-d'; /** @return int */ public function time() { diff --git a/library/Class/User/ILSSubscription.php b/library/Class/User/ILSSubscription.php index 7d4908053fc6601e1b4f08389f6364bea4a5aef7..f3f72a2068eb0229bd339b89ff62ffa86f064c14 100644 --- a/library/Class/User/ILSSubscription.php +++ b/library/Class/User/ILSSubscription.php @@ -29,19 +29,64 @@ class Class_User_ILSSubscription { } - public function isExpirable() { + public static function newFor(object $model):self { + if ($model instanceOf Class_User_Membership) + return Class_User_ILSSubscriptionUserMembership::newWith($model); + return new Class_User_ILSSubscription($model); + } + + + public function getLibelle() :string { + return $this->isBlocked() + ? $this->_('bloqué(e)') + : $this->_('abonné(e)'); + } + + + public function getDateFin(){ + return $this->_user->getDateFin(); + } + + + public function getBadgeLabel() :string { + return ''; + } + + + public function validityDate() : string { + return (new DateTime($this->getDateFin()))->format($this->_('d/m/Y')); + } + + + public function validityClass() :string { + $validity_class = $this->isValid() + ? Intonation_Library_Styles::CSS_SUCCESS + : Intonation_Library_Styles::CSS_DANGER; + + return ($this->isAboutToExpire()) + ? Intonation_Library_Styles::CSS_WARNING + : $validity_class; + } + + + public function isDisplayed() :bool { + return true; + } + + + public function isExpirable() :bool { return $this->_user->isAbonne() && $this->_user->hasDateFin(); } - public function isExpired() { + public function isExpired() :bool { return $this->isExpirable() - && ($this->_user->getDateFin() < $this->getTimeSource()->dateYmd()); + && ($this->getDateFin() < $this->getTimeSource()->dateYmd()); } - public function isAboutToExpire() { + public function isAboutToExpire() :bool { return $this->isExpirable() && ($this->ilsExpireIn() >= 0) @@ -49,14 +94,14 @@ class Class_User_ILSSubscription { } - public function ilsExpireIn() { + public function ilsExpireIn() :string { $date_expiry = new DateTime($this->_user->getDateFin()); $today = new DateTime($this->getTimeSource()->dateYmd()); return $today->diff($date_expiry)->format("%r%a"); } - public function isValid() { + public function isValid() :bool { if (!$this->_user->isAbonne()) return false; @@ -64,7 +109,7 @@ class Class_User_ILSSubscription { } - public function isBlocked() { + public function isBlocked() :bool { return $this->_user->isAbonne() && $this->_user->isBlocked(); } @@ -153,3 +198,53 @@ class Class_User_ILSSubscription { return $this; } } + + + +class Class_User_ILSSubscriptionUserMembership extends Class_User_ILSSubscription { + protected $_user_membership; + + + public static function newWith(Class_User_Membership $user_membership) :self{ + return (new Class_User_ILSSubscriptionUserMembership($user_membership->getUser())) + ->setUserMembership($user_membership); + } + + public function setUserMembership(Class_User_Membership $user_membership):self{ + $this->_user_membership =$user_membership; + return $this; + } + + + public function getLibelle():string{ + return $this->_user_membership->getMembershipLibelle(); + } + + + public function getDateFin():string{ + return $this->_user_membership->getEndDate(); + } + + + public function getBadgeLabel():string{ + return $this->_user_membership->getMembershipLibelle().' '; + } + + + public function isDisplayed():bool{ + return (sizeOf($this->_user->getUserMemberships())==1) + || $this->isValid(); + } + + + public function isExpirable() :bool{ + return $this->_user->isAbonne() && $this->getDateFin(); + } + + + public function ilsExpireIn() :string{ + $date_expiry = new DateTime($this->_user_membership->getEndDate()); + $today = new DateTime($this->getTimeSource()->dateYmd()); + return $today->diff($date_expiry)->format("%r%a"); + } +} diff --git a/library/Class/User/Membership.php b/library/Class/User/Membership.php new file mode 100644 index 0000000000000000000000000000000000000000..824cfc700488ab6bb4676af2788607e9f5221cee --- /dev/null +++ b/library/Class/User/Membership.php @@ -0,0 +1,78 @@ +<?php +/** + * Copyright (c) 2012-2022, Agence Française Informatique (AFI). All rights reserved. + * + * BOKEH is free software; you can redistribute it and/or modify + * it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE as published by + * the Free Software Foundation. + * + * There are special exceptions to the terms and conditions of the AGPL as it + * is applied to this software (see README file). + * + * BOKEH is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU AFFERO GENERAL PUBLIC LICENSE for more details. + * + * You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE + * along with BOKEH; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +class User_MembershipLoader extends Storm_Model_Loader { + public function findOrCreate(Class_Users $user, + Class_Membership $membership, + string $start_date, + string $end_date) : Class_User_Membership { + $params = ['start_date' => $start_date, + 'end_date' => $end_date, + 'membership_id' => $membership->getId() ?? 0, + 'user_id' => $user->getId() ?? 0]; + + return Class_User_Membership::findFirstBy($params) ?? Class_User_Membership::newInstance($params); + } + + + public function findUserIdWithCriteria($where){ + return Zend_Registry::get('sql')->fetchAllByColumn(sprintf('select user_id, max(end_date) from user_membership group by user_id having %s', $where)); + } + + + public function isUserMembershipContext() : bool{ + return Class_IntBib::isSingleNanook() && (Class_User_Membership::count() >0); + } +} + + + +class Class_User_Membership extends Storm_Model_Abstract { + use Trait_Timesource; + + protected + $_table_name = 'user_membership', + $_loader_class = 'User_MembershipLoader', + + $_belongs_to = ['user' => ['model' => Class_Users::class, + 'referenced_in' => 'user_id'], + 'membership' => ['model' => Class_Membership::class, + 'referenced_in' => 'membership_id'] + ], + + $_default_attribute_values = ['id' => 0, + 'user_id' => 0, + 'membership_id' => 0, + 'start_date' => '', + 'end_date' => '']; + + public function getMembershipLibelle() :string{ + if ( $membership=$this->getMembership() ) + return $this->getMembership()->getLibelle() ?? ''; + return ''; + } + + + public function isValidSubscription() : bool { + return (!$this->getEndDate() + || ($this->getCurrentDate() <= $this->getEndDate())); + } +} diff --git a/library/Class/User/SearchCriteria.php b/library/Class/User/SearchCriteria.php index b7d739a5a55cf87efaaae7236eb6de38a6ab3d55..095b6c3b193f782323aede55df9725bc4185eb74 100644 --- a/library/Class/User/SearchCriteria.php +++ b/library/Class/User/SearchCriteria.php @@ -21,27 +21,29 @@ class Class_User_SearchCriteria extends Class_SearchCriteria { - protected $_model_class = 'Class_Users'; + protected $_model_class = Class_Users::class; public function __construct($params) { - $this->_criteria = array_filter([new Class_User_SearchCriteriaLibrary($params), - new Class_User_SearchCriteria_RoleLevelLimited($params), - new Class_User_SearchCriteriaValidSubscription($params), - new Class_User_SearchCriteria_EndSubscriptionDate($params), - new Class_User_SearchCriteria_DateFin($params), - new Class_User_SearchCriteria_InLastSigbExport($params), - new Class_User_SearchCriteria_DateMaj($params), - Class_AdminVar::get('ENABLED_SEARCH_USER_AGE') - ? new Class_User_SearchCriteria_Age($params) - : null, - new Class_User_SearchCriteria_LastLogin($params), - new Class_User_SearchCriteria_NeverLogged($params), - new Class_User_SearchCriteria_NumberOfReviews($params), - new Class_User_SearchCriteria_NumberOfBaskets($params), - new Class_User_SearchCriteriaSearchFor($params), - new Class_User_SearchCriteria_Order($params)] - ); + $this->_criteria = + array_filter([new Class_User_SearchCriteriaLibrary($params), + new Class_User_SearchCriteria_RoleLevelLimited($params), + Class_User_SearchCriteriaValidSubscription::newFor($params), + Class_User_SearchCriteria_EndSubscriptionDate::newFor($params), + Class_User_SearchCriteria_DateFin::newFor($params), + new Class_User_SearchCriteria_Membership($params), + new Class_User_SearchCriteria_InLastSigbExport($params), + new Class_User_SearchCriteria_DateMaj($params), + Class_AdminVar::get('ENABLED_SEARCH_USER_AGE') + ? new Class_User_SearchCriteria_Age($params) + : null, + new Class_User_SearchCriteria_LastLogin($params), + new Class_User_SearchCriteria_NeverLogged($params), + new Class_User_SearchCriteria_NumberOfReviews($params), + new Class_User_SearchCriteria_NumberOfBaskets($params), + new Class_User_SearchCriteriaSearchFor($params), + new Class_User_SearchCriteria_Order($params)] + ); } } @@ -68,6 +70,13 @@ class Class_User_SearchCriteriaValidSubscription $_name = 'valid_subscription', $_value = 0; + + public static function newFor($params){ + return (Class_User_Membership::isUserMembershipContext()) + ? Class_User_SearchCriteriaValidSubscriptionUserMembership::newFor($params) + : Class_User_SearchCriteriaValidSubscriptionUser::newFor($params); + } + public function buildElement() { return new Zend_Form_Element_Checkbox($this->getName(), ['label' => $this->_('Abonnement valide'), @@ -80,12 +89,12 @@ class Class_User_SearchCriteriaValidSubscription } - public function acceptSearchVisitor($visitor) { - $visitor->addWhereParam('STR_TO_DATE(date_fin, \'%Y-%m-%d\') >= CURDATE()'); + public function acceptSearchVisitor($visitor) :Class_SearchCriteria_Abstract{ + return $this; } - public function modelMatch($model) { + public function modelMatch($model) :bool { return $model->isAbonnementValid(); } @@ -105,6 +114,7 @@ class Class_User_SearchCriteriaValidSubscription ->findFirstCriteriaByClass(Class_User_SearchCriteria_RoleLevel::class)) return false; + return $role_level->isAbonneSigb() || $role_level->isAbonne(); } } @@ -112,6 +122,42 @@ class Class_User_SearchCriteriaValidSubscription +class Class_User_SearchCriteriaValidSubscriptionUser + extends Class_User_SearchCriteriaValidSubscription { + + + public static function newFor($params){ + return new Class_User_SearchCriteriaValidSubscriptionUser($params); + } + + + public function acceptSearchVisitor($visitor) :Class_SearchCriteria_Abstract { + $visitor->addWhereParam('STR_TO_DATE(date_fin, \'%Y-%m-%d\') >= CURDATE()'); + return $this; + } +} + + + + +class Class_User_SearchCriteriaValidSubscriptionUserMembership + extends Class_User_SearchCriteriaValidSubscription { + + + public static function newFor($params){ + return new Class_User_SearchCriteriaValidSubscriptionUserMembership($params); + } + + + public function acceptSearchVisitor($visitor) :Class_SearchCriteria_Abstract { + $visitor->addWhereParam('id_user IN (select user_id from user_membership where CURDATE() <= user_membership.end_date)'); + return $this; + } +} + + + + class Class_User_SearchCriteriaSearchFor extends Class_SearchCriteria_Abstract{ protected $_name = 'search_for', @@ -125,18 +171,19 @@ class Class_User_SearchCriteriaSearchFor extends Class_SearchCriteria_Abstract{ } - public function acceptSearchVisitor($visitor) { + public function acceptSearchVisitor($visitor) :Class_SearchCriteria_Abstract { if (!$search_value = $this->_sanitize($this->_value)) - return; + return $this; foreach(array_fill_keys($this->_columns, $search_value) as $column => $value) $table_or[] = $column . ' LIKE "%' . $value . '%"'; $visitor->addWhereParam(implode(' OR ', $table_or)); + return $this; } - public function modelMatch($user) { + public function modelMatch($user) :bool { if (!$search_value = $this->_sanitize($this->_value)) return true; diff --git a/library/Class/User/SearchCriteria/Age.php b/library/Class/User/SearchCriteria/Age.php index f03184e9ff804e6c95f0936e83f44c50c26b426e..8410286692b79090f160374fc41bcd2eb04cbaf5 100644 --- a/library/Class/User/SearchCriteria/Age.php +++ b/library/Class/User/SearchCriteria/Age.php @@ -54,9 +54,9 @@ class Class_User_SearchCriteria_Age extends Class_SearchCriteria_Abstract { } - public function acceptSearchVisitor($visitor) { + public function acceptSearchVisitor($visitor) :Class_SearchCriteria_Abstract { if ($this->_isAllValues()) - return; + return $this; if ($this->_hasFrom()) { $date = $this->substractYearsToCurrentDate((int)$this->_from); @@ -67,10 +67,11 @@ class Class_User_SearchCriteria_Age extends Class_SearchCriteria_Abstract { $date = $this->substractYearsToCurrentDate((int)$this->_to); $visitor->addWhereParam('naissance >=\'' . $date.'\''); } + return $this; } - public function modelMatch($user) { + public function modelMatch($user) :bool { if ($this->_isAllValues()) return true; diff --git a/library/Class/User/SearchCriteria/DateFin.php b/library/Class/User/SearchCriteria/DateFin.php index a16366f6a7723249e36f1c9bf863ba9f8d78e73a..8f667f3e2827a74b730feb29ab20f2cd067e9663 100644 --- a/library/Class/User/SearchCriteria/DateFin.php +++ b/library/Class/User/SearchCriteria/DateFin.php @@ -27,7 +27,94 @@ class Class_User_SearchCriteria_DateFin extends Class_SearchCriteria_DateRange { $_end_suffix = '_end'; + public static function newFor($params){ + return (Class_User_Membership::isUserMembershipContext()) + ? Class_User_SearchCriteria_EndDateUserMembership::newFor($params) + : Class_User_SearchCriteria_DateFinUser::newFor($params); + } + + public function buildElement() { return parent::buildElement()->setLabel($this->_('Abonnement échu')); } } + + + + +class Class_User_SearchCriteria_DateFinUser + extends Class_User_SearchCriteria_DateFin { + + public static function newFor($params){ + return new Class_User_SearchCriteria_DateFinUser($params); + } +} + + + + +class Class_User_SearchCriteria_EndDateUserMembership + extends Class_User_SearchCriteria_DateFin { + + public static function newFor($params){ + return new Class_User_SearchCriteria_EndDateUserMembership($params); + } + + + public function acceptSearchVisitor($visitor) :Class_SearchCriteria_Abstract { + $where_parts = []; + if (!$this->_value_start && !$this->_value_end) + return $this; + + if ($this->_value_start) + $where_parts[] = sprintf('max(end_date) >= "%s"', + $this->_sqlFormat($this->_value_start)); + + if ($this->_value_end) + $where_parts[] = sprintf('max(end_date) <= "%s"', + $this->_sqlFormat($this->_value_end)); + + if ($userids = Class_User_Membership::findUserIdWithCriteria(implode(' AND ', $where_parts))){ + $visitor->addWhereParam('id_user in ('. implode(',' ,$userids) .')'); + return $this; + } + $visitor->hasNoResult(); + return $this; + } + + + public function modelMatch($model) :bool { + if (!$this->_value_start && !$this->_value_end) + return true; + + if (parent::Modelmatch($model)) + return true; + + if (!$user_memberships = $model->getUserMemberships()) + return false; + + usort($user_memberships, fn($a,$b) => ($a->getEndDate() <=> $b->getEndDate())); + $user_membership = reset($user_memberships); + if (!$end_date = $user_membership->getEndDate()) + return false; + $user_membership = end($user_memberships); + $end_date = $user_membership->getEndDate(); + if (!$this->isValidDate($end_date)) + return false; + + if ($this->_value_start + && $this->_sqlFormat($this->_value_start) > $end_date) + return false; + + if ($this->_value_end + && $this->_sqlFormat($this->_value_end) < $end_date) + return false; + + return true; + } + + + public function isValidDate($value) :bool { + return (new ZendAfi_Validate_DateFormat())->setFormat('Y-m-d')->isValid($value); + } +} diff --git a/library/Class/User/SearchCriteria/DateMaj.php b/library/Class/User/SearchCriteria/DateMaj.php index b2a1987118730653391fc719dd14194e22a3c467..be322bef3c69b3397a36ff083b2a8412d0daa199 100644 --- a/library/Class/User/SearchCriteria/DateMaj.php +++ b/library/Class/User/SearchCriteria/DateMaj.php @@ -33,7 +33,7 @@ class Class_User_SearchCriteria_DateMaj extends Class_SearchCriteria_DateRange { } - public function modelMatch($model) { + public function modelMatch($model) :bool { if (!$model->isNew()) return parent::modelMatch($model); diff --git a/library/Class/User/SearchCriteria/EndSubscriptionDate.php b/library/Class/User/SearchCriteria/EndSubscriptionDate.php index 6aea797de1beb4fc83db2c98c694493bbb2655ab..41884ba135c324573d8687f5ac8fa492eb741192 100644 --- a/library/Class/User/SearchCriteria/EndSubscriptionDate.php +++ b/library/Class/User/SearchCriteria/EndSubscriptionDate.php @@ -27,6 +27,14 @@ class Class_User_SearchCriteria_EndSubscriptionDate $_name = 'end_subscription_days', $_value = ''; + + public static function newFor($params){ + return (Class_User_Membership::isUserMembershipContext()) + ? Class_User_SearchCriteria_EndSubscriptionDateUserMembership::newFor($params) + : Class_User_SearchCriteria_EndSubscriptionDateUser::newFor($params); + } + + public function buildElement() { return new Zend_Form_Element_Text($this->getName(), ['label' => $this->_('Abonnement échu d\'ici (jours)'), @@ -34,22 +42,87 @@ class Class_User_SearchCriteria_EndSubscriptionDate } - public function modelMatch($user) { - return $user->getDateFin() - ? $user->getDateFin() <= $this->addDaysToCurrentDate($this->_value) - : true; + public function modelMatch($user) :bool{ + return false; } - public function acceptSearchVisitor($visitor) { - $visitor->addWhereParam('date_fin!=\'\' and date_fin <=\'' . $this->addDaysToCurrentDate($this->_value).'\''); + public function acceptSearchVisitor($visitor) :Class_SearchCriteria_Abstract { + return $this; } - public function shouldFilter($search_criteria) { + public function shouldFilter($search_criteria) :bool { return $this->_value && ($role_level = $search_criteria ->findFirstCriteriaByClass(Class_User_SearchCriteria_RoleLevel::class)) && ($role_level->isAbonneSigb() || $role_level->isAbonne()); } } + + + + +class Class_User_SearchCriteria_EndSubscriptionDateUser + extends Class_User_SearchCriteria_EndSubscriptionDate { + + public static function newFor($params){ + return new Class_User_SearchCriteria_EndSubscriptionDateUser($params); + } + + + public function acceptSearchVisitor($visitor) :Class_SearchCriteria_Abstract { + $visitor->addWhereParam('date_fin!=\'\' and date_fin <=\'' . $this->addDaysToCurrentDate($this->_value).'\''); + return $this; + } + + + public function modelMatch($user) :bool{ + return $user->getDateFin() + ? $user->getDateFin() <= $this->addDaysToCurrentDate($this->_value) + : true; + } +} + + + + +class Class_User_SearchCriteria_EndSubscriptionDateUserMembership + extends Class_User_SearchCriteria_EndSubscriptionDate { + + public static function newFor($params){ + return new Class_User_SearchCriteria_EndSubscriptionDateUserMembership($params); + } + + + public function acceptSearchVisitor($visitor) :Class_SearchCriteria_Abstract { + if (!$this->_value) + return $this; + if ($userids = Class_User_Membership::findUserIdWithCriteria(' max(end_date) >= CURDATE() AND max(end_date) <=\'' .$this->addDaysToCurrentDate($this->_value) .'\' ')){ + $visitor->addWhereParam('id_user in ('. implode(',' ,$userids) .')'); + return $this; + } + + $visitor->hasNoResult(); + return $this; + } + + + public function modelMatch($user) :bool{ + if (!$this->_value) + return true; + if (!$user->isAbonne()) + return false; + $user_memberships = $user->getUserMemberships(); + if (!$user_memberships) + return false; + usort($user_memberships, fn($a,$b) => ($a->getEndDate() <=> $b->getEndDate())); + $user_membership = reset($user_memberships); + if (!$date_fin = $user_membership->getEndDate()) + return false; + $user_membership = end($user_memberships); + $date_fin = $user_membership->getEndDate(); + return (($date_fin >= $this->getCurrentDate()) + && ($date_fin <= $this->addDaysToCurrentDate($this->_value))); + } +} diff --git a/library/Class/User/SearchCriteria/LastLogin.php b/library/Class/User/SearchCriteria/LastLogin.php index ed6a215481b657e53acdb88b2cebdf5e6379e1ee..459ca935de96d19702cebaef2e3bd348233f7570 100644 --- a/library/Class/User/SearchCriteria/LastLogin.php +++ b/library/Class/User/SearchCriteria/LastLogin.php @@ -32,7 +32,7 @@ class Class_User_SearchCriteria_LastLogin extends Class_SearchCriteria_DateRange } - public function isValidDate($value) { + public function isValidDate($value) :bool { return (new ZendAfi_Validate_DateFormat())->setFormat('Y-m-d H:i:s')->isValid($value); } } diff --git a/library/Class/User/SearchCriteria/Membership.php b/library/Class/User/SearchCriteria/Membership.php new file mode 100644 index 0000000000000000000000000000000000000000..613cc2422f3c2001b2c730de726f55f509542a06 --- /dev/null +++ b/library/Class/User/SearchCriteria/Membership.php @@ -0,0 +1,100 @@ +<?php +/** + * Copyright (c) 2012-2022, Agence Française Informatique (AFI). All rights reserved. + * + * BOKEH is free software; you can redistribute it and/or modify + * it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE as published by + * the Free Software Foundation. + * + * There are special exceptions to the terms and conditions of the AGPL as it + * is applied to this software (see README file). + * + * BOKEH is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU AFFERO GENERAL PUBLIC LICENSE for more details. + * + * You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE + * along with BOKEH; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + + +class Class_User_SearchCriteria_Membership + extends Class_SearchCriteria_MultiCheckbox { + use Trait_TimeSource; + + protected $_name = 'membership'; + protected $_value; + + public function _getLabel(){ + return $this->_('Type d\'abonnement'); + } + + + public function buildElement(){ + return Class_IntBib::isSingleNanook() + ? parent::buildElement()->setSelectedAllMeansNothing(false) + : ''; + } + + + public function getArrayValues(){ + return (is_array($this->_value)) + ? (array_filter($this->_value, + function ($element){ + return $element != 'all'; + })) + : explode(';', $this->_value); + } + + + public function acceptSearchVisitor($visitor) :Class_SearchCriteria_Abstract { + $wheres = []; + if ($this->_isIgnore()) + $wheres []= 'id_user not in (select distinct (user_id) from user_membership)'; + + if ($ids = array_filter($this->getArrayValues(), + fn($element) => $element!= 'ignore')) + $wheres [] = 'id_user in ( select distinct (user_id) from user_membership where membership_id in (' + .implode(',',$ids) + .'))'; + + if ($wheres) + $visitor->addWhereParam('('.implode(' or ', $wheres).')'); + return $this; + } + + + protected function _isIgnore(){ + return in_array('ignore', $this->getArrayValues()); + } + + + public function modelMatch($model) : bool { + $user_memberships = $model->getUserMemberships(); + if ($this->_isIgnore() && (sizeOf($user_memberships)==0)) + return true; + + if (!$user_memberships && !sizeOf($this->getArrayValues())) + return true; + + foreach ($user_memberships as $user_membership) + if (in_array($user_membership->getMembershipId(),$this->getArrayValues())) + return true; + + return false; + } + + + public function describeOn($view) { + return ($this->_value) + ? ($this->_element->getLabel() .$this->_( ' dans ').': ' . implode(',',$this->_value)) + : ''; + } + + + public function shouldFilter($search_criteria) : bool { + return Class_IntBib::isSingleNanook() && (bool) $this->_value; + } +} diff --git a/library/Class/User/SearchCriteria/NeverLogged.php b/library/Class/User/SearchCriteria/NeverLogged.php index 2d6bba571bf3cd238e294c7bb7fbc35969fca247..5c861b957539c8ad879dd14bfc96cb9e98858315 100644 --- a/library/Class/User/SearchCriteria/NeverLogged.php +++ b/library/Class/User/SearchCriteria/NeverLogged.php @@ -39,7 +39,7 @@ class Class_User_SearchCriteria_NeverLogged extends Class_SearchCriteria_Abstrac } - public function modelMatch($model) { + public function modelMatch($model):bool { if (!$this->_value) return true; @@ -48,9 +48,10 @@ class Class_User_SearchCriteria_NeverLogged extends Class_SearchCriteria_Abstrac } - public function acceptSearchVisitor($visitor) { + public function acceptSearchVisitor($visitor) :Class_SearchCriteria_Abstract { if (!$this->_value) - return; + return $this; $visitor->addWhereParam('last_login is null or last_login="'.static::EMPTY_DATE.'"'); + return $this; } } diff --git a/library/Class/User/SearchCriteria/NewsletterSubscriptionStatus.php b/library/Class/User/SearchCriteria/NewsletterSubscriptionStatus.php index 3b5dd0f5b1aa4b41012263b5dc913ab672aa1fbb..4ab4ee7cc0d0ae421c11bbe09f5a36cf67024d5e 100644 --- a/library/Class/User/SearchCriteria/NewsletterSubscriptionStatus.php +++ b/library/Class/User/SearchCriteria/NewsletterSubscriptionStatus.php @@ -43,45 +43,52 @@ class Class_User_SearchCriteria_NewsletterSubscriptionStatus extends Class_Searc } - public function acceptSearchVisitor($visitor) { + public function acceptSearchVisitor($visitor) :Class_SearchCriteria_Abstract { if (!$this->_newsletter || 'all' == $this->_value) - return; + return $this; if ('not_subscribed' == $this->_value) - return $this->_applyNotSubscribedFilterOn($visitor); + return $this->_applyNotSubscribedFilterOn($visitor); if ('unsubscribed' == $this->_value) - return $this->_applyUnsubscribedFilterOn($visitor); + return $this->_applyUnsubscribedFilterOn($visitor); return $this->_applySubscribedFilterOn($visitor); } - protected function _applySubscribedFilterOn($visitor) { - if (!$recipient_ids = $this->_newsletter->getRecipientsUsersIds()) - return $visitor->hasNoResult(); + protected function _applySubscribedFilterOn($visitor) :self{ + if (!$recipient_ids = $this->_newsletter->getRecipientsUsersIds()){ + $visitor->hasNoResult(); + return $this; + } $visitor->addWhereParam('id_user in (' . implode(',', $recipient_ids). ')'); if ($blacklisted = $this->_newsletter->getBlackListedMails()) $visitor->addWhereParam('mail not in ("' . implode('","', $blacklisted). '")'); + return $this; } - protected function _applyNotSubscribedFilterOn($visitor) { + protected function _applyNotSubscribedFilterOn($visitor) :self{ if (!$recipient_ids = $this->_newsletter->getRecipientsUsersIds()) - return; + return $this; - return $visitor->addWhereParam('id_user not in (' . implode(',', $recipient_ids). ')'); + $visitor->addWhereParam('id_user not in (' . implode(',', $recipient_ids). ')'); + return $this; } - protected function _applyUnsubscribedFilterOn($visitor) { - if (!$blacklisted = $this->_newsletter->getBlackListedMails()) - return $visitor->hasNoResult(); + protected function _applyUnsubscribedFilterOn($visitor) :self{ + if (!$blacklisted = $this->_newsletter->getBlackListedMails()){ + $visitor->hasNoResult(); + return $this; + } $visitor ->addWhereParam('id_user in (' . implode(',', $this->_newsletter->getRecipientsUsersIds()). ')') ->addWhereParam('mail in ("' . implode('","', $blacklisted). '")'); + return $this; } -} \ No newline at end of file +} diff --git a/library/Class/User/SearchCriteria/RoleLevel.php b/library/Class/User/SearchCriteria/RoleLevel.php index 2b202c4393faa0b5a0c9d68b226f2747520fb501..e9d6d9b3ab26b1b612cc6d89cd7582569b687c95 100644 --- a/library/Class/User/SearchCriteria/RoleLevel.php +++ b/library/Class/User/SearchCriteria/RoleLevel.php @@ -64,8 +64,12 @@ class Class_User_SearchCriteria_RoleLevel extends Class_SearchCriteria_Select { 'end_subscription_days', 'date_fin_start']); + $abonne_toggle = ['statut']; + if (Class_IntBib::isSingleNanook()) + $abonne_toggle [] = 'membership'; + $this->_addToggleVisibilityFor([ZendAfi_Acl_AdminControllerRoles::ABONNE_SIGB], - ['statut']); + $abonne_toggle); } diff --git a/library/Class/User/SearchCriteria/RoleLevelLimit.php b/library/Class/User/SearchCriteria/RoleLevelLimit.php index 5ec3ada2f9eb3b227001b39768464df2fda479c5..c1ef9208fa4a1fad89bd44eaa660c80d6c0cdb17 100644 --- a/library/Class/User/SearchCriteria/RoleLevelLimit.php +++ b/library/Class/User/SearchCriteria/RoleLevelLimit.php @@ -26,7 +26,8 @@ class Class_User_SearchCriteria_RoleLevelLimit extends Class_SearchCriteria_Abst } - public function acceptSearchVisitor($visitor) { + public function acceptSearchVisitor($visitor) :Class_SearchCriteria_Abstract { $visitor->addWhereParam('role_level <= ' . Class_Users::getIdentity()->getRoleLevel()); + return $this; } } diff --git a/library/Class/User/SearchCriteria/SessionActivitySubscriptionStatus.php b/library/Class/User/SearchCriteria/SessionActivitySubscriptionStatus.php index d111e1d44a72e70feffae99e76fb355b8a1a067e..e152b0a8fa8b9ce5d3c69132445f5cefe1e29392 100644 --- a/library/Class/User/SearchCriteria/SessionActivitySubscriptionStatus.php +++ b/library/Class/User/SearchCriteria/SessionActivitySubscriptionStatus.php @@ -51,39 +51,37 @@ class Class_User_SearchCriteria_SessionActivitySubscriptionStatus } - public function acceptSearchVisitor($visitor) { + public function acceptSearchVisitor($visitor) :Class_SearchCriteria_Abstract { if (!$this->_model || static::ALL_VALUES == $this->_value) - return; + return $this; - if (static::OPTION_NOT_SUBSCRIBE == $this->_value) { - $this->_applyNotSubscribedFilterOn($visitor, null); - return; - } + if (static::OPTION_NOT_SUBSCRIBE == $this->_value) + return $this->_applyNotSubscribedFilterOn($visitor, null); - if (static::OPTION_IN_QUEUE == $this->_value) { - $this->_applySubscribedFilterOn($visitor, true); - return; - } + if (static::OPTION_IN_QUEUE == $this->_value) + return $this->_applySubscribedFilterOn($visitor, true); - $this->_applySubscribedFilterOn($visitor, false); + return $this->_applySubscribedFilterOn($visitor, false); } - protected function _applySubscribedFilterOn($visitor, $with_queue) { - if (!$ids = $this->_registeredUserIds($with_queue)) { + protected function _applySubscribedFilterOn($visitor, $with_queue) :Class_SearchCriteria_Abstract{ + if (!$ids = $this->_registeredUserIds($with_queue)){ $visitor->hasNoResult(); - return; + return $this; } $visitor->addWhereParam('id_user in (' . implode(',', $ids). ')'); + return $this; } - protected function _applyNotSubscribedFilterOn($visitor, $with_queue) { + protected function _applyNotSubscribedFilterOn($visitor, $with_queue) :Class_SearchCriteria_Abstract{ if (!$ids = $this->_registeredUserIds($with_queue)) - return; + return $this; $visitor->addWhereParam('id_user not in (' . implode(',', $ids). ')'); + return $this; } diff --git a/library/Class/User/SearchCriteria/WithMail.php b/library/Class/User/SearchCriteria/WithMail.php index 2a3fa4081e0252584c8e975a654364cc1475798b..ee8899a37a4337fa9192ab4c1252e24360fe121c 100644 --- a/library/Class/User/SearchCriteria/WithMail.php +++ b/library/Class/User/SearchCriteria/WithMail.php @@ -31,11 +31,12 @@ class Class_User_SearchCriteria_WithMail extends Class_SearchCriteria_Abstract { 'value' => $this->_value]); } - public function acceptSearchVisitor($visitor) { + public function acceptSearchVisitor($visitor) :Class_SearchCriteria_Abstract { if (!$this->_value) - return; + return $this; $visitor->addWhereParam('mail is not null') ->addWhereParam('mail <> \'\''); + return $this; } -} \ No newline at end of file +} diff --git a/library/Class/User/SearchCriteria/WithRight.php b/library/Class/User/SearchCriteria/WithRight.php index 537f11be11a16a4a7819743092f28260b59fb93e..1298c9baed286e995fb49d3ac4cef9ab510166fc 100644 --- a/library/Class/User/SearchCriteria/WithRight.php +++ b/library/Class/User/SearchCriteria/WithRight.php @@ -39,23 +39,24 @@ class Class_User_SearchCriteria_WithRight extends Class_SearchCriteria_Abstract } - public function acceptSearchVisitor($visitor) { + public function acceptSearchVisitor($visitor) :Class_SearchCriteria_Abstract { if (null === $this->_right) - return; + return $this; $ids = array_merge(Class_UserGroup::findAllUserIdsHavingRight($this->_right), Class_SessionActivityInscription::userIdsOptimizedFor($this->_model)); if (!$ids = array_unique($ids)) { $visitor->hasNoResult(); - return; + return $this; } $visitor->addWhereParam('id_user in (' . implode(',', $ids). ')'); + return $this; } - public function modelMatch($model) { + public function modelMatch($model) :bool { return $model->hasRightSuivreActivity(); } } diff --git a/library/Class/UserGroup.php b/library/Class/UserGroup.php index 2f20c3b96364056e3a65621c2cee94143f187d3c..0f26c13bfe44b11fac84f7592aea8bc75063abe2 100644 --- a/library/Class/UserGroup.php +++ b/library/Class/UserGroup.php @@ -765,6 +765,12 @@ class Class_UserGroup extends Storm_Model_Abstract { } + public function cleanCriteriaCache() :self { + $this->_criteria_cache = null; + return $this; + } + + public function isDeletable() : bool { return false === (bool) $this->getProtected(); } diff --git a/library/Class/UserGroup/Agenda/SearchCriteria/User.php b/library/Class/UserGroup/Agenda/SearchCriteria/User.php index dfe2287eac50f36ea046f2182174a2cdbd619246..9c598415680036c313a45c13028ba4347b09b506 100644 --- a/library/Class/UserGroup/Agenda/SearchCriteria/User.php +++ b/library/Class/UserGroup/Agenda/SearchCriteria/User.php @@ -31,24 +31,31 @@ class Class_UserGroup_Agenda_SearchCriteria_User extends Class_SearchCriteria_Ab } - public function acceptSearchVisitor($visitor) { + public function acceptSearchVisitor($visitor) :Class_SearchCriteria_Abstract{ $value = str_replace(["\000", "\n", "\r", "\"", "\'", "'", "\032"], '', trim($this->_value)); if (!$value) - return; + return $this; - if ((!$members = $this->_groupMembers()) || $members->isEmpty()) - return $visitor->hasNoResult(); + if ((!$members = $this->_groupMembers()) || $members->isEmpty()){ + $visitor->hasNoResult(); + return $this; + } - if (!$matching_members = $this->_getMatchingMembers($members, $value)) - return $visitor->hasNoResult(); + if (!$matching_members = $this->_getMatchingMembers($members, $value)) { + $visitor->hasNoResult(); + return $this; + } - if (!$matching_groups = $this->_getMatchingGroups($members, $matching_members)) - return $visitor->hasNoResult(); + if (!$matching_groups = $this->_getMatchingGroups($members, $matching_members)){ + $visitor->hasNoResult(); + return $this; + } $visitor->addWhereParam('id in (' . implode(',', $matching_groups) . ')'); + return $this; } diff --git a/library/Class/Users.php b/library/Class/Users.php index 01694aaddd842a34d468962645d53a4c8e18e59d..a1b4ba01db90af03f77372e786438218261e7707 100644 --- a/library/Class/Users.php +++ b/library/Class/Users.php @@ -452,7 +452,11 @@ class Class_Users extends Storm_Model_Abstract { 'drive_checkouts' => ['model' => 'Class_DriveCheckout', 'role' => 'user', - 'dependents' => 'delete'] + 'dependents' => 'delete'], + + 'user_memberships' => ['model' => Class_User_Membership::class, + 'role' => 'user', + 'dependents' => 'delete'] ], @@ -2040,4 +2044,23 @@ class Class_Users extends Storm_Model_Abstract { public function isAbonnePortail() : bool { return ZendAfi_Acl_AdminControllerRoles::ABONNE === $this->getRoleLevel(); } + + + public function getLastUserMemberships() : array { + $user_memberships = $this->getUserMemberships(); + + if (sizeOf($user_memberships)==0) + return []; + + usort($user_memberships, + function($a,$b){ + return $b->getEndDate() <=> $a->getEndDate(); + }); + return ($array_filtered = array_filter($user_memberships, + function($element){ + return $element->isValidSubscription(); + })) + ? $array_filtered + : [reset($user_memberships)]; + } } diff --git a/library/Class/WebService/SIGB/Emprunteur.php b/library/Class/WebService/SIGB/Emprunteur.php index c9940eee284672bd899a5c475abeb54e19fceb6f..ee8cd89062d506f938d2180d7abb0ccb7855a1e1 100644 --- a/library/Class/WebService/SIGB/Emprunteur.php +++ b/library/Class/WebService/SIGB/Emprunteur.php @@ -24,9 +24,9 @@ class Class_WebService_SIGB_Emprunteur { $_id, $_name, $_emprunts = [], - $_subscriptions = [], $_reservations = [], $_waiting_holds = [], + $_subscriptions, $_email = '', $_nom = null, $_prenom = null, @@ -66,10 +66,12 @@ class Class_WebService_SIGB_Emprunteur { $this->getEmprunts(); $this->getReservations(); + return ['_id', '_name', '_emprunts', '_reservations', + '_subscriptions', '_email', '_nom', '_prenom', @@ -87,7 +89,6 @@ class Class_WebService_SIGB_Emprunteur { '_is_contact_sms', '_library_code', '_id_int_bib', - '_subscriptions', '_blocked', '_multimedia_access', '_parental_authorization']; @@ -332,12 +333,16 @@ class Class_WebService_SIGB_Emprunteur { public function subscriptionAdd($subscription_id, $subscription_label) { - $this->_subscriptions[$subscription_id] = $subscription_label; + $this->getSubscriptions()->add( (new Class_WebService_SIGB_Subscription) + ->setId($subscription_id) + ->setLabel($subscription_label)); return $this; } public function getSubscriptions() { + if (!isset($this->_subscriptions)) + $this->_subscriptions = new Storm_collection; return $this->_subscriptions; } diff --git a/library/Class/WebService/SIGB/Koha/Emprunteur.php b/library/Class/WebService/SIGB/Koha/Emprunteur.php index 42217bd8fbd0fa14a759f4433c834c545416c04b..584e217f34b01524f9b0dcd3f14d5adff6507131 100644 --- a/library/Class/WebService/SIGB/Koha/Emprunteur.php +++ b/library/Class/WebService/SIGB/Koha/Emprunteur.php @@ -24,9 +24,11 @@ class Class_WebService_SIGB_Koha_Emprunteur extends Class_WebService_SIGB_Emprun const CATEGORY_KOHA = 'Koha'; public function updateUserRelations(Class_Users $user) { - if ( ! $user->getId()) + if (! $user->getId()) return; + parent::updateUserRelations($user); + if ( ! $this->_service->getCreateCategoryUsergroup() ) return; @@ -35,7 +37,7 @@ class Class_WebService_SIGB_Koha_Emprunteur extends Class_WebService_SIGB_Emprun foreach($category->getUserGroups() as $group) $group->removeUser($user)->save(); - foreach($this->_subscriptions as $label) - Class_UserGroup::getOrCreate($category, $label, $user); + foreach($this->getSubscriptions() as $subscription) + Class_UserGroup::getOrCreate($category, $subscription->getLabel(), $user); } } diff --git a/library/Class/WebService/SIGB/Nanook/Emprunteur.php b/library/Class/WebService/SIGB/Nanook/Emprunteur.php new file mode 100644 index 0000000000000000000000000000000000000000..e7beb4e270f08c6f1c2fcf76b30440a26d5d0426 --- /dev/null +++ b/library/Class/WebService/SIGB/Nanook/Emprunteur.php @@ -0,0 +1,54 @@ +<?php +/** + * Copyright (c) 2012-2022, Agence Française Informatique (AFI). All rights reserved. + * + * BOKEH is free software; you can redistribute it and/or modify + * it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE as published by + * the Free Software Foundation. + * + * There are special exceptions to the terms and conditions of the AGPL as it + * is applied to this software (see README file). + * + * BOKEH is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU AFFERO GENERAL PUBLIC LICENSE for more details. + * + * You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE + * along with BOKEH; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + + +class Class_WebService_SIGB_Nanook_Emprunteur extends Class_WebService_SIGB_Emprunteur { + public function updateUserRelations($user) { + if ($this->_mustProcessSubscription($user)) + $this->_processSubscriptions($user); + } + + + protected function _mustProcessSubscription(Class_Users $user) :bool{ + return Class_IntBib::isSingleNanook() + && (Class_Membership::count() >0) + && ($user->isNew() ||$user->isAbonne()); + } + + + protected function _processSubscriptions(Class_Users $user) :void{ + foreach ($this->getSubscriptions() as $subscription){ + $membership = Class_Membership::findOrCreate( $subscription->getId(), $subscription->getLabel()); + if ($membership->isNew()) + $membership->save(); + $user_membership = Class_User_Membership::findOrCreate( + $user, + $membership, + $subscription->getStartDate(), + $subscription->getEndDate() + ); + if ($user_membership->isNew()){ + $user_membership->save(); + $user->addUserMembership($user_membership); + } + } + } +} diff --git a/library/Class/WebService/SIGB/Nanook/PatronInfoReader.php b/library/Class/WebService/SIGB/Nanook/PatronInfoReader.php index e075bd90e951b76a85c2d4bf5fdfcc5c1690730d..01c9b6172aa3c30b71c3a45185e0c08188dff707 100644 --- a/library/Class/WebService/SIGB/Nanook/PatronInfoReader.php +++ b/library/Class/WebService/SIGB/Nanook/PatronInfoReader.php @@ -25,7 +25,8 @@ class Class_WebService_SIGB_Nanook_PatronInfoReader $_user, $_suggests = [], $_item_priorities = [], - $_current_suggest; + $_current_suggest, + $_current_subscription; /** * @return Class_WebService_SIGB_Nanook_PatronInfoReader @@ -64,11 +65,23 @@ class Class_WebService_SIGB_Nanook_PatronInfoReader * @param $data string */ public function endEndDate($data) { - if ($this->_xml_parser->inParents('subscriptions')) + if (!$data || ($data == 'null')) return; - if ($data && 'null' != $data) - $this->getEmprunteur()->setEndDate($data); + return ($this->_xml_parser->inParents('subscriptions')) + ? $this->_addSubscriptionEndDate($data) + : $this->_addEmprunteurEndDate($data); + } + + + protected function _addSubscriptionEndDate(string $data){ + if ($this->_current_subscription) + $this->_current_subscription->setEndDate($data); + } + + + protected function _addEmprunteurEndDate(string $data){ + $this->getEmprunteur()->setEndDate($data); } @@ -298,6 +311,54 @@ class Class_WebService_SIGB_Nanook_PatronInfoReader } + public function startSubscription() { + $this->_newSubscription(); + } + + + public function startSubscriptions() { + if ($this->_xml_parser->inParents('subscriptions')) + $this->_newSubscription(); + } + + + protected function _newSubscription(){ + $this->_current_subscription = new Class_WebService_SIGB_Subscription; + } + + + public function endRateId($data) { + $this->_current_subscription->setId($data); + } + + + public function endRateLabel($data) { + $this->_current_subscription->setLabel($data); + } + + + public function endStartDate($data) { + $this->_current_subscription->setStartDate($data); + } + + + public function endSubscriptions() { + $this->_addToSubscriptions(); + } + + + public function endSubscription() { + $this->_addToSubscriptions(); + } + + protected function _addToSubscriptions(){ + if ($this->_current_subscription){ + $this->getEmprunteur()->getSubscriptions()->add($this->_current_subscription); + $this->_current_subscription = null; + } + } + + public function endSiteId($data) { $this->getEmprunteur()->setLibraryCode($data); } @@ -317,4 +378,4 @@ class Class_WebService_SIGB_Nanook_PatronInfoReader public function endParentalAuthorization($data) : void { $this->getEmprunteur()->setParentalAuthorization((int) $data); } -} \ No newline at end of file +} diff --git a/library/Class/WebService/SIGB/Nanook/Service.php b/library/Class/WebService/SIGB/Nanook/Service.php index 55f97b91b9093d40f3e13c632dd9830c9131b930..9acfeae1f214f484acf03d991c89c082d3db8bb7 100644 --- a/library/Class/WebService/SIGB/Nanook/Service.php +++ b/library/Class/WebService/SIGB/Nanook/Service.php @@ -114,7 +114,12 @@ class Class_Webservice_SIGB_Nanook_Service } - /** + protected function _newEmprunteur() : Class_WebService_SIGB_Emprunteur { + return Class_WebService_SIGB_Nanook_Emprunteur::newInstance(); + } + + +/** * @param Class_Users $user * @return Class_WebService_SIGB_Emprunteur */ diff --git a/library/Class/WebService/SIGB/Subscription.php b/library/Class/WebService/SIGB/Subscription.php new file mode 100644 index 0000000000000000000000000000000000000000..96efd25119a39ae62cc28af980ce75d17b9ae1ae --- /dev/null +++ b/library/Class/WebService/SIGB/Subscription.php @@ -0,0 +1,68 @@ +<?php +/** + * Copyright (c) 2012-2022, Agence Française Informatique (AFI). All rights reserved. + * + * BOKEH is free software; you can redistribute it and/or modify + * it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE as published by + * the Free Software Foundation. + * + * There are special exceptions to the terms and conditions of the AGPL as it + * is applied to this software (see README file). + * + * BOKEH is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU AFFERO GENERAL PUBLIC LICENSE for more details. + * + * You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE + * along with BOKEH; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + + +class Class_WebService_SIGB_Subscription { + protected $_id='', + $_label=''; + + public function setId(string $id) :self{ + $this->_id = $id; + return $this; + } + + + public function setLabel(string $label) :self{ + $this->_label = $label; + return $this; + } + + + public function getLabel() :string{ + return $this->_label; + } + + + public function getId() :string{ + return $this->_id; + } + + + public function getStartDate() :string{ + return $this->_start_date; + } + + public function getEndDate() :string{ + return $this->_end_date; + } + + + public function setStartDate(string $start_date) :self{ + $this->_start_date = $start_date; + return $this; + } + + + public function setEndDate(string $end_date) :self{ + $this->_end_date = $end_date; + return $this; + } +} diff --git a/library/Trait/TimeSource.php b/library/Trait/TimeSource.php index 94eca6d4378e5b2121a9e3c9d4c690396dd0f691..03da053e5c87de65e8561d6edc38a8de1a2d1700 100644 --- a/library/Trait/TimeSource.php +++ b/library/Trait/TimeSource.php @@ -31,6 +31,7 @@ trait Trait_TimeSource { return self::getTimeSource()->time(); } + public function getCurrentMicroTime() : float { return self::getTimeSource()->microtime(); } @@ -102,4 +103,10 @@ trait Trait_TimeSource { public static function setTimeSource($time_source) { self::$_time_source = $time_source; } + + + protected function _isDateFormatValid(string $date, string $format) : bool { + $d = DateTime::createFromFormat($format, $date); + return $d && $d->format( $format ) == $date; + } } diff --git a/library/ZendAfi/Controller/Plugin/ResourceDefinition/Membership.php b/library/ZendAfi/Controller/Plugin/ResourceDefinition/Membership.php new file mode 100644 index 0000000000000000000000000000000000000000..e7a91b2fa0a68fa74471dd73ca228641a9df23c7 --- /dev/null +++ b/library/ZendAfi/Controller/Plugin/ResourceDefinition/Membership.php @@ -0,0 +1,36 @@ +<?php +/** + * Copyright (c) 2012-2017, Agence Française Informatique (AFI). All rights reserved. + * + * BOKEH is free software; you can redistribute it and/or modify + * it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE as published by + * the Free Software Foundation. + * + * There are special exceptions to the terms and conditions of the AGPL as it + * is applied to this software (see README file). + * + * BOKEH is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU AFFERO GENERAL PUBLIC LICENSE for more details. + * + * You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE + * along with BOKEH; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + + +class ZendAfi_Controller_Plugin_ResourceDefinition_Membership extends ZendAfi_Controller_Plugin_ResourceDefinition_Abstract { + + public function getDefinitions() { + return ['model' => ['class' => 'Class_Membership', + 'name' => 'membership', + 'order' => 'code', + 'model_id' => 'id'], + + 'actions' => ['index' => ['title' => $this->_('Parcourir les types d\'abonnement')]], + + 'form_class_name' => ZendAfi_Form_Admin_Membership::class]; + } +} +?> diff --git a/library/ZendAfi/Form/Admin/User.php b/library/ZendAfi/Form/Admin/User.php index 9813c54ea0e9dd7e9b9c8dc7be93cc2402fdd76f..fbaf329bc72263c9d15a9b46ed3665b25940256c 100644 --- a/library/ZendAfi/Form/Admin/User.php +++ b/library/ZendAfi/Form/Admin/User.php @@ -289,11 +289,24 @@ class ZendAfi_Form_Admin_User extends ZendAfi_Form { 'end' => ['name' => 'date_fin', 'allowEmpty' => true, 'dateOnly' => true, - 'toggleAllDay' => 'all_day']]) + 'toggleAllDay' => 'all_day']]); + $array_group = ['idabon', + 'ordreabon']; - ->addDisplayGroup(['idabon', - 'ordreabon', - 'subscription_range_date'], + if ($user_memberships = $this->_user->getLastUserMemberships()){ + $this->addElement('userMemberships', + 'subscription_information', + ['label' => $this->_('Abonnement(s) SIGB'), + 'user_memberships' => $user_memberships]); + $array_group []= 'subscription_information'; + } + + $array_group []= 'subscription_range_date'; + + + + $this + ->addDisplayGroup($array_group, 'sigb', ['legend' => $this->_('Abonnement')]); return $this; diff --git a/library/ZendAfi/Form/Decorator/UserMemberships.php b/library/ZendAfi/Form/Decorator/UserMemberships.php new file mode 100644 index 0000000000000000000000000000000000000000..e8f31939867cef9d8b64ccbd1ac715cc91e55f03 --- /dev/null +++ b/library/ZendAfi/Form/Decorator/UserMemberships.php @@ -0,0 +1,34 @@ +<?php +/** + * Copyright (c) 2012, Agence Française Informatique (AFI). All rights reserved. + * + * BOKEH is free software; you can redistribute it and/or modify + * it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE as published by + * the Free Software Foundation. + * + * There are special exceptions to the terms and conditions of the AGPL as it + * is applied to this software (see README file). + * + * BOKEH is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU AFFERO GENERAL PUBLIC LICENSE for more details. + * + * You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE + * along with BOKEH; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +class ZendAfi_Form_Decorator_UserMemberships extends Zend_Form_Decorator_Abstract { + /** + * @param string $content + * @return string + */ + public function render($content) { + if (! $this->_element->user_memberships) + return $content; + return $content. + $this->_element->getView()->renderUserMemberships($this->_element->user_memberships); + + } +} diff --git a/library/ZendAfi/Form/Element/UserMemberships.php b/library/ZendAfi/Form/Element/UserMemberships.php new file mode 100644 index 0000000000000000000000000000000000000000..2f75a137132bba0034a708ea9b7203be7f0f460c --- /dev/null +++ b/library/ZendAfi/Form/Element/UserMemberships.php @@ -0,0 +1,34 @@ +<?php +/** + * Copyright (c) 2012-2022, Agence Française Informatique (AFI). All rights reserved. + * + * BOKEH is free software; you can redistribute it and/or modify + * it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE as published by + * the Free Software Foundation. + * + * There are special exceptions to the terms and conditions of the AGPL as it + * is applied to this software (see README file). + * + * BOKEH is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU AFFERO GENERAL PUBLIC LICENSE for more details. + * + * You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE + * along with BOKEH; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + + +class ZendAfi_Form_Element_UserMemberships extends Zend_Form_Element_Xhtml { + public function __construct($spec, $options = null) { + parent::__construct($spec, $options); + $decorators = $this->_decorators; + $this->_decorators = ['UserMemberships' => new ZendAfi_Form_Decorator_UserMemberships()]; + + foreach ($decorators as $name => $value) + $this->_decorators[$name] = $value; + + $this->removeDecorator('ViewHelper'); + } +} diff --git a/library/ZendAfi/View/Helper/Admin/SearchUsers.php b/library/ZendAfi/View/Helper/Admin/SearchUsers.php index b94ff46eeec0abcf066ad359ef98d98ebf5916c6..f09493c922537b57003023648be9dd3a570e32de 100644 --- a/library/ZendAfi/View/Helper/Admin/SearchUsers.php +++ b/library/ZendAfi/View/Helper/Admin/SearchUsers.php @@ -24,7 +24,7 @@ class ZendAfi_View_Helper_Admin_SearchUsers extends ZendAfi_View_Helper_Admin_Search { protected - $_table_description_class = 'Class_TableDescription_Users', + $_table_description_class = Class_TableDescription_Users::class, $_table_id = 'users_table', $_with_delete; @@ -74,4 +74,4 @@ class ZendAfi_View_Helper_Admin_SearchUsers return http_build_query($params); } -} \ No newline at end of file +} diff --git a/library/ZendAfi/View/Helper/RenderUserMembership.php b/library/ZendAfi/View/Helper/RenderUserMembership.php new file mode 100644 index 0000000000000000000000000000000000000000..d0c6daf7cef237dd3d9959b97f73713e78f6a8f4 --- /dev/null +++ b/library/ZendAfi/View/Helper/RenderUserMembership.php @@ -0,0 +1,39 @@ +<?php +/** + * Copyright (c) 2012-2022, Agence Française Informatique (AFI). All rights reserved. + * + * BOKEH is free software; you can redistribute it and/or modify + * it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE as published by + * the Free Software Foundation. + * + * There are special exceptions to the terms and conditions of the AGPL as it + * is applied to this software (see README file). + * + * BOKEH is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU AFFERO GENERAL PUBLIC LICENSE for more details. + * + * You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE + * along with BOKEH; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + + +class ZendAfi_View_Helper_RenderUserMembership extends ZendAfi_View_Helper_BaseHelper { + public function renderUserMembership(Class_User_Membership $user_membership) { + $string_date = $this->_('du ') + . Class_Date::human($user_membership->getStartDate()); + $string_date .= ($user_membership->getEndDate()) + ? $this->_(' au ').Class_Date::human($user_membership->getEndDate()) + :''; + + $html= [$this->_tag('strong', + $user_membership->getMembership()->getLibelle()), + $this->_tag('span', + $string_date + ) + ]; + return $this->_tag('p',implode(" ",$html)); + } +} diff --git a/library/ZendAfi/View/Helper/RenderUserMemberships.php b/library/ZendAfi/View/Helper/RenderUserMemberships.php new file mode 100644 index 0000000000000000000000000000000000000000..bbfe3a3d4e057e65eb035a50b8dd0c95f1e9c2b3 --- /dev/null +++ b/library/ZendAfi/View/Helper/RenderUserMemberships.php @@ -0,0 +1,34 @@ +<?php +/** + * Copyright (c) 2012-2022, Agence Française Informatique (AFI). All rights reserved. + * + * BOKEH is free software; you can redistribute it and/or modify + * it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE as published by + * the Free Software Foundation. + * + * There are special exceptions to the terms and conditions of the AGPL as it + * is applied to this software (see README file). + * + * BOKEH is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU AFFERO GENERAL PUBLIC LICENSE for more details. + * + * You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE + * along with BOKEH; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + + +class ZendAfi_View_Helper_RenderUserMemberships extends ZendAfi_View_Helper_BaseHelper { + public function renderUserMemberships(array $user_memberships) { + if (!$user_memberships) + return ''; + + return implode( array_map(function($user_membership){ + return ($user_membership instanceOf Class_User_Membership) + ? $this->view->renderUserMembership($user_membership) + :'';}, + $user_memberships) ); + } +} diff --git a/library/ZendAfi/View/Helper/TagListeCoches.php b/library/ZendAfi/View/Helper/TagListeCoches.php index 40988079d8ab118cd4e03134b846df0781865696..ef2d9797cb9c23b8662e0f6e70e8b5756bd9fce3 100644 --- a/library/ZendAfi/View/Helper/TagListeCoches.php +++ b/library/ZendAfi/View/Helper/TagListeCoches.php @@ -23,7 +23,9 @@ class ZendAfi_View_Helper_TagListeCoches extends ZendAfi_View_Helper_BaseHelper const SOURCE_TYPE_DOC = 'type_doc', SOURCE_GENRE_PNB = 'genre_pnb', - SOURCE_SECTION_PNB = 'section_pnb'; + SOURCE_SECTION_PNB = 'section_pnb', + SOURCE_TARIF = 'membership'; + protected $selected_all_means_nothing = true, $_name, @@ -82,7 +84,8 @@ class ZendAfi_View_Helper_TagListeCoches extends ZendAfi_View_Helper_BaseHelper ->setWhere(array_filter(['id_bib' => $library_id, 'invisible' => 0])), - 'profile' => new ZendAfi_View_Helper_TagListeCochesSourceProfile() + 'profile' => new ZendAfi_View_Helper_TagListeCochesSourceProfile(), + STATIC::SOURCE_TARIF => new ZendAfi_View_Helper_TagListeCochesSourceMembership(), ]; return array_key_exists($data, $datas) @@ -178,7 +181,6 @@ class ZendAfi_View_Helper_TagListeCoches extends ZendAfi_View_Helper_BaseHelper if (!$values) return $this; - $codes = array_filter(preg_split('/[-;,]/', $values)); foreach($codes as $code) $this->_handleValue($code); @@ -208,6 +210,8 @@ class ZendAfi_View_Helper_TagListeCoches extends ZendAfi_View_Helper_BaseHelper class ZendAfi_View_Helper_TagListeCochesSource extends Class_Entity { + use Trait_Translator; + public function __construct($model) { $this->setModelClass($model); } @@ -270,7 +274,6 @@ class ZendAfi_View_Helper_TagListeCochesSourceDocType extends ZendAfi_View_Helpe class ZendAfi_View_Helper_TagListeCochesSourceProfile extends ZendAfi_View_Helper_TagListeCochesSource { - use Trait_Translator; public function __construct() { parent::__construct('Class_Profil'); @@ -324,3 +327,28 @@ class ZendAfi_View_Helper_TagListeCochesSourcePnb extends ZendAfi_View_Helper_Ta Class_Album::findAllDilicom()); } } + + + + +class ZendAfi_View_Helper_TagListeCochesSourceMembership extends ZendAfi_View_Helper_TagListeCochesSource { + public function __construct() { + parent::__construct(Class_Membership::class); + } + + + protected function getKey($instance) { + return $instance->getId() ?? 'ignore'; + } + + + protected function getInstances() { + $instances = parent::getInstances(); + + array_unshift($instances, + (new Class_Membership) + ->setCode('ignore') + ->setLibelle( $this->_('Non Renseigné'))); + return $instances; + } +} diff --git a/library/templates/Intonation/Library/Styles.php b/library/templates/Intonation/Library/Styles.php index 333cf4fe501b6cd89727e4033bd0e928d256d54e..6c45da86cf234dae502c8d4229eba7561bed2fcf 100644 --- a/library/templates/Intonation/Library/Styles.php +++ b/library/templates/Intonation/Library/Styles.php @@ -22,6 +22,10 @@ class Intonation_Library_Styles { protected $_template; + const CSS_DANGER='danger'; + const CSS_WARNING='warning'; + const CSS_SUCCESS='success'; + public function __construct($template) { $this->_template = $template; diff --git a/library/templates/Intonation/Library/View/Wrapper/PNBLoan.php b/library/templates/Intonation/Library/View/Wrapper/PNBLoan.php index 78325d92efdbea0017e43e3d1d529e239bbf1275..61c7b9421600b4d869eaf6be05cee393716ce5f0 100644 --- a/library/templates/Intonation/Library/View/Wrapper/PNBLoan.php +++ b/library/templates/Intonation/Library/View/Wrapper/PNBLoan.php @@ -47,8 +47,8 @@ class Intonation_Library_View_Wrapper_PNBLoan extends Intonation_Library_View_Wr ((new Intonation_Library_Badge) ->setTag('span') ->setClass(($this->_model->isLate() - ? 'danger' - : 'success')) + ? Intonation_Library_Styles::CSS_WARNING + : Intonation_Library_Styles::CSS_SUCCESS)) ->setImage(Class_Template::current()->getIco($this->_view, 'return-date', 'library')) diff --git a/library/templates/Intonation/Library/View/Wrapper/User.php b/library/templates/Intonation/Library/View/Wrapper/User.php index 9de43130a8f0fe490add097186ad1a0da0780062..9a86a624b4d4f0bd3292601e3e7cc45141adc99b 100644 --- a/library/templates/Intonation/Library/View/Wrapper/User.php +++ b/library/templates/Intonation/Library/View/Wrapper/User.php @@ -130,28 +130,8 @@ class Intonation_Library_View_Wrapper_User extends Intonation_Library_View_Wrapp ->setTitle($this->_('Votre numéro de carte %s', $card_number))); - $validity_date = (new DateTime($this->_model->getDateFin()))->format($this->_('d/m/Y')); - $subscription = (new Class_User_ILSSubscription($this->_model)); - $this->_model_validity = $subscription->isValid(); - $validity_class = $this->_model_validity - ? 'success' - : 'danger'; - - $validity_class = $subscription->isAboutToExpire() - ? 'warning' - : $validity_class; - - if ($this->_model->getDateFin()) - $badges [] = ((new Intonation_Library_Badge) - ->setTag('span') - ->setClass($validity_class) - ->setImage(Class_Template::current() - ->getIco($this->_view, - 'subscription', - 'library')) - ->setText($validity_date) - ->setTitle($this->_('Vous êtes abonné(e) jusqu\'au %s', - $validity_date))); + $badges=[...$badges, ...array_filter($this->_subscriptionBadges($this->_model))]; + if ($number_of_loans = $cards->getLoansCount()) $badges [] = ((new Intonation_Library_Badge) @@ -262,6 +242,18 @@ class Intonation_Library_View_Wrapper_User extends Intonation_Library_View_Wrapp } + protected function _subscriptionBadges(object $user) : array { + + return array_map(function($element){ + return $this->_view->abonne_ILSSubscriptionsBadge(Class_User_ILSSubscription::newFor($element)); + }, + ($user_memberships = $user->getUserMemberships()) + ? $user_memberships + : [$user] + ); + } + + public function getActions() { return [(new Intonation_Library_Link) ->setUrl($this->_view->url(['controller' => 'abonne', diff --git a/library/templates/Intonation/View/Abonne/ILSSubscriptionsBadge.php b/library/templates/Intonation/View/Abonne/ILSSubscriptionsBadge.php new file mode 100644 index 0000000000000000000000000000000000000000..8c0b5b9c2c569857dfe373c82ae346ba4fbd7b8f --- /dev/null +++ b/library/templates/Intonation/View/Abonne/ILSSubscriptionsBadge.php @@ -0,0 +1,44 @@ +<?php +/** + * Copyright (c) 2012-2022, Agence Française Informatique (AFI). All rights reserved. + * + * BOKEH is free software; you can redistribute it and/or modify + * it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE as published by + * the Free Software Foundation. + * + * There are special exceptions to the terms and conditions of the AGPL as it + * is applied to this software (see README file). + * + * BOKEH is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU AFFERO GENERAL PUBLIC LICENSE for more details. + * + * You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE + * along with BOKEH; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + + +class Intonation_View_Abonne_ILSSubscriptionsBadge extends ZendAfi_View_Helper_BaseHelper { + public function abonne_ILSSubscriptionsBadge(Class_User_ILSSubscription $subscription) : ?Intonation_Library_Badge { + if (!$subscription->isDisplayed() ||!$subscription->getDateFin()) + return null; + + $validity_date = $subscription->validityDate(); + + return (new Intonation_Library_Badge) + ->setTag('span') + ->setClass(sprintf('%s subscription',$subscription->validityClass())) + ->setImage(Class_Template::current() + ->getIco($this->view, + 'subscription', + 'library')) + ->setText($subscription->getBadgeLabel() + .$validity_date) + ->setTitle($this->_('Vous êtes %s jusqu\'au %s', + $subscription->getLibelle(), + $validity_date)); + + } +} diff --git a/library/templates/Intonation/View/User/Informations.php b/library/templates/Intonation/View/User/Informations.php index e26f050d6dbb950794e14aa4a58a12d1881f7a3b..b8abdd28b777bede71fca2bcb433d82742082c11 100644 --- a/library/templates/Intonation/View/User/Informations.php +++ b/library/templates/Intonation/View/User/Informations.php @@ -105,9 +105,12 @@ class Intonation_View_User_Informations extends ZendAfi_View_Helper_BaseHelper { : ''), $this->_('Numéro de carte') => $user->getIdabon(), - $this->_('Bibliothèque') => $this->_getLibrary($user), + $this->_('Bibliothèque') => $this->_getLibrary($user) ]; + if ($user_memberships = $user->getLastUserMemberships()) + $map [$this->_('Abonnements')] = $this->_getAbonnements($user_memberships); + $html = []; foreach ($map as $label => $value) { @@ -129,4 +132,30 @@ class Intonation_View_User_Informations extends ZendAfi_View_Helper_BaseHelper { ['title' => $this->_('En lire plus sur %s', $library->getLibelle())]); } + + protected function _getAbonnements(array $user_memberships) :string { + return implode('',array_map( + function ($user_membership){ + $membership_libelle = $user_membership + ->getMembership() + ->getLibelle(); + $date_string = $this->_(' du %s', + Class_Date::human($user_membership->getStartDate())); + $date_string .= ($user_membership->getEndDate()) + ? $this->_(' au %s', + Class_Date::human($user_membership->getEndDate())) + :''; + return $this->view->tag('p', + $this->view->tag('strong', + $membership_libelle) + . $this->view->tag('span', + $date_string + ), + ['class' => 'subscription-information user_info', + 'title' => $this->_('Vous êtes "%s" jusqu\'au %s', + $membership_libelle, + Class_Date::human($user_membership->getEndDate()))]); + }, + $user_memberships)); + } } diff --git a/tests/application/modules/admin/controllers/UserGroupControllerTest.php b/tests/application/modules/admin/controllers/UserGroupControllerTest.php index 2c4dc18976029c506304c91189aca3ef65764596..fcd0e60a31d4f88d3d1adccf3cbc434492757989 100644 --- a/tests/application/modules/admin/controllers/UserGroupControllerTest.php +++ b/tests/application/modules/admin/controllers/UserGroupControllerTest.php @@ -1675,3 +1675,376 @@ class Admin_UserGroupControllerIndexWithSystemGroupsTest $this->assertNotNull(Class_UserGroup::find(2)); } } + + + + +abstract class Admin_UserGroupControllerSelectionWithMembershipTestCase extends Admin_UserGroupControllerTestCase { + protected $_group = null; + public function setUp() { + parent::setUp(); + + Class_User_Membership::setTimesource(new TimeSourceForTest('2022-12-25 00:00:01')); + Class_User_SearchCriteria_EndSubscriptionDate::setTimesource(new TimeSourceForTest('2022-12-25 02:01:01')); + Class_User_SearchCriteria_DateFin::setTimesource(new TimeSourceForTest('2022-12-25 00:00:01')); + $this->fixture(Class_IntBib::class, + ['id' => 100, + 'sigb' => Class_IntBib::SIGB_NANOOK, + 'comm_sigb' => Class_IntBib::COM_NANOOK, + 'comm_params' => ['url_serveur' => 'https://mynanook.org']]); + + $this->_prepareMemberships(); + + $this->_prepareDispatch(); + + $this->_group = Class_UserGroup::find(7); + $this->_group->cleanCriteriaCache(); + } + + protected function _prepareMemberships(){ + $this->_batman->setRoleLevel(ZendAfi_Acl_AdminControllerRoles::ABONNE_SIGB); + + $this->fixture(Class_Membership::class, + ['id' => 2, + 'libelle' => 'Abonné Adulte Interne', + 'enabled' => 1, + ]); + + $this->fixture(Class_User_Membership::class, + ['id' => 1, + 'user_id' => 31, + 'membership_id' => 2, + 'start_date' => '2022-01-01', + 'end_date' => '2023-01-01', + ]); + + $this->fixture(Class_Users::class, + ['id' => 23, + 'nom' => 'logan', + 'prenom' => 'Wolverine', + 'bib' => Class_Bib::find(9), + 'password' => '123', + 'login' => '0123', + 'idabon' => '12344', + 'role_level' => ZendAfi_Acl_AdminControllerRoles::ABONNE_SIGB]); + + $this->fixture(Class_User_Membership::class, + ['id' => 2, + 'user_id' => 23, + 'membership_id' => 2, + 'start_date' => '2022-01-01', + 'end_date' => '2022-12-01', + ]); + + $this->fixture(Class_Users::class, + ['id' => 24, + 'nom' => 'Tony', + 'prenom' => 'Stark', + 'bib' => Class_Bib::find(9), + 'password' => '123', + 'login' => '0124', + 'idabon' => '12345', + 'role_level' => ZendAfi_Acl_AdminControllerRoles::ABONNE_SIGB]); + + $this->fixture(Class_User_Membership::class, + ['id' => 3, + 'user_id' => 24, + 'membership_id' => 2, + 'start_date' => '2023-12-01', + 'end_date' => '2023-12-02', + ]); + + $this->fixture(Class_User_Membership::class, + ['id' => 4, + 'user_id' => 24, + 'membership_id' => 2, + 'date_debut' => '2022-12-01', + 'date_fin' => '2022-12-25', + ]); + + $this->fixture(Class_Users::class, + ['id' => 25, + 'nom' => 'Red', + 'prenom' => 'Richards', + 'bib' => Class_Bib::find(9), + 'password' => '123', + 'login' => '0125', + 'idabon' => '12346', + 'role_level' => ZendAfi_Acl_AdminControllerRoles::ABONNE_SIGB]); + + $this->fixture(Class_User_Membership::class, + ['id' => 5, + 'user_id' => 25, + 'membership_id' => 2, + 'start_date' => '2023-12-01', + 'end_date' => '', + ]); + + } + + + protected function _prepareDispatch(){ + } + + public function tearDown(){ + Class_User_Membership::setTimesource(null); + Class_User_SearchCriteria_EndSubscriptionDate::setTimesource(null); + Class_User_SearchCriteria_DateFin::setTimesource(null); + parent::tearDown(); + } +} + + + + +class Admin_UserGroupControllerEditPostMembershipSelectionTest + extends Admin_UserGroupControllerSelectionWithMembershipTestCase { + + protected function _prepareDispatch(){ + $this->postDispatch('admin/usergroup/edit/id/7', + ['libelle' => 'Abonné Adultes', + 'search_membership' => '2']); + } + + + /** @test */ + public function groupeNewLibelleShouldBeAbonneAdultes() { + $this->assertEquals('Abonné Adultes', $this->_group->getLibelle()); + } + + + /** @test */ + public function group7ShouldHaveUserBatman() { + $this->assertTrue($this->_group->hasUser($this->_batman)); + } + + + /** @test */ + public function group7ShouldNotHaveUserSpiderman() { + $this->assertFalse($this->_group->hasUser($this->_spiderman)); + } + + + public function getUsersIdAndReturn(){ + return [['23'], + ['24'], + ['25']]; + } + + + /** @test + * @dataProvider getUsersIdAndReturn + */ + public function group7ShouldHaveUserIdentified($userid) { + $this->assertTrue($this->_group->hasUser(Class_Users::find($userid))); + } + + + /** @test */ + public function responseShouldRedirectToEdit() { + $this->assertRedirectTo(Class_Url::absolute('/admin/usergroup/edit/id/7')); + } + + + /** @test */ + public function shouldNotifySave() { + $this->assertFlashMessengerContentContains('Groupe "Abonné Adultes" sauvegardé'); + } +} + + + + +class Admin_UserGroupControllerEditPostMembershipWithIgnoreSelectionTest + extends Admin_UserGroupControllerSelectionWithMembershipTestCase { + + protected function _prepareDispatch(){ + $this->postDispatch('admin/usergroup/edit/id/7', + ['libelle' => 'Abonné Adultes', + 'search_membership' => '2;ignore']); + } + + + /** @test */ + public function groupeNewLibelleShouldBeAbonneAdultes() { + $this->assertEquals('Abonné Adultes', $this->_group->getLibelle()); + } + + + /** @test */ + public function group7ShouldHaveUserBatman() { + $this->assertTrue($this->_group->hasUser($this->_batman)); + } + + + /** @test */ + public function group7ShouldHaveUserSpiderman() { + $this->assertTrue($this->_group->hasUser($this->_spiderman)); + } + + + public function getUsersIdAndReturn(){ + return [['23'], + ['24'], + ['25']]; + } + + + /** @test + * @dataProvider getUsersIdAndReturn + */ + public function group7ShouldHaveUserIdentified($userid) { + $this->assertTrue($this->_group->hasUser(Class_Users::find($userid))); + } + + + /** @test */ + public function responseShouldRedirectToEdit() { + $this->assertRedirectTo(Class_Url::absolute('/admin/usergroup/edit/id/7')); + } + + + /** @test */ + public function shouldNotifySave() { + $this->assertFlashMessengerContentContains('Groupe "Abonné Adultes" sauvegardé'); + } +} + + + + +class Admin_UserGroupControllerEditPostValidSubscriptionWithMembershipTest + extends Admin_UserGroupControllerSelectionWithMembershipTestCase { + + protected function _prepareDispatch(){ + $this->postDispatch('admin/usergroup/edit/id/7', + ['libelle' => 'Abonné Adultes', + 'search_valid_subscription' => 1]); + } + + + /** @test */ + public function groupeNewLibelleShouldBeAbonneAdultes() { + $this->assertEquals('Abonné Adultes', $this->_group->getLibelle()); + } + + + /** @test */ + public function group7ShouldHaveUserBatman() { + $this->assertTrue($this->_group->hasUser($this->_batman)); + } + + + /** @test */ + public function group7ShouldHaveUserSpiderman() { + $this->assertTrue($this->_group->hasUser($this->_spiderman)); + } + + + /** @test */ + public function responseShouldRedirectToEdit() { + $this->assertRedirectTo(Class_Url::absolute('/admin/usergroup/edit/id/7')); + } + + + /** @test */ + public function shouldNotifySave() { + $this->assertFlashMessengerContentContains('Groupe "Abonné Adultes" sauvegardé'); + } +} + + + + +class Admin_UserGroupControllerEditPostEndSubscriptionWithMembershipTest + extends Admin_UserGroupControllerSelectionWithMembershipTestCase { + + protected function _prepareDispatch(){ + $this->postDispatch('admin/usergroup/edit/id/7', + ['libelle' => 'Abonnement expire dans 12 jours', + 'search_role_level' => 2, + 'search_end_subscription_days' => 12]); + } + + + /** @test */ + public function groupeNewLibelleShouldBeAbonnementExpireDans() { + $this->assertEquals('Abonnement expire dans 12 jours', $this->_group->getLibelle()); + } + + + /** @test */ + public function group7ShouldHaveUserBatman() { + $this->assertTrue($this->_group->hasUser($this->_batman)); + } + + + /** @test */ + public function group7ShouldNotHaveUserSpiderman() { + $this->assertFalse($this->_group->hasUser($this->_spiderman)); + } + + + public function getUsersId(){ + return [['23'], + ['24'], + ['25']]; + } + + + /** @test + * @dataProvider getUsersId + */ + public function group7ShouldNotHaveUserIdentified($userid) { + $this->assertFalse($this->_group->hasUser(Class_Users::find($userid))); + } +} + + + + +class Admin_UserGroupControllerEditPostDateFinWithMembershipTest + extends Admin_UserGroupControllerSelectionWithMembershipTestCase { + + protected function _prepareDispatch(){ + $this->postDispatch('admin/usergroup/edit/id/7', + ['libelle' => 'Abonnement expire entre le 1er et le 10 janvier', + 'search_role_level' => 2, + 'search_date_fin_end' => '10/01/2023', + 'search_date_fin_start' => '01/01/2023']); + } + + + /** @test */ + public function groupeNewLibelleShouldBeAbonnementExpireDans() { + $this->assertEquals('Abonnement expire entre le 1er et le 10 janvier', $this->_group->getLibelle()); + } + + + /** @test */ + public function group7ShouldHaveUserBatman() { + $this->assertTrue($this->_group->hasUser($this->_batman)); + } + + + /** @test */ + public function group7ShouldNotHaveUserSpiderman() { + $this->assertFalse($this->_group->hasUser($this->_spiderman)); + } + + + public function getUsersId(){ + return [['23'], +# ['24'], + // ['25'] + ]; + } + + + /** @test + * @dataProvider getUsersId + */ + public function group7ShouldNotHaveUserIdentified($userid) { + $this->assertFalse($this->_group->hasUser(Class_Users::find($userid))); + } +} diff --git a/tests/application/modules/admin/controllers/UsersControllerTest.php b/tests/application/modules/admin/controllers/UsersControllerTest.php index da54fa4325385c6c785a6070e6375ff0dbc87e8e..2a915b3bd6387e2003cbc93c0c21b7374b83fb3f 100644 --- a/tests/application/modules/admin/controllers/UsersControllerTest.php +++ b/tests/application/modules/admin/controllers/UsersControllerTest.php @@ -22,6 +22,7 @@ abstract class UsersControllerWithMarcusTestCase extends AbstractControllerTestCase { protected $_storm_default_to_volatile = true; + protected $_intbib; public function setUp() { @@ -74,14 +75,20 @@ abstract class UsersControllerWithMarcusTestCase extends AbstractControllerTestC 'last_login' => null, 'civilite' => Class_Users::CIVILITE_MONSIEUR]); + $this->_setIntBib(); $this->marcus->setFicheSIGB(['type_comm' => 0]) ->setUserGroups([$group_vodeclic,$group_referent]) - ->setIntBib($this->fixture('Class_IntBib', ['id' => 100, 'comm_sigb' => 0])); + ->setIntBib($this->_intbib); $this->user_loader = $this->onLoaderOfModel(Class_Users::class); } + protected function _setIntBib(){ + $this->_intbib = $this->fixture(Class_IntBib::class, ['id' => 100, 'comm_sigb' => 0]); + } + + protected function _postEditData($data) { $this ->getRequest() @@ -106,18 +113,36 @@ abstract class UsersControllerIndexTestCase extends UsersControllerWithMarcusTes Class_User_SearchCriteria_Age::setTimeSource($time_source); Class_AdminVar::set('ENABLED_SEARCH_USER_AGE',1); - Zend_Registry::set('sql', $this->mock() - ->whenCalled('fetchAll') - ->with('select min(id_user) as id_user, login, idabon, ordreabon, password, count(*) as doublon from bib_admin_users where role_level = 2 and id_user > 0 group by login, idabon, ordreabon, password having doublon > 1 order by id_user asc') - ->answers([]) + $this->fixture(Class_Membership::class, + ['id' => 1, + 'code' => 1, + 'libelle' => 'Abonné Adulte Interne' + ]); - ->whenCalled('fetchAll') - ->with('select idabon, count(*) as doublon from bib_admin_users where role_level = ' . $this->_role_level . ' group by idabon having doublon > 1;') - ->answers([]) + $this->fixture(Class_User_Membership::class, + ['id' => 1, + 'membership_id' => 1, + 'user_id' => 10, + 'start_date' => '2012-01-01', + 'end_date' => '2013-01-01' + ]); - ->whenCalled('fetchAllByColumn') - ->with('select distinct(id_user) as id from notices_avis') - ->answers([2233, 987398])); + $sql_mock = $this + ->mock() + ->whenCalled('fetchAll') + ->with('select min(id_user) as id_user, login, idabon, ordreabon, password, count(*) as doublon from bib_admin_users where role_level = 2 and id_user > 0 group by login, idabon, ordreabon, password having doublon > 1 order by id_user asc') + ->answers([]) + + ->whenCalled('fetchAll') + ->with('select idabon, count(*) as doublon from bib_admin_users where role_level = ' . $this->_role_level . ' group by idabon having doublon > 1;') + ->answers([]) + + ->whenCalled('fetchAllByColumn') + ->with('select distinct(id_user) as id from notices_avis') + ->answers([2233, 987398]); + + + Zend_Registry::set('sql', $sql_mock); $user = $this->fixture(Class_Users::class, ['id' => 1, @@ -132,8 +157,10 @@ abstract class UsersControllerIndexTestCase extends UsersControllerWithMarcusTes 'password' => 'francis', 'last_login' => 0]); - $borrower_birthdate = (in_array($this->_role_level, [1,2])) - ? '(STR_TO_DATE(date_fin, \'%Y-%m-%d\') >= CURDATE()) AND ' + $borrower_validSubscription = (in_array($this->_role_level, [1,2])) + ? (Class_IntBib::isSingleNanook() + ? '(id_user IN (select user_id from user_membership where CURDATE() <= user_membership.end_date)) AND ' + : '(STR_TO_DATE(date_fin, \'%Y-%m-%d\') >= CURDATE()) AND ') : ''; $this->onLoaderOfModel(Class_Users::class) @@ -163,14 +190,14 @@ abstract class UsersControllerIndexTestCase extends UsersControllerWithMarcusTes ->whenCalled('findAllBy') ->with(['role_level' => (string) $this->_role_level, 'order' => 'nom asc', - 'where' => $borrower_birthdate . '(naissance <=\'2002-02-01\') AND (naissance >=\'1913-02-01\') AND (id_user in (2233,987398)) AND (login LIKE "%francis%" OR nom LIKE "%francis%" OR prenom LIKE "%francis%" OR pseudo LIKE "%francis%" OR mail LIKE "%francis%" OR idabon LIKE "%francis%") AND (role_level <= 7)', + 'where' => $borrower_validSubscription . '(naissance <=\'2002-02-01\') AND (naissance >=\'1913-02-01\') AND (id_user in (2233,987398)) AND (login LIKE "%francis%" OR nom LIKE "%francis%" OR prenom LIKE "%francis%" OR pseudo LIKE "%francis%" OR mail LIKE "%francis%" OR idabon LIKE "%francis%") AND (role_level <= 7)', 'limitPage' => [1, 20]]) ->answers([$francis]) ->whenCalled('countBy') ->with(['role_level' => (string) $this->_role_level, 'order' => 'nom asc', - 'where' => $borrower_birthdate . '(naissance <=\'2002-02-01\') AND (naissance >=\'1913-02-01\') AND (id_user in (2233,987398)) AND (login LIKE "%francis%" OR nom LIKE "%francis%" OR prenom LIKE "%francis%" OR pseudo LIKE "%francis%" OR mail LIKE "%francis%" OR idabon LIKE "%francis%") AND (role_level <= 7)']) + 'where' => $borrower_validSubscription . '(naissance <=\'2002-02-01\') AND (naissance >=\'1913-02-01\') AND (id_user in (2233,987398)) AND (login LIKE "%francis%" OR nom LIKE "%francis%" OR prenom LIKE "%francis%" OR pseudo LIKE "%francis%" OR mail LIKE "%francis%" OR idabon LIKE "%francis%") AND (role_level <= 7)']) ->answers(55) ->whenCalled('findAllBy') @@ -185,6 +212,13 @@ abstract class UsersControllerIndexTestCase extends UsersControllerWithMarcusTes $this->dispatch('/admin/users?search_id_site=all&search_role_level=' . $this->_role_level . '&search_age_debut=10&search_age_fin=99&search_valid_subscription=1&search_review=1&search_search_for=\"\'fra"n\'cis"'); } + + public function tearDown(){ + Zend_Registry::set('sql', null); + Class_User_SearchCriteria_Age::setTimeSource(null); + Class_AdminVar::set('ENABLED_SEARCH_USER_AGE',0); + parent::tearDown(); + } } @@ -194,7 +228,6 @@ class UsersControllerIndexSearchRoleLevelBorowersTest extends UsersControllerInd protected $_role_level = 2; - /** @test */ public function formShouldContainsTextSearch() { $this->assertXPath('//input[@name="search_search_for"]'); @@ -233,6 +266,29 @@ class UsersControllerIndexSearchRoleLevelBorowersTest extends UsersControllerInd } + /** @test */ + public function formShouldNotContainsMembershipDropDown() { + $this->assertNotXPathContentContains('//label[@data-name="search_membership"]', + "Type d'abonnement"); + } + + + /** @test */ + public function formMulticheckboxDropdownMembershipShouldNotContainsMembershipNonRenseigne() { + $this->assertNotXPathContentContains('//div[@id="search_membership_saisie"]', + 'Non Renseigné<br/>'); + $this->assertNotXPath('//input[@type="checkbox"][@clef="ignore"]'); + } + + + /** @test */ + public function formMulticheckboxDropdownMembershipShouldNotContainsMembershipAbonneInterne() { + $this->assertNotXPathContentContains('//div[@id="search_membership_saisie"]', + 'Abonné Adulte Interne<br/>'); + $this->assertNotXPath('//input[@type="checkbox"][@clef="1"]'); + } + + /** @test */ public function formShouldContainsInLastExportSelect() { $this->assertXPathContentContains('//select[@name="search_statut"]//option[@value="all"]', @@ -285,7 +341,8 @@ class UsersControllerIndexSearchRoleLevelBorowersTest extends UsersControllerInd /** @test */ public function jsToogleVisibilityForRoleLevelBorrowersShouldBeForStatut() { - $this->assertXPathContentContains('//script', 'formSelectToggleVisibilityForElement("#search_role_level", $("#search_statut").closest("tr"), ["2"]);'); + $this->assertXPathContentContains('//script', + 'formSelectToggleVisibilityForElement("#search_role_level", $("#search_statut").closest("tr"), ["2"]);'); } @@ -317,6 +374,57 @@ class UsersControllerIndexSearchRoleLevelBorowersTest extends UsersControllerInd + +class UsersControllerIndexSearchRoleLevelAbonneWithNanookUniqueTest extends UsersControllerIndexTestCase { + + protected $_role_level = 2; + + protected function _setIntBib(){ + $this->_intbib = $this->fixture(Class_IntBib::class, + ['id' => 100, + 'sigb' => Class_IntBib::SIGB_NANOOK, + 'comm_sigb' => Class_IntBib::COM_NANOOK, + 'comm_params' => ['url_serveur' => 'https://mynanook.org']]); + } + + + /** @test */ + public function singleNanookShouldBeTrue() { + $this->assertEquals(1,Class_IntBib::isSingleNanook()); + } + + /** @test */ + public function formShouldContainsMembershipDropDown() { + $this->assertXPathContentContains('//label[@data-name="search_membership"]', + "Type d'abonnement"); + } + + + /** @test */ + public function formMulticheckboxDropdownMembershipShouldContainsMembershipNonRenseigne() { + $this->assertXPathContentContains('//div[@id="search_membership_saisie"]', + 'Non Renseigné<br/>'); + $this->assertXPath('//input[@type="checkbox"][@clef="ignore"]'); + } + + + /** @test */ + public function formMulticheckboxDropdownMembershipShouldContainsMembershipAbonneInterne() { + $this->assertXPathContentContains('//div[@id="search_membership_saisie"]', + 'Abonné Adulte Interne<br/>'); + $this->assertXPath('//input[@type="checkbox"][@clef="1"]'); + } + + + /** @test */ + public function jsToogleVisibilityForRoleLevelBorrowersShouldBeForStatut() { + $this->assertXPathContentContains('//script', + 'formSelectToggleVisibilityForElement("#search_role_level", $("#search_statut,#search_membership").closest("tr"), ["2"]);'); + } +} + + + class UsersControllerIndexSearchRoleLevelGuestTest extends UsersControllerIndexTestCase { protected $_role_level = 0; @@ -1961,25 +2069,25 @@ class UsersControllerManageDoubleUserTest extends UsersControllerDoubleTestCase /** @test */ public function buttonMergeShouldBe654to25() { - $this->assertXpath('//button[contains(@onclick, "/admin/users/manage-double-merge/id_user/25/id_user_to/25/id_user_from/654")]',$this->_response->getBody()); + $this->assertXpath('//button[contains(@onclick, "/admin/users/manage-double-merge/id_user/25/id_user_to/25/id_user_from/654")]'); } /** @test */ public function buttonMergeShouldBe25to654() { - $this->assertXpath('//button[contains(@onclick, "/admin/users/manage-double-merge/id_user/25/id_user_to/654/id_user_from/25_655")]',$this->_response->getBody()); + $this->assertXpath('//button[contains(@onclick, "/admin/users/manage-double-merge/id_user/25/id_user_to/654/id_user_from/25_655")]'); } /** @test */ public function buttonIgnoreAndContinueShouldHaveUserId2() { - $this->assertXpath('//button[contains(@onclick, "/admin/users/manage-double-user/id_user/2")]',$this->_response->getBody()); + $this->assertXpath('//button[contains(@onclick, "/admin/users/manage-double-user/id_user/2")]'); } /** @test */ public function buttonPreviousShouldNotBeAvailable() { - $this->assertXpathContentContains('//button[contains(@disabled, "disabled")]','Précédent',$this->_response->getBody()); + $this->assertXpathContentContains('//button[contains(@disabled, "disabled")]','Précédent'); } } @@ -1995,7 +2103,7 @@ class UsersControllerManageNextDoubleUserTest extends UsersControllerDoubleTestC /** @test*/ public function buttonMergeShouldBe2to29() { - $this->assertXpath('//button[contains(@onclick, "/admin/users/manage-double-merge/id_user/2/id_user_to/29/id_user_from/2")]',$this->_response->getBody()); + $this->assertXpath('//button[contains(@onclick, "/admin/users/manage-double-merge/id_user/2/id_user_to/29/id_user_from/2")]'); } @@ -2475,6 +2583,12 @@ class Admin_UsersControllerEditModoBibTest extends Admin_AbstractControllerTestC public function formIdSIteOptionsShouldNotContainsWonderVille() { $this->assertXPathCount('//form//select[@id="id_site"]/option',2); } + + + /** @test */ + public function formShouldNotContainsSubscriptionInformation() { + $this->assertNotXPath('//form//tr[@class="subscription_information"]'); + } } @@ -2577,7 +2691,7 @@ class Admin_UsersControllerEditFormTest extends AbstractControllerTestCase { class UsersControllerIndexSearchRoleLevelPortalBorowersTest extends UsersControllerIndexTestCase { - protected $_role_level = 1; + protected $_role_level = ZendAfi_Acl_AdminControllerRoles::ABONNE; /** @test */ @@ -2611,9 +2725,458 @@ class UsersControllerIndexSearchRoleLevelPortalBorowersTest extends UsersControl } + /** @test */ + public function formShouldNotContainsAnyUserMembershipElement() { + $this->assertNotXPath('//input[contains(@name,"search_user_membership")]'); + } + + /** @test */ public function formShouldContainsSubscriptionEndDateRange() { $this->assertXPath('//input[@name="search_date_fin_start"]'); $this->assertXPath('//input[@name="search_date_fin_end"]'); } } + + + + +class UsersControllerSearchUserMembershipPostDispatchTest extends AbstractControllerTestCase { + protected $_role_level = ZendAfi_Acl_AdminControllerRoles::ABONNE_SIGB; + + public function setUp() { + parent::setUp(); + $this->fixture(Class_IntBib::class, + ['id' => 100, + 'sigb' => Class_IntBib::SIGB_NANOOK, + 'comm_sigb' => Class_IntBib::COM_NANOOK, + 'comm_params' => ['url_serveur' => 'https://mynanook.org']]); + + $mock_sql = + $this->mock() + ->whenCalled('fetchAllByColumn') + ->with('select user_id, max(end_date) from user_membership group by user_id having max(end_date) >= CURDATE() AND max(end_date) <=\'2012-02-04\' ') + ->answers([123,456]) + + ->whenCalled('fetchAllByColumn') + ->with('select user_id, max(end_date) from user_membership group by user_id having max(end_date) >= "2012-12-09" AND max(end_date) <= "2013-01-09"') + ->answers([123,456]) + + ->whenCalled('fetchAllByColumn') + ->with('select user_id, max(end_date) from user_membership group by user_id having max(end_date) >= "2010-12-01" AND max(end_date) <= "2010-12-31"') + ->answers([]) + + ->whenCalled('fetchAll') + ->with('select min(id_user) as id_user, id_sigb, count(*) as doublon from bib_admin_users where role_level = 2 and id_user > 0 group by id_sigb having doublon > 1 order by id_user asc') + ->answers([]) + + ->whenCalled('fetchAll') + ->with('select min(id_user) as id_user, login, idabon, ordreabon, password, count(*) as doublon from bib_admin_users where role_level = 2 and id_user > 0 group by login, idabon, ordreabon, password having doublon > 1 order by id_user asc') + ->answers([]) + ->beStrict(); + + Zend_Registry::set('sql', $mock_sql); + + $this->fixture(Class_User_Membership::class, + ['id'=>1, + 'membership_id'=>1, + 'user_id'=>1, + 'start_date' => '2012-01-01', + 'end_date' => '2013-01-01']); + + $time_source = new TimeSourceForTest('2012-02-01 14:00:00'); + Class_User_SearchCriteria_Membership::setTimeSource($time_source); + Class_User_SearchCriteria_EndSubscriptionDate::setTimeSource($time_source); + $this->OnLoaderOfModel(Class_Users::class); + } + + + public function tearDown(){ + Class_User_SearchCriteria_EndSubscriptionDate::setTimeSource(null); + Class_User_SearchCriteria_Membership::setTimeSource(null); + parent::tearDown(); + } + + + /** @test */ + public function queryOnUsersShouldSearchOnMembershipIdOneOrTwo() { + $this->postDispatch('/admin/users',['search_membership' => '1;2']); + $this->assertEquals([ + 'order' => 'nom asc', + 'where' => '((id_user in ( select distinct (user_id) from user_membership where membership_id in (1,2)))) AND (role_level <= 6)', + 'limitPage' => [1, 20] + ], + Class_Users::getFirstAttributeForMethodCallAt('findAllBy',1) + ); + } + + + /** @test */ + public function whenAllMembershipSelectedQueryOnUsersShouldNotFilterByMembership() { + $this->postDispatch('/admin/users',['search_membership' => 'ignore']); + $this->assertEquals([ + 'order' => 'nom asc', + 'where' => '((id_user not in (select distinct (user_id) from user_membership))) AND (role_level <= 6)', + 'limitPage' => [1, 20] + ], + Class_Users::getFirstAttributeForMethodCallAt('findAllBy',1) + ); + } + + + /** @test */ + public function whenNoSearchMembershipSentQueryOnUsersShouldNotFilterOnMembership() { + $this->postDispatch('/admin/users',['role_level' => 2]); + $this->assertEquals([ + 'order' => 'nom asc', + 'where' => '(role_level <= 6)', + 'limitPage' => [1, 20] + ], + Class_Users::getFirstAttributeForMethodCallAt('findAllBy',1) + ); + } + + + /** @test */ + public function whenSearchMembershipProvidedShouldReturnNoResult() { + $this->postDispatch('/admin/users',['search_role_level' => 2, + 'search_valid_subscription' => 1, + 'search_membership' => 1]); + $this->assertEquals([ + 'order' => 'nom asc', + 'where' => '(id_user IN (select user_id from user_membership where CURDATE() <= user_membership.end_date)) AND ((id_user in ( select distinct (user_id) from user_membership where membership_id in (1)))) AND (role_level <= 6)', + 'role_level' => 2, + 'limitPage' => [1, 20] + ], + Class_Users::getFirstAttributeForMethodCallAt('findAllBy',1) + ); + } + + + /** @test */ + public function whenSearchMembershipProvidedWithEndSubscriptionInXDaysShouldProcessExpectedQuery() { + $this->postDispatch('/admin/users',['role_level' => 2, + 'search_role_level' => 2, + 'search_end_subscription_days' => 3, + 'search_membership' => 1]); + $this->assertEquals([ + 'order' => 'nom asc', + 'where' => '(id_user in (123,456)) AND ((id_user in ( select distinct (user_id) from user_membership where membership_id in (1)))) AND (role_level <= 6)', + 'role_level' => 2, + 'limitPage' => [1, 20] + ], + Class_Users::getFirstAttributeForMethodCallAt('findAllBy',1) + ); + } + + + /** @test */ + public function whenSearchMembershipProvidedWithDateFinStartAndEndShouldProcessExpectedQuery() { + $this->postDispatch('/admin/users',['role_level' => 2, + 'search_date_fin_start' => '09/12/2012', + 'search_date_fin_end' => '09/01/2013', + 'search_membership' => 1]); + $this->assertEquals([ + 'order' => 'nom asc', + 'where' => '(id_user in (123,456)) AND ((id_user in ( select distinct (user_id) from user_membership where membership_id in (1)))) AND (role_level <= 6)', + 'limitPage' => [1, 20] + ], + Class_Users::getFirstAttributeForMethodCallAt('findAllBy',1) + ); + } + + + /** @test */ + public function whenSearchMembershipProvidedWithDateFinAndNoUserhouldDisplayAucunUtilisateur() { + $this->postDispatch('/admin/users',['role_level' => 2, + 'search_date_fin_start' => '01/12/2010', + 'search_date_fin_end' => '31/12/2010', + 'search_membership' => 1]); + $this->assertXPathContentContains('//p', + 'Aucun utilisateur trouvé' + ); + } +} + + + + +class UsersControllerSearchNoUserMembershipPostDispatchTest extends AbstractControllerTestCase { + protected $_role_level = ZendAfi_Acl_AdminControllerRoles::ABONNE_SIGB; + + + public function setUp() { + parent::setUp(); + $this->fixture(Class_IntBib::class, + ['id' => 100, + 'sigb' => Class_IntBib::SIGB_NANOOK, + 'comm_sigb' => Class_IntBib::COM_NANOOK, + 'comm_params' => ['url_serveur' => 'https://mynanook.org']]); + + $time_source = new TimeSourceForTest('2012-02-01 14:00:00'); + Class_User_SearchCriteria_EndSubscriptionDate::setTimeSource($time_source); + Class_User_SearchCriteria_Membership::setTimeSource($time_source); + $this->OnLoaderOfModel(Class_Users::class); + } + + + public function tearDown(){ + Class_User_SearchCriteria_EndSubscriptionDate::setTimeSource(null); + Class_User_SearchCriteria_Membership::setTimeSource(null); + parent::tearDown(); + } + + + /** @test */ + public function queryOnUsersShouldSearchOnMembershipIdOneOrTwo() { + $this->postDispatch('/admin/users',['search_membership' => '1;2']); + $this->assertEquals([ + 'order' => 'nom asc', + 'where' => '((id_user in ( select distinct (user_id) from user_membership where membership_id in (1,2)))) AND (role_level <= 6)', + 'limitPage' => [1, 20] + ], + Class_Users::getFirstAttributeForMethodCallAt('findAllBy',1) + ); + } + + + /** @test */ + public function whenValidSubscriptionQueryOnUsersShouldNotUseUserMembership() { + $this->postDispatch('/admin/users',['search_role_level' => 2, + 'search_valid_subscription' => 1]); + $this->assertEquals([ + 'order' => 'nom asc', + 'where' => '(STR_TO_DATE(date_fin, \'%Y-%m-%d\') >= CURDATE()) AND (role_level <= 6)', + 'role_level' => 2, + 'limitPage' => [1, 20] + ], + Class_Users::getFirstAttributeForMethodCallAt('findAllBy',1) + ); + } + + + /** @test */ + public function whenDateFinQueryOnUsersShouldFilterOnUserDateFin() { + $this->postDispatch('/admin/users',['role_level' => 2, + 'search_date_fin_start' => '01/02/2012', + 'search_date_fin_end' => '01/05/2013', + ]); + $this->assertEquals([ + 'order' => 'nom asc', + 'where' => '(left(date_fin, 10) >= "2012-02-01") AND (left(date_fin, 10) <= "2013-05-01") AND (role_level <= 6)', + 'limitPage' => [1, 20] + ], + Class_Users::getFirstAttributeForMethodCallAt('findAllBy',1) + ); + } + + + /** @test */ + public function whenEndSubscriptionDaysQueryOnUsersShouldNotUseUserMembership() { + $this->postDispatch('/admin/users',['search_role_level' => 2, + 'search_end_subscription_days' => 3]); + $this->assertEquals([ + 'order' => 'nom asc', + 'role_level' => 2, + 'where' => '(date_fin!=\'\' and date_fin <=\'2012-02-04\') AND (role_level <= 6)', + 'limitPage' => [1, 20] + ], + Class_Users::getFirstAttributeForMethodCallAt('findAllBy',1) + ); + } +} + + + + +abstract class UsersControllerEditUserMarcusWithUserMembershipsTestCase extends UsersControllerWithMarcusTestCase { + + public function setUp() { + parent::setUp(); + + $this->_prepareMemberships(); + + $this->_prepareTimesource(); + + $this->dispatch('/admin/users/edit/id/10'); + } + + + public function tearDown(){ + Class_User_Membership::setTimesource(null); + parent::tearDown(); + } + + protected function _prepareMemberships(){ + $this->fixture(Class_Membership::class, + ['id'=>1, + 'code'=>1, + 'libelle' => 'Abonné Adulte intra-muros', + 'enabled' => 1]); + + $this->fixture(Class_Membership::class, + ['id'=>2, + 'code'=>2, + 'libelle' => 'Abonnement invalide', + 'enabled' => 1]); + + $this->fixture(Class_Membership::class, + ['id'=>3, + 'code'=>3, + 'libelle' => 'Bouquets numériques', + 'enabled' => 1]); + + $this->fixture(Class_User_Membership::class, + ['id' => 1, + 'membership_id' => 1, + 'user_id' => 10, + 'start_date' => '2012-05-01', + 'end_date' => '2013-01-01']); + + $this->fixture(Class_User_Membership::class, + ['id' => 2, + 'membership_id' => 2, + 'user_id' => 10, + 'start_date' => '1970-01-01', + 'end_date' => '1971-06-06']); + + $this->fixture(Class_User_Membership::class, + ['id' => 3, + 'membership_id' => 3, + 'user_id' => 10, + 'start_date' => '2012-01-01', + 'end_date' => '']); + + } +} + + + +class UsersControllerEditUserMarcusWithUserMembershipsIn2011TestCase + extends UsersControllerEditUserMarcusWithUserMembershipsTestCase { + protected function _prepareTimesource(){ + $time_source = new TimeSourceForTest('2011-02-01 14:00:00'); + Class_User_Membership::setTimeSource($time_source); + } + + /** @test **/ + public function LabelInformationAbonnementSIGBShouldBeDisplayed() { + $this->assertXPathContentContains('//tr[@class="subscription_information"]//td','Abonnement(s) SIGB'); + } + + + /** @test **/ + public function abonnementInformationShouldContainsExactlyTwoItems() { + $this->assertXPathCount('//tr[@class="subscription_information"]//td//p',2); + } + + + /** @test **/ + public function abonnementInformationShouldContainsAdulteIntraMuros() { + $this->assertXPathContentContains('//tr[@class="subscription_information"]//td//p//strong','Abonné Adulte intra-muros'); + } + + + /** @test **/ + public function abonnementInformationShouldContainsDu1Mai2012() { + $this->assertXPathContentContains('//tr[@class="subscription_information"]//td//p','du 01/05/2012', $this->_response->getBody()); + } + + + /** @test **/ + public function abonnementInformationShouldContainsBouquetNumerique() { + $this->assertXPathContentContains('//tr[@class="subscription_information"]//td//p//strong','Bouquets numériques'); + } + + + /** @test **/ + public function abonnementInformationShouldContainsDu1Janvier2012() { + $this->assertXPathContentContains('//tr[@class="subscription_information"]//td//p', + 'du 01/01/2012'); + } + + + /** @test **/ + public function abonnementShouldNotContainsAbonnementInvalide() { + $this->assertNotXPathContentContains('//tr[@class="subscription_information"]//td//p//strong','Abonnement invalide'); + } +} + + +class UsersControllerEditUserMarcusWithUserMembershipsIn2023TestCase + extends UsersControllerEditUserMarcusWithUserMembershipsTestCase { + + protected function _prepareMemberships() { + parent::_prepareMemberships(); + Class_User_Membership::find(3)->setEndDate('2021-12-01') + ->save(); + } + + protected function _prepareTimesource(){ + $time_source = new TimeSourceForTest('2023-02-01 14:00:00'); + Class_User_Membership::setTimeSource($time_source); + } + + /** @test **/ + public function LabelInformationAbonnementSIGBShouldBeDisplayed() { + $this->assertXPathContentContains('//tr[@class="subscription_information"]//td','Abonnement(s) SIGB'); + } + + + /** @test **/ + public function abonnementInformationShouldContainsOneItemOnly() { + $this->assertXPathCount('//tr[@class="subscription_information"]//td//p',1); + } + + + /** @test **/ + public function abonnementInformationShouldNotContainsAdulteIntraMuros() { + $this->assertNotXPathContentContains('//tr[@class="subscription_information"]//td//p//strong','Abonné Adulte intra-muros'); + } + + + /** @test **/ + public function abonnementInformationShouldNotContainsDu1Mai2012() { + $this->assertNotXPathContentContains('//tr[@class="subscription_information"]//td//p','du 01/05/2012'); + } + + + /** @test **/ + public function abonnementInformationShouldContainsBouquetNumerique() { + $this->assertXPathContentContains('//tr[@class="subscription_information"]//td//p//strong','Bouquets numériques'); + } + + + /** @test **/ + public function abonnementInformationShouldContainsDu1Janvier2012() { + $this->assertXPathContentContains('//tr[@class="subscription_information"]//td//p', + 'du 01/01/2012 au 01/12/2021'); + } + + + /** @test **/ + public function abonnementShouldNotContainsAbonnementInvalide() { + $this->assertNotXPathContentContains('//tr[@class="subscription_information"]//td//p//strong','Abonnement invalide'); + } +} + + + + +class UsersControllerEditUserMarcusWithNoUserMembershipsIn2023TestCase + extends UsersControllerEditUserMarcusWithUserMembershipsTestCase { + + protected function _prepareMemberships() { + Class_User_Membership::deleteBy(['user_id'=>10]); + } + + protected function _prepareTimesource(){ + $time_source = new TimeSourceForTest('2023-02-01 14:00:00'); + Class_User_Membership::setTimeSource($time_source); + } + + /** @test **/ + public function LabelInformationAbonnementSIGBShouldNotBeDisplayed() { + $this->assertNotXPathContentContains('//tr[@class="subscription_information"]//td','Abonnement(s) SIGB'); + } +} diff --git a/tests/application/modules/opac/controllers/AuthControllerLostPasswordTest.php b/tests/application/modules/opac/controllers/AuthControllerLostPasswordTest.php index 6e0acb7c4b692fa4798871ed30fe5de4bd1f14e4..901ad9e742f2cd116cb04182eda66fed7364bb66 100644 --- a/tests/application/modules/opac/controllers/AuthControllerLostPasswordTest.php +++ b/tests/application/modules/opac/controllers/AuthControllerLostPasswordTest.php @@ -385,8 +385,8 @@ class AuthControllerLostPasswordOrpheeOnDemandBorrowerCreationTest <cat_pret><![CDATA[7]]></cat_pret> <codif><![CDATA[0]]></codif> <lib_cat_pret><![CDATA[ Pers médiat]]></lib_cat_pret> - <cat_tarif><![CDATA[1]]></cat_tarif> - <lib_cat_tarif><![CDATA[ Gratuit]]></lib_cat_tarif> + <cat_membership><![CDATA[1]]></cat_membership> + <lib_cat_membership><![CDATA[ Gratuit]]></lib_cat_membership> <anx><![CDATA[1]]></anx> <lib_anx><![CDATA[ Bibliothèque]]></lib_anx> <site><![CDATA[20]]></site> diff --git a/tests/application/modules/opac/controllers/AuthControllerWithNanookTest.php b/tests/application/modules/opac/controllers/AuthControllerWithNanookTest.php index fc757ac0b58b333b98bc6f991c7e026ae7076efd..50a64d3b10cfa77cb00e976b82e4019439335c18 100644 --- a/tests/application/modules/opac/controllers/AuthControllerWithNanookTest.php +++ b/tests/application/modules/opac/controllers/AuthControllerWithNanookTest.php @@ -58,6 +58,7 @@ abstract class AuthControllerNanookTestCase extends AbstractControllerTestCase { $this->fixture('Class_IntBib', ['id' => 5, + 'sigb' => Class_IntBib::SIGB_NANOOK, 'comm_sigb' => Class_IntBib::COM_NANOOK, 'comm_params' => serialize($params)]); } @@ -327,15 +328,18 @@ class AuthControllerWithNanookPostLoginWithMailAndUnsecurePasswordOthersLogins require_once(__DIR__ . '/../../../../fixtures/NanookFixtures.php'); -class AuthControllerWithNanookPostAxelLogin +abstract class AuthControllerWithNanookPostAxelLoginTestCase extends AuthControllerNanookTestCase { + protected $_patron_info; public function setUp() { parent::setUp(); Class_WebService_SIGB_AbstractRESTService::shouldThrowError(true); + $this->_prepareMemberships(); + $this->_web_client ->whenCalled('open_url') ->with('http://localhost:8080/afi_Nanook/ilsdi/service/AuthenticatePatron/username/Axel/password/2022') @@ -343,7 +347,8 @@ class AuthControllerWithNanookPostAxelLogin ->whenCalled('open_url') ->with('http://localhost:8080/afi_Nanook/ilsdi/service/GetPatronInfo/patronId/8') - ->answers(NanookFixtures::axelPatronInfo()); + ->answers($this->_patron_info); + $this->postDispatch('/opac/auth/login', ['username' => 'Axel', @@ -351,6 +356,25 @@ class AuthControllerWithNanookPostAxelLogin } + public function tearDown(){ + parent::tearDown(); + Class_User_Membership::setTimesource(null); + } + + + protected function _prepareMemberships(){ + Class_User_Membership::setTimesource(new TimeSourceForTest('2022-01-01 08:00:00')); + $this->_patron_info = NanookFixtures::axelPatronInfo(); + $this->fixture(Class_Membership::class, + ['id' => 1415, + 'code' => '14', + 'libelle' => 'Abonne Adulte', + 'enabled' => 1, + 'date_maj' => "" + ]); + } + + /** @test */ public function axelMultimediaAccessShouldBeUpdatedToZero() { $this->assertEquals(0, Class_Users::findFirstBy(['login' => 'Axel'])->getMultimediaAccess()); @@ -361,4 +385,210 @@ class AuthControllerWithNanookPostAxelLogin public function axelParentalAuthorizationShouldBeUpdatedToOne() { $this->assertEquals(1, Class_Users::findFirstBy(['login' => 'Axel'])->getParentalAuthorization()); } -} \ No newline at end of file +} + + + +class AuthControllerWithNanookPostAxelLoginNoMemberships + extends AuthControllerWithNanookPostAxelLoginTestCase { + + + /** @test */ + public function membershipShouldHaveBeenCreated() { + $this->assertEquals(['id' => 1416, + 'code' => '3', + 'libelle' => 'Abonné Adulte intra-muros', + 'enabled' => 0, + 'date_maj'=>''], + Class_Membership::findFirstBy(['code' => 3])->toArray()); + } + + + /** @test */ + public function userMembershipShouldHaveBeenCreated() { + $user_membership = Class_User_Membership::find(1); + $this->assertEquals(['id'=> 1, + 'membership_id'=> 1416, + 'user_id' => 667, + 'start_date' => '2022-02-16', + 'end_date'=>'2023-02-16'], + $user_membership->toArray()); + return $user_membership; + } + + + /** @test + * @depends userMembershipShouldHaveBeenCreated + */ + public function userAxelgetUserMembershipsShouldBeUserMembershipCreated($usermembership) { + $this->assertEquals([$usermembership], + Class_Users::find(667)->getUserMemberships()); + } +} + + + + +class AuthControllerWithNanookPostAxelLoginWithExistingMemberships + extends AuthControllerWithNanookPostAxelLoginTestCase { + + protected function _prepareMemberships(){ + parent::_prepareMemberships(); + $this->fixture(Class_Membership::class, + ['id' => 1, + 'libelle' => 'Abonné Adulte intra-muros', + 'enabled' => 1, + 'code' => 3 + ]); + + $this->fixture(Class_User_Membership::class, + ['id' => 1, + 'user_id' => 667, + 'membership_id' => 1, + 'start_date' => '2022-02-16', + 'end_date' => '2023-02-16' + ]); + } + + + /** @test */ + public function membershipShouldNotHaveBeenCreated() { + $this->assertEquals(2,Class_Membership::count()); + } + + + /** @test */ + public function userMembershipShouldNotHaveBeenCreated() { + $user_membership = Class_User_Membership::find(1); + $this->assertEquals(1, Class_User_Membership::count()); + return $user_membership; + } + + + /** @test + */ + public function userAxelgetUserMembershipsShouldBeUserMembership() { + $this->assertEquals([Class_User_Membership::find(1)], + Class_Users::find(667)->getUserMemberships()); + } +} + + + + + +class AuthControllerWithNanookPostAxelLoginWithoutLabelButExistingMemberships + extends AuthControllerWithNanookPostAxelLoginTestCase { + + protected function _prepareMemberships(){ + parent::_prepareMemberships(); + $this->_patron_info = NanookFixtures::axelPatronInfoWithoutSubscriptionLabel(); + $this->fixture(Class_Membership::class, + ['id' => 1, + 'libelle' => 'Abonné Adulte intra-muros', + 'enabled' => 1, + 'code' => 3 + ]); + + $this->fixture(Class_User_Membership::class, + ['id' => 1, + 'user_id' => 667, + 'membership_id' => 1, + 'start_date' => '2022-02-16', + 'end_date' => '2023-02-16' + ]); + } + + + /** @test */ + public function membershipShouldNotHaveBeenCreated() { + $this->assertEquals(2,Class_Membership::count()); + } + + + /** @test */ + public function userMembershipShouldNotHaveBeenCreated() { + $user_membership = Class_User_Membership::find(1); + $this->assertEquals(1, Class_User_Membership::count()); + return $user_membership; + } + + + /** @test + */ + public function userAxelgetUserMembershipsShouldBeUserMembership() { + $this->assertEquals([Class_User_Membership::find(1)], + Class_Users::find(667)->getUserMemberships()); + } +} + + + + +class AuthControllerWithNanookPostAxelLoginWithRoleLevelModoBibWithoutLabelButExistingMemberships + extends AuthControllerNanookTestCase { + protected $_patron_info; + + public function setUp() { + parent::setUp(); + + Class_WebService_SIGB_AbstractRESTService::shouldThrowError(true); + + $this->_prepareMemberships(); + + $this->_web_client + ->whenCalled('open_url') + ->with('http://localhost:8080/afi_Nanook/ilsdi/service/AuthenticatePatron/username/Axel/password/2022') + ->answers(NanookFixtures::axelAuthenticatePatron()) + + ->whenCalled('open_url') + ->with('http://localhost:8080/afi_Nanook/ilsdi/service/GetPatronInfo/patronId/8') + ->answers($this->_patron_info); + + + $this->postDispatch('/opac/auth/login', + ['username' => 'Axel', + 'password' => '2022']); + } + + + protected function _prepareMemberships(){ + Class_User_Membership::setTimesource(new TimeSourceForTest('2022-01-01 08:00:00')); + $this->_patron_info = NanookFixtures::axelPatronInfo(); + + $this->fixture(Class_Membership::class, + ['id' => 1415, + 'code' => '14', + 'libelle' => 'Abonne Adulte', + 'enabled' => 1, + 'date_maj' => "" + ]); + + $this->_patron_info = NanookFixtures::axelPatronInfoWithoutSubscriptionLabel(); + $this->fixture(Class_Membership::class, + ['id' => 1, + 'libelle' => 'Abonné Adulte intra-muros', + 'enabled' => 1, + 'code' => 3 + ]); + + $this->fixture(Class_Users::class, + ['id' => 667, + 'login' => 'Axel', + 'password' => '2022', + 'role' => ZendAfi_Acl_AdminControllerRoles::MODO_BIB + ]); + } + + + /** @test */ + public function membershipShouldNotHaveBeenCreated() { + $this->assertEquals(2,Class_Membership::count()); + } + + + /** @test */ + public function userMembershipShouldNotHaveBeenCreated() { + $this->assertEquals(0, Class_User_Membership::count()); + } +} diff --git a/tests/db/UpgradeDBTest.php b/tests/db/UpgradeDBTest.php index 41a413f99d73e78eb6e7d343936f15a5ed2ab7ea..9d0a873efb8b829b38b956bd7a2e8ab40a9ca089 100644 --- a/tests/db/UpgradeDBTest.php +++ b/tests/db/UpgradeDBTest.php @@ -5093,3 +5093,80 @@ class UpgradeDB_446_Test extends UpgradeDBTestCase { $this->query("select * from variables where clef='max_items'")->fetch()['valeur']); } } + + + + +class UpgradeDB_447_Test extends UpgradeDBTestCase { + + public function prepare() { + $this->silentQuery('drop table membership'); + $this->silentQuery('drop table user_membership'); + } + + + /** @test */ + public function membershipTableShouldBeCreated() { + $this->assertTable('membership'); + } + + + /** @test */ + public function userMembershipTableShouldBeCreated() { + $this->assertTable('user_membership'); + } + + + public function fields() : array { + return [['membership', 'id', 'int(11) unsigned'], + ['membership', 'code', 'varchar(255)'], + ['membership', 'libelle', 'varchar(255)'], + ['membership', 'enabled', 'tinyint(1)'], + ['membership', 'date_maj', 'datetime'], + ['membership', 'date_created', 'datetime'], + ['user_membership', 'id', 'int(11) unsigned'], + ['user_membership', 'user_id', 'int(11) unsigned'], + ['user_membership', 'membership_id', 'int(11) unsigned'], + ['user_membership', 'start_date', 'date'], + ['user_membership', 'end_date', 'date'] + ]; + } + + + /** + * @test + * @dataProvider fields + */ + public function fieldForTableShouldBeOfType(string $table_name, string $field, string $type) { + $this->assertFieldType($table_name, $field, $type); + } + + /** @test */ + public function userMembershipIdFieldShouldBePrimary() { + $this->assertPrimary('user_membership', 'id'); + } + + + /** @test */ + public function membershipIdFieldShouldBePrimary() { + $this->assertPrimary('membership', 'id'); + } + + + public function fields_not_null() : array { + return [['membership', 'id'], + ['membership', 'code'], + ['membership', 'libelle'], + ['user_membership', 'id'], + ['user_membership', 'user_id'], + ['user_membership', 'membership_id'], + ]; + } + + /** @test + * @dataProvider fields_not_null + */ + public function notNullableFieldShouldNotBeNullable(string $table_name, string $field_name) { + $this->assertFieldNotNullable($table_name, $field_name); + } +} diff --git a/tests/fixtures/NanookFixtures.php b/tests/fixtures/NanookFixtures.php index f37523b15473a4285bdf938e93bcbb375852df10..46f7bb98049faece7b536ecf80c492f25add3268 100644 --- a/tests/fixtures/NanookFixtures.php +++ b/tests/fixtures/NanookFixtures.php @@ -327,10 +327,16 @@ class NanookFixtures { </suggest> </suggests> <subscriptions> - <subscriptions> + <subscription> <rateId>958</rateId> + <rateLabel>Abonné Adulte</rateLabel> <startDate>2011-10-25</startDate> <endDate>2011-11-25</endDate> + </subscription> + <subscriptions> + <rateId>976</rateId> + <startDate>2012-10-25</startDate> + <endDate>2013-11-25</endDate> </subscriptions> </subscriptions> </GetPatronInfo>'; @@ -407,11 +413,11 @@ class NanookFixtures { </hold> </holds> <subscriptions> - <subscriptions> + <subscription> <rateId>958</rateId> <startDate>2011-10-25</startDate> <endDate>2011-11-25</endDate> - </subscriptions> + </subscription> </subscriptions> </GetPatronInfo>'; } @@ -841,9 +847,54 @@ class NanookFixtures { <holds> </holds> <subscriptions> +<subscriptions> +<rateId>3</rateId> +<rateLabel>Abonné Adulte intra-muros</rateLabel> <startDate>2022-02-16</startDate> <endDate>2023-02-16</endDate> </subscriptions> +</subscriptions> +</GetPatronInfo>'; + } + + + public static function axelPatronInfoWithoutSubscriptionLabel() : string { + return '<?xml version="1.0" encoding="UTF-8"?> +<GetPatronInfo> +<patronId>8</patronId> +<siteId>1</siteId> +<barcode>U-00008</barcode> +<cardType>Particulier</cardType> +<cardStatus>Validité</cardStatus> +<notes></notes> +<lastName>Ho Ho Ho</lastName> +<firstName>Axel</firstName> +<displayOrder>1</displayOrder> +<birthDate>2022-07-12</birthDate> +<phoneNumber></phoneNumber> +<town>Valleiry</town> +<zipcode>74520</zipcode> +<address></address> +<endDate>2023-02-16</endDate> +<mail></mail> +<parentalAuthorization>1</parentalAuthorization> +<multimediaAccess>0</multimediaAccess> +<newsletter>1</newsletter> +<alertPreviousLoanOnDocument>0</alertPreviousLoanOnDocument> +<noAnonymization>0</noAnonymization> +<loanForbidden>0</loanForbidden> +<holdForbidden>0</holdForbidden> +<loans> +</loans> +<holds> +</holds> +<subscriptions> +<subscriptions> +<rateId>3</rateId> +<startDate>2022-02-16</startDate> +<endDate>2023-02-16</endDate> +</subscriptions> +</subscriptions> </GetPatronInfo>'; } diff --git a/tests/library/Class/Cosmogramme/Integration/PhasePatronsTest.php b/tests/library/Class/Cosmogramme/Integration/PhasePatronsTest.php index 22633ea39df2d0ebbc229262ad29a2cd74d17516..3d18342027475b199fda75311fb7da261b11413b 100644 --- a/tests/library/Class/Cosmogramme/Integration/PhasePatronsTest.php +++ b/tests/library/Class/Cosmogramme/Integration/PhasePatronsTest.php @@ -438,7 +438,8 @@ abstract class PhasePatronsIntegrationTestCase extends ModelTestCase { ['id' => 2, 'id_bib' => 2]); - $this->abon_config = new Class_Cosmogramme_Integration_Record_Patron($this->getIntegration()); + $this->abon_config = new Class_Cosmogramme_Integration_Record_Patron($this->getIntegration(), + fn($message)=>print $message); } public function getIntegration() { @@ -887,3 +888,122 @@ class PhasePatronsImportOrpheeTest $this->assertEquals('Céline DELBECQUE', $user->getNomComplet()); } } + + + + +class PhasePatronsFullImportWithAbonnementsTest extends PhasePatronsTestCase { + public function _prepareFixtures(){ + parent::_prepareFixtures(); + + $this->fixture(Class_Membership::class, + ['id' => 22, + 'code' => 22, + 'libelle' => 'Abonnement Bouquet Numérique' + ]); + $this->fixture(Class_Membership::class, + ['id' => 21, + 'code' => 21, + 'libelle' => 'Membership Adulte' + ]); + + $this->fixture(Class_IntProfilDonnees::class, + ['id' => 102, + 'libelle' => 'Patrons', + 'accents' => Class_IntProfilDonnees::ENCODING_UTF8, + 'type_fichier' => Class_IntProfilDonnees::FT_PATRONS, + 'format' => Class_IntProfilDonnees::FORMAT_PIPED_ASCII, + 'attributs' => [1 => ['champs' => 'IDABON;ID_SIGB;ORDREABON;NOM;PRENOM;PASSWORD;MAIL;NAISSANCE;DATE_FIN;ABONNEMENTS']]]); + + Class_Cosmogramme_Integration::find(999)->setProfilDonnees(Class_IntProfilDonnees::find(102)) + ->setFichier('abonnes.txt') + ->save(); + } + + public function setUp() { + parent::setUp(); + + $this->_phase->run(); + Class_Users::clearCache(); + } + + /** @test */ + public function patron4NomCompletShouldBeIggyPop() { + $this->assertEquals('Iggy POP',Class_Users::find(4)->getNomComplet()); + } + + + /** @test */ + public function patron5NomCompletShouldBeDemisRoussos() { + $this->assertEquals('DEMIS ROUSSOS',Class_Users::find(5)->getNomComplet()); + } + + + /** @test */ + public function patron6NomCompletShouldBeKaasPatricia() { + $this->assertEquals('Patricia KAAS',Class_Users::find(6)->getNomComplet()); + } + + + /** @test */ + public function patron6UserMembershipsCountShouldBeTwo() { + $this->assertEquals(2,sizeOf(Class_Users::find(6)->getUserMemberships())); + } + + + /** @test */ + public function patron7NomCompletShouldBeJohnBanner() { + $this->assertEquals('John Banner',Class_Users::find(7)->getNomComplet()); + } + + + /** @test */ + public function patron7DateFinShouldBe06Fevrier2022() { + $this->assertEquals('2022-02-06',Class_Users::find(7)->getDateFin()); + } + + + /** @test */ + public function patron7UserMembershipsShouldEmpty() { + $this->assertEmpty(Class_Users::find(7)->getUserMemberships()); + } + + + public function usermemberships(){ + return [[1, ['id' => 1, + 'user_id' => 5, + 'membership_id' => 22, + 'start_date' => '2019-02-06', + 'end_date' => '2020-02-06']], + [2, ['id' => 2, + 'user_id' => 6, + 'membership_id' => 22, + 'start_date' => '2019-05-06', + 'end_date' => '2020-06-06']], + [3, ['id' => 3, + 'user_id' => 6, + 'membership_id' => 21, + 'start_date' => '2019-07-06', + 'end_date' => '2020-09-06']]]; + + } + + + /** @test + * @dataProvider usermemberships + */ + public function userMembershipsSavedShouldBeAsExpected($user_membership_id, $expected) { + $this->assertEquals($expected,Class_User_Membership::find($user_membership_id)->toArray()); + } + + + /** @test */ + public function logShouldContainsMembership42introuvable() { + $this->assertLogContains('membership 42 introuvable dans la table Membership'); + } + + /** @test */ + public function logShouldContainsdateDouzeDouzeDeuxmilleVingtDeuxInvalide() { + $this->assertLogContains('date de début 12-12-2022 invalide pour le membership 21'); + } +} diff --git a/tests/library/Class/Cosmogramme/Integration/PhasePrepareIntegrationsTest.php b/tests/library/Class/Cosmogramme/Integration/PhasePrepareIntegrationsTest.php index 7ab0e294cea8a2ff67ebad4d8edfe831ae3cdaa0..9f19a2fdf10d2bed3500ad2e77806d73aafbf94c 100644 --- a/tests/library/Class/Cosmogramme/Integration/PhasePrepareIntegrationsTest.php +++ b/tests/library/Class/Cosmogramme/Integration/PhasePrepareIntegrationsTest.php @@ -441,6 +441,12 @@ abstract class PhasePrepareIntegrationsNanookStandardTestCase '0|3|Bande dessinée|f', '0|4|' . iconv('UTF-8', 'ISO-8859-1', 'Bande dessinée') . '|f',]) + ->whenCalled('getMembershipsOf')->with('foo') + ->answers(['ID|LIBELLE|ENABLED', + '1|Abonné Adulte|1', + '2|Abonné Comm Comm|1', + '4|' . iconv('UTF-8', 'ISO-8859-1', 'Abonné') . '|0',]) + ->beStrict(); Class_Cosmogramme_LandingDirectory::setInstance($landing_directory); @@ -544,6 +550,13 @@ abstract class PhasePrepareIntegrationsNanookStandardTestCase }); } + $db_adapter->whenCalled('query') + ->with('delete from membership where date(date_maj) != "' . $now->dateYmd() . '"') + ->willDo(function() use ($model_class, $now) + { + $model_class::deleteBy(['date_maj not' => $now->dateYmd()]); + }); + Class_Cosmogramme_Generator_AbstractTask::setDbAdapter($db_adapter); } @@ -745,6 +758,12 @@ class PhasePrepareIntegrationsNanookStandardTest public function renamedSectionShouldBeUpdated() { $this->assertEquals('Jeunes', Class_CodifSection::find(38)->getLibelle()); } + + + /** @test */ + public function membership1LibelleShouldBeAbonneAdulte() { + $this->assertEquals('Abonné Adulte', Class_Membership::find(1)->getLibelle()); + } } diff --git a/tests/library/Class/Cosmogramme/Integration/abonnes.txt b/tests/library/Class/Cosmogramme/Integration/abonnes.txt new file mode 100644 index 0000000000000000000000000000000000000000..d65d2e293afe76fbf8904187097fd02f26d8518d --- /dev/null +++ b/tests/library/Class/Cosmogramme/Integration/abonnes.txt @@ -0,0 +1,5 @@ +BIB_ABON_CARTE|ID_ABON|ORDRE|NOM|PRENOM|MOT_DE_PASSE|E_MAIL|NAISSANCE|DATE_FIN|ABONNEMENTS +B592071393|4333|4|POP|Iggy|mdpasse|iggy@yahoo.fr|2000-06-07|2019-11-30| +B592070002|1|1|ROUSSOS|DEMIS|secret|droussos@sfr.fr|1948-03-19|2020-02-06|22;2019-02-06;2020-02-06 +B592070003|2|1|KAAS|Patricia|password|p.kaas@sfr.fr|1973-03-19|2020-02-06|22;2019-05-06;2020-06-06;21;2019-07-06;2020-09-06;42;12-12-2022;12-12-2023;21;12-12-2022;1976-01-000 +B592070004|6|1|Banner|John|password|johnSavage@combination.fr|1973-05-19|2022-02-06| diff --git a/tests/library/Class/Cosmogramme/Integration/tarifs.txt b/tests/library/Class/Cosmogramme/Integration/tarifs.txt new file mode 100644 index 0000000000000000000000000000000000000000..c1f4d93b9c800958e842089300681c18443f37cb --- /dev/null +++ b/tests/library/Class/Cosmogramme/Integration/tarifs.txt @@ -0,0 +1,8 @@ +ID|LIBELLE|ACTIF +0|Tous les sites|1 +21|Hem 30 €|1 +22|Bibliothécaire 15 €|1 +23|Hors Hem 45 €|1 +24|Enfant seul Gratuit (ex 515)|1 +25|Groupe|1 +26|Vacancier 2 €|1 diff --git a/tests/library/Class/Migration/AbonnementsUtilisateursTest.php b/tests/library/Class/Migration/AbonnementsUtilisateursTest.php new file mode 100644 index 0000000000000000000000000000000000000000..4fbfbe927676afbc8270f27b1b6897926dd4d9cb --- /dev/null +++ b/tests/library/Class/Migration/AbonnementsUtilisateursTest.php @@ -0,0 +1,229 @@ +<?php +/** + * Copyright (c) 2012-2023, Agence Française Informatique (AFI). All rights reserved. + * + * BOKEH is free software; you can redistribute it and/or modify + * it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE as published by + * the Free Software Foundation. + * + * There are special exceptions to the terms and conditions of the AGPL as it + * is applied to this software (see README file). + * + * BOKEH is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU AFFERO GENERAL PUBLIC LICENSE for more details. + * + * You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE + * along with BOKEH; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + + + +abstract class AbonnementsUtilisateursTestCase extends ModelTestCase { + protected $_return_from_run, + $_profil; + + public function setUp(){ + parent::setUp(); + $this->_setIntProfilDonnees(); + $this->_setIntBib(); + $this->_return_from_run = (new Class_Migration_AbonnementsUtilisateurs) + ->run(); + } + + public function tearDown(){ + parent::tearDown(); + } + + + protected function _setIntProfilDonnees() :void{ + $this->_profil = clone($this->fixture(Class_IntProfilDonnees::class, + ['id' => 4, + 'libelle' => 'Nanook Patrons', + 'type_fichier' => Class_IntProfilDonnees::FT_PATRONS, + 'format' => Class_IntProfilDonnees::FORMAT_PIPED_ASCII, + 'attributs' => + [['type_doc' => + [[ 'code' => '0', 'label' => '', 'zone_995' => '' ], + [ 'code' => '1', 'label' => 'am;na', 'zone_995' => '' ], + [ 'code' => '2', 'label' => 'as', 'zone_995' => ''], + [ 'code' => '3', 'label' => 'i;j', 'zone_995' => ''], + [ 'code' => '4', 'label' => 'g','zone_995' => ''], + [ 'code' => '5', 'label' => 'l;m', 'zone_995' => ''], + [ 'code' => '6', 'label' => '', 'zone_995' => '' ], + [ 'code' => '7', 'label' => '', 'zone_995' => '' ], + [ 'code' => '8', 'label' => '', 'zone_995' => ''], + [ 'code' => '9', 'label' => '', 'zone_995' => ''] + ], + Class_IntProfilDonnees::FIELD_ITEM_BARCODE => 'f', + Class_IntProfilDonnees::FIELD_ITEM_COTE => 'k', + Class_IntProfilDonnees::FIELD_ITEM_TYPE_DOC => '', + Class_IntProfilDonnees::FIELD_ITEM_GENRE => '', + Class_IntProfilDonnees::FIELD_ITEM_SECTION => 'j', + Class_IntProfilDonnees::FIELD_ITEM_EMPLACEMENT => 'u', + Class_IntProfilDonnees::FIELD_ITEM_ANNEXE => '' + ], + ['champs' => 'IDABON;ORDREABON;NOM;PRENOM;NAISSANCE;DATE_DEBUT;DATE_FIN;MAIL'], + ['champs' => 'IDABON;ORDREABON;NOM;PRENOM;NAISSANCE;DATE_DEBUT;DATE_FIN;MAIL'], + ['champs' => 'IDABON;ORDREABON;NOM;PRENOM;NAISSANCE;DATE_DEBUT;DATE_FIN;MAIL'] + ] + ])); + } + + + protected function _setSingleNanook(){ + $params = ['url_serveur' => 'http://localhost:8080/afi_Nanook/ilsdi/', + 'id_bib' => 5, + 'type' => Class_IntBib::COM_NANOOK]; + + + $intbib = $this->fixture(Class_IntBib::class, + ['id' => 5, + 'sigb' => Class_IntBib::SIGB_NANOOK, + 'comm_sigb' => Class_IntBib::COM_NANOOK, + 'comm_params' => serialize($params)]); + + $this->fixture(Class_IntMajAuto::class, + ['id' => 4, + 'int_bib' => $intbib, + 'profil' => 4 + ]); + } + + + protected function _setIntProfilDonneesCustomized() { + return $this->fixture(Class_IntProfilDonnees::class, + ['id' => 4, + 'libelle' => 'Nanook Patrons', + 'type_fichier' => Class_IntProfilDonnees::FT_PATRONS, + 'format' => Class_IntProfilDonnees::FORMAT_PIPED_ASCII, + 'attributs' => + [ + ['champs' => $this->_string], + ] + ]); + } + + + protected function _setIntBib() :void { + $this->_intBib = $this->fixture('Class_IntBib', + ['id' => 5, + 'comm_sigb' => Class_IntBib::COM_KOHA]); + } + + protected function _checkChampsValueWith(string $value) : void{ + $attributs = Class_IntProfilDonnees::find(4)->getAttributsAsArray(); + foreach($this->_filterArrayOnChamps($attributs, true) as $attr) + $this->assertEquals($value, $attr['champs'] ); + + } + + + protected function _checkOtherFields() :void { + $this->assertEquals($this->_filterArrayOnChamps($this->_profil->getAttributsAsArray(),false), + $this->_filterArrayOnChamps(Class_IntProfilDonnees::find(4)->getAttributsAsArray(),false)); + + } + + + protected function _filterArrayOnChamps(array $array, bool $champs_filter = true) :array{ + return array_filter($array, fn($elt) => is_array($elt) && ($champs_filter + ? isset($elt['champs']) + : !isset($elt['champs']))); + } +} + + + + +class AbonnementsUtilisateursNoSingleNanookTest extends AbonnementsUtilisateursTestCase { + /** @test */ + public function intProfilDonneesChampsFieldShouldNotBeEdited() { + $this->_checkChampsValueWith('IDABON;ORDREABON;NOM;PRENOM;NAISSANCE;DATE_DEBUT;DATE_FIN;MAIL'); + } + + + /** @test */ + public function intProfilDonneesOtherFieldsShouldNotBeEdited() { + $this->_checkOtherFields(); + } + + + /** @test */ + public function resultShouldBeEmptyString() { + $this->assertEmpty($this->_return_from_run); + } +} + + + + +class AbonnementsUtilisateursNoSingleNanookWithAbonnementsTest extends AbonnementsUtilisateursTestCase { + protected $_string = 'NAISSANCE;DATE_DEBUT;DATE_FIN;MAIL;ABONNEMENTS'; + + protected function _setIntProfilDonnees() :void{ + $this->_profil = $this->_setIntProfilDonneesCustomized(); + } + + /** @test */ + public function intProfilDonneesChampsFieldShouldNotBeEdited() { + $this->_checkChampsValueWith($this->_string); + } + + + /** @test */ + public function resultShouldBeEmptyString() { + $this->assertEmpty($this->_return_from_run); + } +} + + + + +class AbonnementsUtilisateursSingleNanookTest extends AbonnementsUtilisateursTestCase { + protected function _setIntBib() :void{ + $this->_setSingleNanook(); + } + + + /** @test */ + public function intProfilDonneesShouldContainsAbonnements() { + $this->_checkChampsValueWith('IDABON;ORDREABON;NOM;PRENOM;NAISSANCE;DATE_DEBUT;DATE_FIN;MAIL;ABONNEMENTS'); + } + + + /** @test */ + public function intProfilDonneesOtherFieldsShouldNotBeEdited() { + $this->_checkOtherFields(); + } + + + /** @test */ + public function resultShouldBeOneConfigurationModifiee(){ + $this->assertEquals("1 configurations modifiées",$this->_return_from_run); + } +} + + + + +class AbonnementsUtilisateursSingleNanookWithAbonnementsTest extends AbonnementsUtilisateursTestCase { + protected $_string = 'NAISSANCE;DATE_DEBUT;DATE_FIN;MAIL;ABONNEMENTS'; + + + protected function _setIntBib() :void{ + $this->_setSingleNanook(); + } + + protected function _setIntProfilDonnees():void { + $this->_profil = $this->_setIntProfilDonneesCustomized(); + } + + + /** @test */ + public function intProfilDonneesChampsFieldShouldNotBeEdited() { + $this->_checkChampsValueWith($this->_string); + } +} diff --git a/tests/library/Class/Migration/SigbStandardCodificationsTest.php b/tests/library/Class/Migration/SigbStandardCodificationsTest.php index 5b93ab803a6955ca4874af53ede2f518651d6f03..e21c0b147f684bc28ed43c628c124ae4983ef7a2 100644 --- a/tests/library/Class/Migration/SigbStandardCodificationsTest.php +++ b/tests/library/Class/Migration/SigbStandardCodificationsTest.php @@ -78,6 +78,10 @@ class Class_Migration_SigbStandardCodificationsTest extends ModelTestCase { '0|3|Bande dessinée|f', '0|4|' . iconv('UTF-8', 'ISO-8859-1', 'Bande dessinée') . '|f',]) + ->whenCalled('getMembershipsOf')->with('foo') + ->answers(['CODE|LIBELLE|ENABLED', + '1|Adulte Interne|1']) + ->beStrict(); Class_Cosmogramme_LandingDirectory::setInstance($landing_directory); @@ -96,6 +100,11 @@ class Class_Migration_SigbStandardCodificationsTest extends ModelTestCase { ->with('update ' . $codif . ' set date_maj=""') ->answers(0); + $db_adapter + ->whenCalled('query') + ->with('delete from membership where date(date_maj) != "2015-03-26"') + ->answers(0); + Class_Cosmogramme_Generator_AbstractTask::setDbAdapter($db_adapter); } diff --git a/tests/library/Class/WebService/SIGB/FloraTest.php b/tests/library/Class/WebService/SIGB/FloraTest.php index 2dc06f043e321b222646cc2520de9f7587e989f1..a22ba53197ad749348a73556d416ea5da8ed8a08 100644 --- a/tests/library/Class/WebService/SIGB/FloraTest.php +++ b/tests/library/Class/WebService/SIGB/FloraTest.php @@ -426,7 +426,7 @@ class FloraPatronIntegrationTest extends ModelTestCase { 'traite' => 'non', 'fichier' => 'patrons.txt', 'pointeur_reprise' => 0]); - $this->_record_patron = (new Class_Cosmogramme_Integration_Record_Patron($integration)) + $this->_record_patron = (new Class_Cosmogramme_Integration_Record_Patron($integration, fn($message)=> print $message)) ->import(['IDABON' => 'abon123', 'ID_SIGB' => 123, 'NOM' => 'Brun', @@ -505,4 +505,4 @@ class FloraSaveEmprunteurTest extends FloraTestCase { $this->assertTrue($this->_service->providesChangePasswordService()); } -} \ No newline at end of file +} diff --git a/tests/library/Class/WebService/SIGB/KohaTest.php b/tests/library/Class/WebService/SIGB/KohaTest.php index 3401f8910d017114848b6b3e49da5e3224aad958..6da0073c0d56c358d5159eec51575b191355e981 100644 --- a/tests/library/Class/WebService/SIGB/KohaTest.php +++ b/tests/library/Class/WebService/SIGB/KohaTest.php @@ -614,8 +614,9 @@ class KohaGetEmprunteurLaureAfondTest extends KohaTestCase { /** @test */ public function subscriptionShouldBeINDIVIDU() { - $this->assertEquals(['INDIVIDU' => 'INDIVIDU'], - $this->laurent->getSubscriptions()); + $subscriptions = $this->laurent->getSubscriptions(); + $this->assertEquals('INDIVIDU', + $subscriptions[0]->getId()); } diff --git a/tests/library/Class/WebService/SIGB/NanookTest.php b/tests/library/Class/WebService/SIGB/NanookTest.php index 76e32ccb917fb77682981c5afbe3181dc33ffc1b..749d4c38320504c19f97d01e8987a5939be65f9a 100644 --- a/tests/library/Class/WebService/SIGB/NanookTest.php +++ b/tests/library/Class/WebService/SIGB/NanookTest.php @@ -526,6 +526,52 @@ class NanookGetEmprunteurChristelDelpeyrouxAsAdminTest public function nbReservationsShouldBeFour() { $this->assertEquals(4, $this->_emprunteur->getNbReservations()); } + + + /** @test */ + public function numberOfDecodedSubscriptionsShouldBeTwo() { + $this->assertEquals(2, sizeOf($subscriptions = $this->_emprunteur->getSubscriptions())); + return $subscriptions; + } + + /** @test + * @depends numberOfDecodedSubscriptionsShouldBeTwo + */ + public function firstSubscriptionIdShouldBe958($subscriptions) { + $this->assertEquals('958', $subscriptions[0]->getId()); + } + + + /** @test + * @depends numberOfDecodedSubscriptionsShouldBeTwo + */ + public function firstSubscriptionLabelShouldBe($subscriptions) { + $this->assertEquals('Abonné Adulte', $subscriptions[0]->getLabel()); + } + + + /** @test + * @depends numberOfDecodedSubscriptionsShouldBeTwo + */ + public function firstSubscriptionDateDebutShouldBe($subscriptions) { + $this->assertEquals('2011-10-25', $subscriptions[0]->getStartDate()); + } + + + /** @test + * @depends numberOfDecodedSubscriptionsShouldBeTwo + */ + public function firstSubscriptionDateFinShouldBe($subscriptions) { + $this->assertEquals('2011-11-25', $subscriptions[0]->getEndDate()); + } + + + /** @test + * @depends numberOfDecodedSubscriptionsShouldBeTwo + */ + public function secondSubscriptionIdShouldBe($subscriptions) { + $this->assertEquals('976', $subscriptions[1]->getId()); + } } diff --git a/tests/library/Class/WebService/SIGB/OrpheeServiceTest.php b/tests/library/Class/WebService/SIGB/OrpheeServiceTest.php index 8378060f86094496e3175011411d460c0a3de603..8d384044a2ec7936348d113943b69da34093f4d1 100644 --- a/tests/library/Class/WebService/SIGB/OrpheeServiceTest.php +++ b/tests/library/Class/WebService/SIGB/OrpheeServiceTest.php @@ -1027,8 +1027,10 @@ class OrpheeServiceGetInfoUserCarteHenryDupontTest extends OrpheeServiceTestCase /** @test */ - public function emprunteurShouldHaveLibCatPretContains() { - $this->assertEquals(['1' => 'Lecteur adulte'], $this->emprunteur->getSubscriptions()); + public function emprunteurShouldHaveLibCatPret() { + $this->assertEquals(1, sizeOf($subscriptions = $this->emprunteur->getSubscriptions())); + $this->assertEquals(1, $subscriptions[0]->getId()); + $this->assertEquals('Lecteur adulte', $subscriptions[0]->getLabel()); } diff --git a/tests/scenarios/Templates/TemplatesAbonneTest.php b/tests/scenarios/Templates/TemplatesAbonneTest.php index c7eb555053d3cb43e3e9f88ca32b23a8b4d71762..4000d3d9da84eb1fa8c41f570131caf3f9ae1b53 100644 --- a/tests/scenarios/Templates/TemplatesAbonneTest.php +++ b/tests/scenarios/Templates/TemplatesAbonneTest.php @@ -300,6 +300,21 @@ abstract class TemplatesIntonationAccountTestCase extends TemplatesIntonationTes 'loan_link' => 'https://pnb-dilicom.centprod.com/v2//XXXXXXXX.do', 'options' => 'LCP', 'order_line_id' => '584837a045ce56ef0a072a8b']); + + $membership = $this->fixture(Class_Membership::class, + [ 'id' => 1, + 'code' => 1, + 'libelle' => 'Abonné adulte', + 'enabled' => 1 + ]); + + $this->fixture(Class_User_Membership::class, + [ 'id' => 1, + 'user' => $current_user, + 'membership' => $membership, + 'start_date' => '2012-01-01', + 'end_date' => '2020-01-01' + ]); } } @@ -2157,3 +2172,186 @@ class TemplatesAbonnePaginatedReviewsSearchConsRoiPage2Test extends TemplatesAbo $this->assertXPath('//input[@value="cons roi"]'); } } + + + + +class TemplatesDispatchAbonneUserMembershipTest extends TemplatesIntonationAccountTestCase { + public function setUp() { + parent::setUp(); + Class_AdminVar::set('TEMPLATING', 1); + + $this->fixture(Class_Membership::class, + ['id'=>2, + 'code'=>2, + 'libelle' => 'Abonnement invalide', + 'enabled' => 1]); + + $this->fixture(Class_Membership::class, + ['id'=>3, + 'code'=>3, + 'libelle' => 'Bouquets numériques', + 'enabled' => 1]); + + + $user = Class_Users::getIdentity(); + + $this->fixture(Class_User_Membership::class, + ['id' => 4, + 'membership_id' => 1, + 'user' => $user, + 'start_date' => '2012-05-01', + 'end_date' => '2013-01-01']); + + $this->fixture(Class_User_Membership::class, + ['id' => 2, + 'membership_id' => 2, + 'user' => $user, + 'start_date' => '1970-01-01', + 'end_date' => '1971-06-06']); + + $this->fixture(Class_User_Membership::class, + ['id' => 3, + 'membership_id' => 3, + 'user' => $user, + 'start_date' => '2019-01-01', + 'end_date' => '']); + + + Class_User_Membership::setTimesource(new TimeSourceForTest('2017-01-31')); + $this->_buildTemplateProfil(['id'=>1]); + $this->dispatch('/opac/abonne'); + } + + /** @test */ + public function pageShouldContainsAbonnements() { + $this->assertXPathContentContains('//dt[contains(@class,"user_info")]', 'Abonnements'); + } + + + /** @test */ + public function pageShouldContainsAbonneAdulte() { + $this->assertXPathContentContains('//dd//p//strong', 'Abonné adulte'); + } + + + /** @test */ + public function pageShouldContainsdu() { + $this->assertXPathContentContains('//dd//p//span', 'du 01/01/2012 au 01/01/2020'); + } + /** @test */ + public function pageShouldContainsBouquetsNumeriques() { + $this->assertXPathContentContains('//dd//p//strong', 'Bouquets numériques'); + } + + + /** @test */ + public function pageShouldContainsDuPremierJanvier2019() { + $this->assertXPathContentContains('//dd//p//span', 'du 01/01/2019'); + } + + + /** @test */ + public function pageShouldNotContainsAbonnementInvalide() { + $this->assertNotXPathContentContains('//dd//p//strong', 'Abonnement invalide'); + } +} + + +class TemplatesAbonneDispatchFicheWithMembershipBadgeAbonnementTest extends TemplatesIntonationAccountTestCase { + public function setUp() { + parent::setUp(); + Class_FileManager::setFileSystem(null); + + Class_User_ILSSubscription::setTimesource(new TimeSourceForTest('2022-01-01')); + $this->fixture(Class_User_Membership::class, + ['id'=> 12, + 'user' => Class_Users::getIdentity(), + 'membership' => Class_Membership::find(1), + 'start_date' => '2021-01-03', + 'end_date' => '2022-12-12']); + + $this->fixture(Class_User_Membership::class, + ['id'=> 15, + 'user' => Class_Users::getIdentity(), + 'membership' => Class_Membership::find(1), + 'start_date' => '2010-01-03', + 'end_date' => '2012-06-01']); + + $this->dispatch('/opac/abonne/fiche/id_profil/72'); + } + + public function tearDown(){ + Class_User_ILSSubscription::setTimesource(null); + parent::tearDown(); + } + + + /** @test */ + public function badgeSubscriptionContentShouldContainsAbonneAdulte12Decembre() { + $this->assertXPathContentContains('//span[contains(@class,"badge_text")]',"Abonné adulte 12/12/2022"); + } + + + /** @test */ + public function badgeSubscriptionCountShouldBeTwo() { + $this->assertXPathCount('//span[contains(@class,"subscription")]',2); + } +} + + + +class TemplatesAbonneDispatchFicheWithMembershipBadgeAbonnementExpiredButUniqueTest extends TemplatesIntonationAccountTestCase { + public function setUp() { + parent::setUp(); + Class_FileManager::setFileSystem(null); + + Class_User_ILSSubscription::setTimesource(new TimeSourceForTest('2022-01-01')); + + $this->dispatch('/opac/abonne/fiche/id_profil/72'); + } + + public function tearDown(){ + Class_User_ILSSubscription::setTimesource(null); + parent::tearDown(); + } + + + /** @test */ + public function badgeSubscriptionInformationTitleShouldContainsAbonneAdultePremierJanvier2020() { + $this->assertXPathContentContains('//span[contains(@class,"badge_tag danger")]//span[contains(@class,"badge_text")]',"Abonné adulte 01/01/2020"); + } +} + + + + +class TemplatesAbonneDispatchFicheBadgeAbonnementWithoutMembershipsTest extends TemplatesIntonationAccountTestCase { + public function setUp() { + parent::setUp(); + Class_FileManager::setFileSystem(null); + + Class_User_Membership::deleteBy([]); + + Class_User_ILSSubscription::setTimesource(new TimeSourceForTest('2020-01-01')); + + $this->dispatch('/opac/abonne/fiche/id_profil/72'); + } + + public function tearDown(){ + Class_User_ILSSubscription::setTimesource(null); + parent::tearDown(); + } + + + /** @test */ + public function badgeSubscriptionInformationContentShouldContainsAbonneAdultePremierJanvier2020() { + $this->assertXPathContentContains('//span[contains(@class,"badge_tag")]//span[contains(@class,"badge_text")]',"01/01/2020"); + } + + + /** @test */ + public function badgeSubscriptionInformationTitleShouldContainsAbonneAdultePremierJanvier2020() { + $this->assertXPathContentContains('//span[contains(@class,"badge_tag")]//span[contains(@class,"sr-only")]',"Vous êtes abonné(e) jusqu'au"); + } +} diff --git a/tests/scenarios/Templates/TemplatesPatronConfigurationsTest.php b/tests/scenarios/Templates/TemplatesPatronConfigurationsTest.php index 3a4ac7218173a0157e089cc2ed0e33c2d5f115a8..2ab41036b71e6ebb30bdb6a0430619adb359613c 100644 --- a/tests/scenarios/Templates/TemplatesPatronConfigurationsTest.php +++ b/tests/scenarios/Templates/TemplatesPatronConfigurationsTest.php @@ -98,7 +98,7 @@ class TemplatesPatronConfigurationsSubscriptionDateTest /** @test */ public function withSubscribtionIn2020DateShouldBeDisplayInSpanBadgeDanger() { $this->dispatch('/opac/abonne/configurations/id_profil/72'); - $this->assertXPathContentContains('//div//span[@class="badge_tag danger text-left badge badge-danger text-light"]', + $this->assertXPathContentContains('//div//span[@class="badge_tag danger subscription text-left badge badge-danger text-light"]', '01/01/2020'); } @@ -107,7 +107,7 @@ class TemplatesPatronConfigurationsSubscriptionDateTest public function withSubscribtionIn2020DateShouldBeDisplayInSpanBadgeSuccess() { Class_User_ILSSubscription::setTimeSource(new TimeSourceForTest('2019-02-12 11:25:31')); $this->dispatch('/opac/abonne/configurations/id_profil/72'); - $this->assertXPathContentContains('//div//span[@class="badge_tag success text-left badge badge-success text-light"]', + $this->assertXPathContentContains('//div//span[@class="badge_tag success subscription text-left badge badge-success text-light"]', '01/01/2020'); } @@ -116,9 +116,8 @@ class TemplatesPatronConfigurationsSubscriptionDateTest public function withSubscribtionIsAboutToExpireDateShouldBeDisplayInSpanBadgeWarning() { Class_User_ILSSubscription::setTimeSource(new TimeSourceForTest('2020-01-01 11:25:31')); $this->dispatch('/opac/abonne/configurations/id_profil/72'); - $this->assertXPathContentContains('//div//span[@class="badge_tag warning text-left badge badge-warning text-dark"]', - '01/01/2020', - $this->_response->getBody()); + $this->assertXPathContentContains('//div//span[@class="badge_tag warning subscription text-left badge badge-warning text-dark"]', + '01/01/2020'); }