Commit d8f755e1 authored by Arthur Suzuki's avatar Arthur Suzuki Committed by Laurent
Browse files

dev #86039 dev#86039 : SIGB Koha : add grouped holds capabilities

dev #86039 prepares calendar hold
parent 6229f181
Pipeline #8239 failed with stage
in 28 minutes and 59 seconds
'86039' =>
['Label' => $this->_('PAIRING [Contractuel] BDP89 Specs prêt malle'),
'Desc' => '',
'Image' => '',
'Video' => '',
'Category' => '',
'Right' => function($feature_description, $user) {return true;},
'Wiki' => '',
'Test' => '',
'Date' => '2019-07-26'],
\ No newline at end of file
- ticket #86039 : PAIRING [Contractuel] BDP89 Specs prêt malle
\ No newline at end of file
......@@ -671,7 +671,7 @@ class RechercheController extends ZendAfi_Controller_Action {
$viewRenderer = $this->getHelper('ViewRenderer');
$viewRenderer->setNoRender();
if (!$user=$this->userConnected())
if (!$user = $this->userConnected())
return;
$id_bib = (int)$this->_getParam('id_bib');
......@@ -681,15 +681,123 @@ class RechercheController extends ZendAfi_Controller_Action {
if (Class_CosmoVar::isSiteRetraitResaPatronLibrary())
$code_annexe = $user->getUserIdSite();
$comm = new Class_CommSigb();
$ret = $comm->reserverExemplaire($id_bib, $id_exemplaire, $code_annexe);
try {
$ret = Class_CommSigb::getInstance()->reserverExemplaire($id_bib, $id_exemplaire, $code_annexe);
} catch(Class_WebService_SIGB_RequiresCalendarHoldException $e) {
return $this->_redirect(sprintf('/recherche/reservation-calendar-ajax/id_bib/%s/copy_id/%s/code_annexe/%s',
$id_bib,
$id_exemplaire,
$code_annexe));
}
$this->renderPopupResult($this->view->_('Réservation'),
$this->_getHoldMessage($user, $id_exemplaire, $ret));
}
public function reservationCalendarAjaxAction() {
$id_bib = (int)$this->_getParam('id_bib');
$id_exemplaire = $this->_getParam('copy_id');
$code_annexe = $this->_getParam('code_annexe');
$form = $this->view
->newForm(['id' => 'reservation-calendar'])
->setAction($this->view->url())
->addElement('dateRangePicker',
'reservation-date',
['label' => $this->_('Période de réservation'),
'start' => ['name' => 'reservedate',
'allowEmpty' => false,
'DateFormat' => 'DD/MM/YYYY',
'validators' => [new Zend_Validate_Date('DD/MM/YYYY')]],
'end' => ['name' => 'expirationdate',
'allowEmpty' => false,
'DateFormat' => 'DD/MM/YYYY',
'validators' => [new Zend_Validate_Date('DD/MM/YYYY')]]
])
->addElement('Submit', $this->_('Valider'))
->addElement('Button', $this->_('Annuler'),
['onclick' => 'opacDialogClose();return false;'])
->addUniqDisplayGroup('hold');
if ($this->_request->isPost() && $form->isValid($this->_request->getPost())) {
$reservedate = Class_Date::frToIso($this->_getParam('reservedate'));
$expirationdate = Class_Date::frToIso($this->_getParam('expirationdate'));
$ret = Class_CommSigb::getInstance()->reserverExemplaire($id_bib,
$id_exemplaire,
$code_annexe,
$reservedate,
$expirationdate);
if ($ret['statut'])
return $this->renderPopupResult($this->view->_('Réservation'),
$this->_getHoldMessage($this->userConnected(),
$id_exemplaire,
$ret));
$form
->addError($ret['erreur'])
->addDecorator('Errors');
}
$holds = $this->_renderHolds($id_exemplaire);
$form = $this->view->renderForm($form);
return $this->renderPopupResult($this->view->_('Réservation'),
Class_ScriptLoader::getInstance()->html()
. $holds
. $form );
}
protected function _renderHolds($id_exemplaire) {
$item = Class_Exemplaire::find($id_exemplaire);
$holds = Class_CommSigb::getInstance()->holdsForItem($item)['holds'];
usort($holds,
function($a, $b)
{
return strcmp($a->getReserveDate(), $b->getReserveDate());
});
$html = implode('',
array_map(function($hold)
{
return $this->view->tag('li',
$hold->renderRange());
},
$holds));
$js_holds = json_encode(array_map(
function($hold)
{
return [$hold->getReserveDate(), $hold->getExpirationDate()];
},
$holds));
Class_ScriptLoader::getInstance()
->addAdminScript('jquery_ui_datepicker_i18n/datepicker-fr.js')
->addJQueryReady('$.datepicker.setDefaults($.datepicker.regional["' . ((Zend_Registry::get('locale') == 'en_US') ? '' : 'fr' ). '"]);
$("input").blur();
$("#holds_view").datepicker(
{
numberOfMonths: 4,
beforeShowDay: function(date) {
var holds = '. $js_holds . ';
var hold = holds.find( (hold) => {
return (new Date(hold[0]) <= date) && (new Date(hold[1]) >= date);
});
if (undefined == hold)
return [false, "day-without-hold"];
return [false, "day-with-hold", "' . $this->_("Reservation déjà présente ce jour") . '"];
}}
);');
return '<div id="holds_view"></div>' . $this->view->tag('div', $this->view->tag('ul',$html));
}
protected function _getHoldMessage($user, $item_id, $response) {
if ($response['erreur'])
return $response['erreur'];
......
......@@ -30,6 +30,7 @@ abstract class Cosmo_DataProfileControllerTestCase extends CosmoControllerTestCa
->setId(56)
->setItemField(Class_IntProfilDonnees::FIELD_ITEM_ID_ORIGINE, ['zone' => '999',
'champ' => 'c'])
->setItemField(Class_IntProfilDonnees::FIELD_ITEM_BUNDLE_ID, 8)
->save();
Class_IntProfilDonnees::forNanook()
......@@ -334,6 +335,12 @@ class Cosmo_DataProfileControllerEditUnimarcKohaTest extends Cosmo_DataProfileCo
}
/** @test */
public function itemBundleIdShouldBePresent() {
$this->assertXPath('//form//select[@id="champ_bundle_id"]/option[@value="8"][@selected]');
}
/** @test */
public function multiInputItemUrlShouldBePresent() {
$this->assertXPath('//form//div[@id="multi_inputs_item_url"]');
......@@ -416,6 +423,7 @@ class Cosmo_DataProfileControllerPostEditUnimarcKohaFileFormatTest extends Cosmo
'champ_genre' => 'z',
'champ_emplacement' => 'u',
'champ_annexe' => 'a',
'champ_bundle_id' => '8',
'champ_availability' => 't',
'url_zone' => [0 => '932'],
'url_champ' => [0 => 'n'],
......@@ -549,6 +557,12 @@ class Cosmo_DataProfileControllerPostEditUnimarcKohaFileFormatTest extends Cosmo
public function interestFieldShouldBe7() {
$this->assertEquals('7', $this->_koha->getInterestField());
}
/** @test */
public function bundleIdFieldShouldBe8() {
$this->assertEquals('8', $this->_koha->getBundleIdField());
}
}
......
......@@ -721,7 +721,8 @@ class notice_integration {
->setIdNotice($id_notice)
->setIdOrigine($this->notice['id_origine'])
->setIdBib($this->id_bib)
->setIdIntBib($this->id_int_bib);
->setIdIntBib($this->id_int_bib)
->setIdDataProfile($this->id_profil);
/**
* @see http://forge.afi-sa.fr/issues/14279
......
......@@ -126,7 +126,16 @@ function getBlocsParams($id_bib, $type, $valeurs) {
'use_card_number',
['Codification_disponibilites' => function($id, $valeur){
return getTextArea($id, $valeur, 30, 20);
}]];
}],
['withdrawn_mapping' => function($id, $valeur){
return getTextArea($id, $valeur, 30, 5);
}],
'bundled_holds_minimal_duration',
'bundled_holds_maximal_duration',
['grouped_holds_itypes' => function($id, $valeur){
return getTextArea($id, $valeur, 30, 5);
}]
];
if ($clef == COM_OPSYS)
$champs_params[0] = ['url_serveur', 'catalogue_web', 'reserver_retrait_bib_abonne'];
......
<?php
$adapter = Zend_Db_Table_Abstract::getDefaultAdapter();
try {
$adapter->query('alter table exemplaires add column id_data_profile int(11) unsigned');
} catch(Exception $e) {}
......@@ -27,7 +27,9 @@ abstract class KohaRecordIntegrationTestCase extends NoticeIntegrationTestCase {
public function getProfilDonnees() {
return Class_IntProfilDonnees::forKoha()->getRawAttributes();
return Class_IntProfilDonnees::forKoha()
->setIdProfil(45)
->getRawAttributes();
}
}
......@@ -73,11 +75,6 @@ class KohaRecordIntegrationRecordWithoutMainTitleTest extends KohaRecordIntegrat
class KohaRecordIntegrationBdMilleniumTest extends KohaRecordIntegrationTestCase {
public function getProfilDonnees() {
return Class_IntProfilDonnees::forKoha()->getRawAttributes();
}
public function setUp() {
parent::setUp();
$this->loadNotice('unimarc_bd_millenium');
......@@ -99,6 +96,18 @@ class KohaRecordIntegrationBdMilleniumTest extends KohaRecordIntegrationTestCase
public function collectionMilleniumShouldBeIndexed() {
$this->assertEquals('MILLENIUM MILENIUM', $this->millenium->getRawAttributes()['collection']);
}
/** @test */
public function firstItemIdDataProfileShouldBe45() {
$this->assertEquals(45, Class_Exemplaire::find(1)->getIdDataProfile());
}
/** @test */
public function itemDataProfileLabelShouldBeUnimarcKoha() {
$this->assertEquals('Unimarc Koha', Class_Exemplaire::find(1)->getDataProfile()->getLibelle());
}
}
......
......@@ -182,18 +182,13 @@ class Class_Agenda_SQY_EventWrapper {
}
public function formatDateForArticle($date) {
return implode('-', array_reverse(explode('/', $date)));
}
public function setDateStart($date) {
$this->_wrapped_instance->setEventsDebut($this->formatDateForArticle($date));
$this->_wrapped_instance->setEventsDebut(Class_Date::frToIso($date));
}
public function setDateEnd($date) {
$this->_wrapped_instance->setEventsFin($this->formatDateForArticle($date));
$this->_wrapped_instance->setEventsFin(Class_Date::frToIso($date));
}
......
......@@ -130,7 +130,7 @@ class Class_CommSigb {
* @param string $code_annexe
* @return array
*/
public function reserverExemplaire($id_bib, $exemplaire_id, $code_annexe) {
public function reserverExemplaire($id_bib, $exemplaire_id, $code_annexe, $reservedate = null, $expirationdate = null) {
if (!$user = Class_Users::getIdentity())
return $this->_error($this->_('Vous devez vous connecter pour réserver un document.'));
......@@ -140,8 +140,14 @@ class Class_CommSigb {
if(!$exemplaire = Class_Exemplaire::find($exemplaire_id))
return $this->_error($this->_('Document introuvable'));
$reserver = function ($user, $sigb) use ($exemplaire, $code_annexe) {
$result = $sigb->reserverExemplaire($user, $exemplaire, $code_annexe);
$reserver = function ($user, $sigb) use ($exemplaire, $code_annexe, $reservedate, $expirationdate) {
$params = [$user, $exemplaire, $code_annexe];
if ($reservedate && $expirationdate)
$params = array_merge($params, [$reservedate, $expirationdate]);
$result = call_user_func_array([$sigb, 'reserverExemplaire'],
$params);
if (true === $result['statut'])
$user->notifyHold($exemplaire, $code_annexe);
......@@ -226,6 +232,11 @@ class Class_CommSigb {
}
public function holdsForItem($item) {
return $item->getSIGBComm()->holdsForItem($item);
}
/**
* @param Class_Users $user
* @param int $id_pret
......
......@@ -35,6 +35,12 @@ class Class_Date {
}
}
public static function frToIso($date) {
return implode('-', array_reverse(explode('/', $date)));
}
/*
* @param string $dateFormat Format used to generate the date
* @return string Today's date
......
......@@ -81,7 +81,11 @@ class Class_Exemplaire extends Storm_Model_Abstract {
'referenced_in' => 'id_origine'],
'int_bib' => [ 'model' => 'Class_IntBib',
'referenced_in' => 'id_int_bib']];
'referenced_in' => 'id_int_bib'],
'data_profile' => ['model' => 'Class_IntProfilDonnees',
'referenced_in' => 'id_data_profile']
];
protected $_default_attribute_values = [
'id_origine' => null,
......@@ -98,6 +102,7 @@ class Class_Exemplaire extends Storm_Model_Abstract {
'date_nouveaute' => '',
'to_delete' => false,
'id_int_bib' => 0,
'id_data_profile' => 0,
'type' => Class_Notice::TYPE_BIBLIOGRAPHIC,
'cote' => ''];
......@@ -237,7 +242,9 @@ class Class_Exemplaire extends Storm_Model_Abstract {
'id_int_bib' => $this->getIdIntBib(),
'id_bib' => $this->getIdBib(),
'copy_id' => $this->getId(),
'code_annexe' => $this->_getBranchCode()]);
'code_annexe' => $this->_getBranchCode()],
null,
false);
}
......@@ -421,11 +428,14 @@ class Class_Exemplaire extends Storm_Model_Abstract {
}
/**
* /!\ Temporary fix to #13903
*/
protected function get995Key($data) {
return (isset($data['clef'])) ? $data['clef'] : $data['code'];
if (isset($data['clef']))
return $data['clef'];
if (isset($data['code']))
return $data['code'];
return null;
}
public function toRaw() {
......@@ -466,6 +476,23 @@ class Class_Exemplaire extends Storm_Model_Abstract {
}
public function getBundle() {
if (!$data_profile = $this->getDataProfile())
return null;
$bundle_id_field = $data_profile->getBundleIdField();
$bundle_id = $this->getSubfield($bundle_id_field);
$bundle_item = Class_Exemplaire::getLoader()
->findFirstBy(['id_int_bib' => $this->getIdIntBib(),
'id_origine' => $bundle_id]);
return $bundle_item
? $bundle_item->getNotice()
: null;
}
public function isLoanable() {
if(!$record = $this->getNotice())
return false;
......
......@@ -42,6 +42,7 @@ class IntProfilDonneesLoader extends Storm_Model_Loader {
Class_IntProfilDonnees::FIELD_ITEM_SECTION => '',
Class_IntProfilDonnees::FIELD_ITEM_EMPLACEMENT => '',
Class_IntProfilDonnees::FIELD_ITEM_ANNEXE => '',
Class_IntProfilDonnees::FIELD_ITEM_BUNDLE_ID => '',
Class_IntProfilDonnees::FIELD_ITEM_AVAILABILITY => ''];
}
......@@ -329,6 +330,7 @@ class Class_IntProfilDonnees extends Storm_Model_Abstract {
FIELD_ITEM_SECTION = 'champ_section',
FIELD_ITEM_EMPLACEMENT = 'champ_emplacement',
FIELD_ITEM_ANNEXE = 'champ_annexe',
FIELD_ITEM_BUNDLE_ID = 'champ_bundle_id',
FIELD_ITEM_AVAILABILITY = 'champ_availability',
FIELD_ITEM_URL = 'champ_url',
FIELD_ITEM_ID_ORIGINE = 'champ_id_origine',
......@@ -1015,6 +1017,11 @@ class Class_IntProfilDonnees extends Storm_Model_Abstract {
}
public function getBundleIdField() {
return $this->getProfilePrefs()->getItemBundleIdField();
}
public function getNoveltyFormat() {
return $this->getProfilePrefs()->getItemNoveltyFormat();
}
......
......@@ -21,7 +21,6 @@
class Class_ProfilePrefs extends Class_Entity {
public function getItemZone() {
$prefs = $this->getItemPrefs();
return isset($prefs[Class_IntProfilDonnees::FIELD_ITEM_ZONE])
......@@ -69,6 +68,11 @@ class Class_ProfilePrefs extends Class_Entity {
}
public function getItemBundleIdField() {
return $this->getItemPrefs()[Class_IntProfilDonnees::FIELD_ITEM_BUNDLE_ID];
}
public function getPatronXmlField() {
return $this->getPrefsXml()[Class_IntProfilDonnees::XML_PATRON_FIELD];
}
......
......@@ -47,6 +47,7 @@ class Class_ProfileSerializer_UnimarcRecord extends Class_ProfileSerializer_Abst
->populateItemSection()
->populateItemEmplacement()
->populateItemAnnexe()
->populateItemBundleId()
->populateItemAvailability()
->populateItemNoveltyZoneAndField()
->populateItemNoveltyFormat()
......
......@@ -140,7 +140,7 @@ class Class_RendezVous extends Storm_Model_Abstract {
if (false === strpos($value, '/'))
return $value;
return implode('-', array_reverse(explode('/', $value)));
return Class_Date::frToIso($value);
}
......
......@@ -93,7 +93,7 @@ class Class_SearchCriteria_DateRange extends Class_SearchCriteria_Abstract {
protected function _sqlFormat($value) {
return implode('-', array_reverse(explode('/', $value)));
return Class_Date::frToIso($value);
}
......
......@@ -1198,8 +1198,8 @@ class Class_Users extends Storm_Model_Abstract {
$loans->uasort(function($a, $b)
{
return strcmp(implode('/', array_reverse(explode('/', $a->getIssueDate()))),
implode('/', array_reverse(explode('/', $b->getIssueDate()))));
return strcmp(Class_Date::frToIso($a->getIssueDate()),
Class_Date::frToIso($b->getIssueDate()));
});
return Class_User_CardsOperationDecorator::decorateAll($loans, $this);
}
......
......@@ -161,7 +161,14 @@ abstract class Class_WebService_SIGB_AbstractILSDIPatronInfoReader {
* @param array $attributes
*/
public function startHold($attributes) {
$this->_current_operation = $this->_currentHold = Class_WebService_SIGB_Reservation::newInstanceWithEmptyExemplaire();
$this->_current_operation = $this->_currentHold = call_user_func([$this->getHoldClassName(),
'newInstanceWithEmptyExemplaire']);
}
public function getHoldClassName() {
return 'Class_WebService_SIGB_Reservation';
}
......
......@@ -33,7 +33,7 @@ class Class_WebService_SIGB_Emprunt extends Class_WebService_SIGB_ExemplaireOper
public function getDateRetourISO8601() {
return implode('-', array_reverse(explode('/', $this->getDateRetour())));
return Class_Date::frToIso($this->getDateRetour());
}
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment