Skip to content
Snippets Groups Projects
Commit c165e2fb authored by Patrick Barroca's avatar Patrick Barroca :grin:
Browse files

hotline #173292 : fix drive SQL queries with "left()"

parent 173ec51b
Branches
Tags
1 merge request!4691hotline #173292 : fix drive SQL queries with "left()"
Pipeline #21598 passed with stage
in 20 minutes and 32 seconds
- correctif #173292 : Drive : Suppression d'une erreur survenant dans le tableau de bord des rendez-vous
\ No newline at end of file
......@@ -113,10 +113,9 @@ class Admin_DriveCheckoutController extends ZendAfi_Controller_Action {
$library = Class_Bib::find($this->_getParam('id_bib'));
$date = $this->_getParam('date', $this->getCurrentDate());
$checkouts = Class_DriveCheckout::findAllBy(['role' => 'library',
'model' => $library,
'left(start_at,10)' => $date,
'order' => 'start_at']);
$checkouts = $library && (false !== ($timestamp = strtotime($date)))
? Class_DriveCheckout::findAllByStartingAt($library, $timestamp)
: [];
$holds = (new Storm_Collection($checkouts))
->injectInto(new Storm_Collection(),
......
......@@ -42,6 +42,13 @@ class Class_Bib_DriveOpening_Period {
}
public static function periodFor(DateTimeInterface $start,
DateTimeInterface $end) : DatePeriod {
return new DatePeriod($start,
new DateInterval('PT' . static::CHECKOUT_TIME_SLOT . 'M'),
$end);
}
public function __construct($library, $date, $opening) {
$this->_opening = $opening;
......@@ -124,9 +131,8 @@ class Class_Bib_DriveOpening_Period {
return $this->_times;
$day = $this->format('Y-m-d');
$period = new DatePeriod(new DateTime($day . ' ' . $this->start()),
new DateInterval('PT' . static::CHECKOUT_TIME_SLOT . 'M'),
new DateTime($day . ' ' . $this->end()));
$period = static::periodFor(new DateTime($day . ' ' . $this->start()),
new DateTime($day . ' ' . $this->end()));
$times = new Storm_Collection();
foreach($period as $step)
......@@ -141,4 +147,4 @@ class Class_Bib_DriveOpening_Period {
? 0
: $quota * $this->_times()->count();
}
}
\ No newline at end of file
}
......@@ -24,27 +24,43 @@ class Class_DriveCheckoutLoader extends Storm_Model_Loader {
if (!$library || !$user)
return;
return Class_DriveCheckout::findFirstBy(['library_id' => $library->getId(),
'user_id' => $user->getId(),
'where' => 'date(start_at) >= curdate()',
'order' => 'start_at']);
return ($futures = Class_DriveCheckout::query()
->eq('library_id', $library->getId())
->eq('user_id', $user->getId())
->gt_eq_left('start_at', 10, Class_DriveCheckout::getCurrentDate())
->order('start_at')
->limit(1)
->fetchAll())
? $futures[0]
: null;
}
public function findAllByLibraryAndDates($library, $start_date, $days_count) {
$checkouts = new Storm_Model_Collection();
for($i=0; $i<$days_count; $i++) {
$start_at = strftime('%Y-%m-%d', strtotime($start_date . ' +' . $i . ' day'));
public function findAllByLibraryAndDates(Class_Bib $library,
string $start_date,
int $days_count) : Storm_Model_Collection {
if (false === strtotime($start_date))
return new Storm_Model_Collection;
$checkouts = new Storm_Model_Collection;
foreach (range(0, $days_count - 1) as $step)
$checkouts
->addAll(Class_DriveCheckout::findAllBy(['role' => 'library',
'model' => $library,
'left(start_at,10)' => $start_at,
'order' => 'start_at']));
}
->addAll(Class_DriveCheckout::findAllByStartingAt($library,
strtotime($start_date . ' +' . $step . ' day')));
return $checkouts;
}
public function findAllByStartingAt(Class_Bib $library, int $timestamp) : array {
return Class_DriveCheckout::query()
->eq('library_id', $library->getId())
->eq_left('start_at', 10, date('Y-m-d', $timestamp))
->order('start_at')
->fetchAll();
}
public function findFor($id, $user) {
return $user
? Class_DriveCheckout::findFirstBy(['id' => (int)$id,
......@@ -54,12 +70,14 @@ class Class_DriveCheckoutLoader extends Storm_Model_Loader {
public function countBetweenForLibrary($start, $end, $library) {
return $library && $start && $end
? Class_DriveCheckout::countBy(['library_id' => $library->getId(),
'where' => sprintf('start_at >= "%s" and start_at < "%s"',
$this->_dateAsSql($start),
$this->_dateAsSql($end))])
: 0;
if (!$library || !$start || !$end)
return 0;
$params = ['library_id' => $library->getId(),
Storm_Query_Clause::greaterEqual('start_at', $this->_dateAsSql($start)),
Storm_Query_Clause::lesser('start_at', $this->_dateAsSql($end))];
return Class_DriveCheckout::countBy($params);
}
......@@ -71,15 +89,15 @@ class Class_DriveCheckoutLoader extends Storm_Model_Loader {
}
public function countByPreviousMonthFrom($date_time) {
public function countByPreviousMonthFrom(DateTimeInterface $date_time) : int {
$date_time->modify('previous month midnight');
$params = [ Storm_Query_Clause::greaterEqual('start_at', $this->_dateAsSql($date_time)) ];
return Class_DriveCheckout::countBy(['where' => sprintf('start_at >= "%s"',
$this->_dateAsSql($date_time))]);
return Class_DriveCheckout::countBy($params);
}
protected function _dateAsSql($date) {
protected function _dateAsSql(DateTimeInterface $date) {
return $date->format('Y-m-d H:i:s');
}
}
......@@ -93,10 +111,10 @@ class Class_DriveCheckout extends Storm_Model_Abstract {
const DATETIME_FORMAT = 'Y-m-d H:i:s';
protected
$_loader_class = 'Class_DriveCheckoutLoader',
$_loader_class = Class_DriveCheckoutLoader::class,
$_table_name = 'drive_checkout',
$_belongs_to = ['user' => ['model' => 'Class_Users'],
'library' => ['model' => 'Class_Bib']],
$_belongs_to = ['user' => ['model' => Class_Users::class],
'library' => ['model' => Class_Bib::class]],
$_default_attribute_values = ['start_at' => null,
'user_id' => null,
......
Subproject commit 4f8e91183ee11d0a1be8205439e1abae14ac4f03
Subproject commit d2015db051956daad6aa242baa24908ce761d77f
......@@ -21,9 +21,6 @@
class DriveCheckOutBookingNotActiveTest extends AbstractControllerTestCase {
protected $_storm_default_to_volatile = true;
public function setUp() {
parent::setUp();
Class_AdminVar::set('ENABLE_DRIVE_CHECKOUT', 0);
......@@ -48,7 +45,6 @@ class DriveCheckOutBookingNotActiveTest extends AbstractControllerTestCase {
abstract class DriveCheckOutBookingTestCase extends AbstractControllerTestCase {
protected
$_storm_default_to_volatile = true,
$_marcus,
$_mail_transport;
......@@ -95,7 +91,7 @@ abstract class DriveCheckOutBookingTestCase extends AbstractControllerTestCase {
protected function _setupLibraries() {
$lib_hotel_dieu = $this
->fixture('Class_Bib',
->fixture(Class_Bib::class,
['id' => 1,
'libelle' => 'Hotel-Dieu',
'closed_on_holidays' => false,
......@@ -111,12 +107,12 @@ abstract class DriveCheckOutBookingTestCase extends AbstractControllerTestCase {
->beDrive(),
]]);
$this->fixture('Class_Bib',
$this->fixture(Class_Bib::class,
['id' => 2,
'enable_drive' => 1,
'libelle' => 'Albert Camus']);
$this->fixture('Class_Bib',
$this->fixture(Class_Bib::class,
['id' => 3,
'enable_drive' => 1,
'libelle' => 'Mauricette-Rafin',
......@@ -126,7 +122,7 @@ abstract class DriveCheckOutBookingTestCase extends AbstractControllerTestCase {
]
]);
$this->fixture('Class_Bib',
$this->fixture(Class_Bib::class,
['id' => 4,
'enable_drive' => 0,
'libelle' => 'Le Turbomoteur']);
......@@ -386,13 +382,12 @@ class DriveCheckOutBookingPlanOnBibWithDriveStartingNextWeekTest extends DriveCh
class DriveCheckOutBookingPlanWithFuturExistingTest extends DriveCheckOutBookingTestCase {
public function setUp() {
parent::setUp();
$this->onLoaderOfModel('Class_DriveCheckout')
->whenCalled('findFuturefor')->with(Class_Bib::find(2), $this->_marcus)
->answers($this->fixture('Class_DriveCheckout',
['id' => 2,
'library_id' => 2,
'user_id' => $this->_marcus->getId(),
'start_at' => '2020-05-12 09:00:00']));
$this->fixture(Class_DriveCheckout::class,
['id' => 2,
'library_id' => 2,
'user_id' => $this->_marcus->getId(),
'start_at' => '2020-05-12 09:00:00']);
$this->dispatch('/opac/drive-checkout/plan');
}
......@@ -688,14 +683,23 @@ class DriveCheckOutBookingPlanBibHotelDieuAllowTodayTest extends DriveCheckOutBo
class DriveCheckOutBookingPlanBibHotelDieuQuotaFullOn2020_05_12Test
extends DriveCheckOutBookingTestCase {
protected function _occupyFull2020_05_12() {
$period = Class_Bib_DriveOpening_Period::periodFor(new DateTime('2020-05-12 09:00'),
new DateTime('2020-05-12 18:00'));
$i = 0;
foreach($period as $step)
$this->fixture(Class_DriveCheckout::class,
['id' => 884 + $i++,
'library_id' => 1,
'user_id' => 48849,
'start_at' => '2020-05-12 ' . $step->format('H:i') . ':00']);
}
public function setUp() {
parent::setUp();
$this->onLoaderOfModel('Class_DriveCheckout')
->whenCalled('countBetweenForLibrary')
->willDo(function($start, $end, $library)
{
return '2020-05-12' == $start->format('Y-m-d') ? 600 : 0;
});
$this->_occupyFull2020_05_12();
$this->dispatch('/opac/drive-checkout/plan/id_bib/1');
}
......@@ -1139,4 +1143,4 @@ class DriveCheckOutBookingPlanWithOnlyOnePossibleLibrary
$this->dispatch('/opac/drive-checkout/plan');
$this->assertNotRedirect();
}
}
\ No newline at end of file
}
......@@ -23,9 +23,7 @@
require_once('application/modules/admin/controllers/DriveCheckoutController.php');
abstract class DriveCheckOutAdminControllerTestCase extends Admin_AbstractControllerTestCase {
protected
$_storm_default_to_volatile = true,
$_mail_transport;
protected MockMailTransport $_mail_transport;
public function setUp() {
parent::setUp();
......@@ -40,22 +38,23 @@ abstract class DriveCheckOutAdminControllerTestCase extends Admin_AbstractContro
$this->_mail_transport = new MockMailTransport();
Zend_Mail::setDefaultTransport($this->_mail_transport);
$lib_hotel_dieu = $this->fixture('Class_Bib',
['id' => 1,
'libelle' => 'Hotel-Dieu',
'enable_drive' => true,
'ouvertures' => [
Class_Ouverture::chaqueLundi('00:00', '00:00', '12:00', '18:00')
->beDrive(),
Class_Ouverture::chaqueMardi('09:00', '12:00', '14:00', '18:00')
->beDrive()]]);
$lib_camus = $this->fixture('Class_Bib',
$lib_hotel_dieu = $this
->fixture(Class_Bib::class,
['id' => 1,
'libelle' => 'Hotel-Dieu',
'enable_drive' => true,
'ouvertures' => [
Class_Ouverture::chaqueLundi('00:00', '00:00', '12:00', '18:00')
->beDrive(),
Class_Ouverture::chaqueMardi('09:00', '12:00', '14:00', '18:00')
->beDrive()]]);
$lib_camus = $this->fixture(Class_Bib::class,
['id' => 2,
'libelle' => 'Albert Camus',
'enable_drive' => true]);
$lib_maurissette = $this->fixture('Class_Bib',
$lib_maurissette = $this->fixture(Class_Bib::class,
['id' => 3,
'libelle' => 'Maurissette',
'enable_drive' => false]);
......@@ -80,20 +79,20 @@ abstract class DriveCheckOutAdminControllerTestCase extends Admin_AbstractContro
'bib' => $lib_hotel_dieu]);
$this->fixture('Class_CodifSection',
$this->fixture(Class_CodifSection::class,
['id' => 3,
'libelle' => 'Jeunesse']);
$this->fixture('Class_CodifEmplacement',
$this->fixture(Class_CodifEmplacement::class,
['id' => 2,
'libelle' => 'BD',
'regles' => '995$e=bd']);
$holds = [Class_WebService_SIGB_Reservation::newInstanceWithEmptyExemplaire()
->setExemplaireOPAC($this->fixture('Class_Exemplaire',
->setExemplaireOPAC($this->fixture(Class_Exemplaire::class,
['id' => 2,
'code_barres' => 'tintin123',
'notice' => $this->fixture('Class_Notice',
'notice' => $this->fixture(Class_Notice::class,
['id' => 123,
'titre_principal' => 'Tintin à Dole']),
'emplacement' => 2,
......@@ -135,38 +134,39 @@ abstract class DriveCheckOutAdminControllerTestCase extends Admin_AbstractContro
'last_login' => 0,
'bib' => $lib_hotel_dieu])
->setFicheSigb(['type_comm' => Class_IntBib::COM_NANOOK,
'fiche' => (new Class_WebService_SIGB_Emprunteur(4, 'Maurice'))
->reservationsAddAll($holds)]);
'fiche' => ((new Class_WebService_SIGB_Emprunteur(4,
'Maurice'))
->reservationsAddAll($holds))]);
$this->fixture('Class_DriveCheckout',
$this->fixture(Class_DriveCheckout::class,
['id' => 1,
'user' => $emilie,
'library' => $lib_hotel_dieu,
'start_at' => '2020-05-12 09:00:00',
'created_at' => '0000-00-00 00:00:00']);
$this->fixture('Class_DriveCheckout',
$this->fixture(Class_DriveCheckout::class,
['id' => 2,
'user' => $bernard,
'library' => $lib_hotel_dieu,
'start_at' => '2020-05-12 14:00:00',
'created_at' => '2020-05-02 23:46:33']);
$this->fixture('Class_DriveCheckout',
$this->fixture(Class_DriveCheckout::class,
['id' => 3,
'user' => $maurice,
'library' => $lib_camus,
'start_at' => '2020-05-14 09:00:00',
'created_at' => '0000-00-00 00:00:00']);
$this->fixture('Class_DriveCheckout',
$this->fixture(Class_DriveCheckout::class,
['id' => 4,
'user' => $emilie,
'library' => $lib_camus,
'start_at' => '2020-05-14 09:15:00',
'created_at' => '2020-05-03 19:32:55']);
$this->fixture('Class_DriveCheckout',
$this->fixture(Class_DriveCheckout::class,
['id' => 5,
'user' => $bernard,
'library' => $lib_camus,
......@@ -259,12 +259,21 @@ class DriveCheckoutAdminControllerIndexTest extends DriveCheckOutAdminController
class DriveCheckoutAdminControllerListHotelDieuTest extends DriveCheckOutAdminControllerTestCase {
protected bool $_storm_mock_zend_adapter = true;
protected array $_storm_scopes = ['->findAllByLibraryAndDates'];
public function setUp() {
parent::setUp();
$this->dispatch('/admin/drive-checkout/list/id_bib/1');
}
/** @test */
public function shouldQueryCheckoutsOf2020_05_12() {
$this->assertSql("SELECT `drive_checkout`.* FROM `drive_checkout` WHERE (`drive_checkout`.`library_id` = 1 AND LEFT(`drive_checkout`.`start_at`, 10) = '2020-05-12') ORDER BY `drive_checkout`.`start_at` ASC");
}
/** @test */
public function pageTitleShouldBeRendezVousHotelDieu() {
$this->assertXPathContentContains('//h1', 'Drive : rendez-vous : Hotel-Dieu, 12 mai 2020');
......@@ -493,12 +502,23 @@ class DriveCheckoutAdminControllerListAllHoldsForMauriceIdFourTest extends Drive
class DriveCheckoutAdminControllerExportItemsCSVCamusOnMayFourteenthTest extends DriveCheckOutAdminControllerTestCase {
protected bool $_storm_mock_zend_adapter = true;
protected array $_storm_scopes = ['->findAllByStartingAt'];
public function setUp() {
parent::setUp();
$this->dispatch('/admin/drive-checkout/items-csv/id_bib/2/date/2020-05-14');
}
/** @test */
public function shouldQueryCheckoutsOf2020_05_14() {
$this->assertSql("SELECT `drive_checkout`.* FROM `drive_checkout` WHERE (`drive_checkout`.`library_id` = 2 AND LEFT(`drive_checkout`.`start_at`, 10) = '2020-05-14') ORDER BY `drive_checkout`.`start_at` ASC");
}
/** @test */
public function filenameShouldBe2020_05_14_Albert_Camus_Rendez_Vous() {
$this->assertContains(['name' => 'Content-Type',
......@@ -549,7 +569,12 @@ class DriveCheckoutAdminControllerDeleteCheckoutThreeTest extends DriveCheckOutA
class DriveCheckoutAdminControllerPlanNewCheckoutForMauriceTest extends DriveCheckOutAdminControllerTestCase {
class DriveCheckoutAdminControllerPlanNewCheckoutForMauriceTest
extends DriveCheckOutAdminControllerTestCase {
protected bool $_storm_mock_zend_adapter = true;
protected array $_storm_scopes = ['->findFutureFor'];
public function setUp() {
parent::setUp();
Class_DriveCheckout::find(3)->delete();
......@@ -557,6 +582,13 @@ class DriveCheckoutAdminControllerPlanNewCheckoutForMauriceTest extends DriveChe
}
/** @test */
public function shouldHaveQueriedNextCheckoutOnEachLibrary() {
$this->assertSql("SELECT `drive_checkout`.* FROM `drive_checkout` WHERE (`drive_checkout`.`library_id` = 1 AND `drive_checkout`.`user_id` = 4 AND LEFT(`drive_checkout`.`start_at`, 10) >= '2023-03-27') ORDER BY `drive_checkout`.`start_at` ASC LIMIT 1");
$this->assertSql("SELECT `drive_checkout`.* FROM `drive_checkout` WHERE (`drive_checkout`.`library_id` = 2 AND `drive_checkout`.`user_id` = 4 AND LEFT(`drive_checkout`.`start_at`, 10) >= '2023-03-27') ORDER BY `drive_checkout`.`start_at` ASC LIMIT 1");
}
/** @test */
public function pageTitleShouldBePlanCheckout() {
$this->assertXPathContentContains('//title', 'Planifier un retrait pour maurice');
......@@ -648,7 +680,9 @@ class DriveCheckoutAdminControllerDownloadCheckoutThreeTest
class DriveCheckoutAdminControllerPlanInvalidCheckoutForMauriceHotelDieuOnMayFourteenthTest extends DriveCheckOutAdminControllerTestCase {
class DriveCheckoutAdminControllerPlanInvalidCheckoutForMauriceHotelDieuOnMayFourteenthTest
extends DriveCheckOutAdminControllerTestCase {
public function setUp() {
parent::setUp();
Class_DriveCheckout::find(3)->delete();
......
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