This topic is locked

Reserve the shared resources of a Company

3/19/2020 6:29:28 AM
PHPRunner Tips and Tricks
fhumanes author


Nowadays, with the rise of teleworking and jobs outside the office, the good management of companies' resources is more relevant, these situations are not new, but at the moment the needs of the media and the optimization of their management.
For example, a garage space assigned to a person, when this person is on vacation or traveling for work, can offer this space to another colleague who has not assigned it.
To understand how it works, it is very important to understand what were the requirements that I used to do the development.
Application requirements:

  • The Company has an inventory of all the means / resources that it is providing for its workers. These goods have a classification that indicates:

    Middle key.
  • Maximum reservation time (it is not the same to reserve a meeting room as a parking space).
  • Starting time of day when you can book.
  • End time of day when you can book.
    All the media (meeting rooms, projectors, garage spaces, cars, offices, desks, etc.) have a person from the organization as "owner / manager".
    It is the owners who indicate the dates on which the medium will be able to be shared. Media that could be general, such as a meeting room, also have an "owner" that defines the periods of availability.
    All availability inquiries will take place in a certain period. Now the application has to show availability and meetings for 10 days and up to 30 days more than the current date. These are CONFIG parameters that can be changed without any problem.
    Everyone can see the reserved media and their availability, but only the owners of the media or the reservation can change these or cancel the reservation.
    Administrators can do anything, without restrictions.
    The application in DEMO mode is at https://fhumanes.com/reservations
    The access users you have are:
    admin / admin - Administrator

    user1 / user1 - Normal user

    user2 / user2 - Normal user
    As I always indicate in these examples that I do, the source is to be downloaded and each one adapts it to your Company.
    Also, for those of you starting with PHPRunner, this example can help you learn many of the features of this excellent programming environment. It doesn't have a lot of code and it's very easy to read.
    Technical description of the development
    It has been developed in PHPRunner 10.2 and Mysql.
    The data model is quite simple:


The only "secret" that it has, with respect to other developments that I have in the portal, is that every time a reservation is made, the "available_block" table is updated, which are the date blocks in which the medium is free to be able to be reserved.


(1) Although the information is not presented in the classic "LIST", the application maintains the characteristics of the filters and the search functions.
(2) To display the date ranges, the DayPilot javascript libraries have been used, which I have used on other occasions. It is a DEMO version.
(3) In the availability and in the reservations, when positioning on them, it provides information in a popup and if it is clicked it shows in a new window to make the reservation or modify it.


The application is in English and Spanish.
Next I will leave some examples of the source code, so you can appreciate how simple it is to integrate with javascript libraries, in this case with Daypilot.
daypilot_availability.php (graph to facilitate the availability of dates in reservations)



<?php

$V_idavailability = $_SESSION['idavailability'];

$date_range_evaluations_min = $_SESSION['config'][array_search('DATE_RANGE_EVALUATIONS_MIN', array_column($_SESSION['config'], 'name'))][value];

$date_range_evaluations_max = $_SESSION['config'][array_search('DATE_RANGE_EVALUATIONS_MAX', array_column($_SESSION['config'], 'name'))][value];

// $V_now = strtotime(now());

$date = new DateTime(now());

$V_now = strtotime($date->format('d-m-Y H:i:s')."$date_range_evaluations_min days");

$V_now = date("Y-m-d",$V_now)."T00:00:01";

$V_tot_day = $date_range_evaluations_max - $date_range_evaluations_min;

if ($_SESSION['language'] == 'Spanish') {

$language = 'es-es'; // Spanish

$range_row = 20;

$formatDate = "dd/MM/yyyy HH:mm";

$formatDatePHP = "d/m/Y H:i";

$startTx = 'Inicio';

$endTx = 'Fin';

} else {

$language = 'en-us'; // English

$range_row = 40;

$formatDate = "MM/dd/yyyy HH:mm";

$formatDatePHP = "m/d/Y H:i";

$startTx = 'Start';

$endTx = 'End';

}

$strSQL = "SELECT `idavailability`, `media_idmedia`, `startDate`, `endDate` FROM availability where `idavailability` = $V_idavailability

";

$rsSQL = db_query($strSQL,$conn);

$data1 = db_fetch_array($rsSQL);

$V_idmedia = $data1['media_idmedia'];

$strSQL = "SELECT `idmedia`, `type_media_idtype_media`, `code` FROM media where idmedia = $V_idmedia

";

$rsSQL = db_query($strSQL,$conn);

$data2 = db_fetch_array($rsSQL);

$V_idtype_media = $data2['type_media_idtype_media'];

$strSQL = "SELECT `idtype_media`, `code`, `color`, `maxTimeReservation`, `startTimeDay`, `endTimeDay` FROM type_media where idtype_media = $V_idtype_media

";

$rsSQL = db_query($strSQL,$conn);

$data3 = db_fetch_array($rsSQL);

$V_idtype_media = $data2['type_media_idtype_media'];

$V_titleResource = $data3['code'].' -max:'.substr($data3['maxTimeReservation'],0,5).'
('.substr($data3['startTimeDay'],0,5).' - '.substr($data3['endTimeDay'],0,5).')';

$V_color = $data3['color'];

$V_event = '';

$strSQL = "SELECT `idavailable_block`, `availability_idavailability`, `media_idmedia`, `startDate`, `endDate` FROM available_block where availability_idavailability = $V_idavailability

";

$rsSQL = db_query($strSQL,$conn);

while ($data4 = db_fetch_array($rsSQL)) {

$V_start = date($formatDatePHP,strtotime($data4['startDate']));

$V_end = date($formatDatePHP,strtotime($data4['endDate']));

$V_event .= "

{

\"start\": \"".$data4['startDate']."\",

\"end\": \"".$data4['endDate']."\",

\"id\": \"".$data4['idavailable_block']."\",

\"resource\": \"available\",

\"text\": \"(".$V_start.' - '.$V_end.")\",

\"barColor\": \"$V_color\"

},";

}

if (strlen($V_event) <> 0) {

$V_event = substr($V_event, 0, -1); // rest last comma

}

// ---------------------------------------------- Template of javascript ---------------------------------

$html = <<<EOT

<!-- daypilot libraries -->

<script src="daypilot/js/daypilot-all.min.js?v=2019.4.4160" type="text/javascript"></script>

<div id="dp"></div>

<script>

var dp = new DayPilot.Scheduler("dp", {

cellWidthSpec: "Fixed",

cellWidth: $range_row,

autoScroll: "Disabled",

locale: "$language",

timeHeaders: [{"groupBy":"Day"},{"groupBy":"Hour"}],

scale: "Hour",

startDate: "$V_now",

days: $V_tot_day,

// days: DayPilot.Date.today().daysInMonth(),

// startDate: DayPilot.Date.today().firstDayOfMonth(),

showNonBusiness: false,

businessBeginsHour: 8,

businessEndsHour: 21,

eventHeight: 30,

eventMovingStartEndEnabled: true,

timeRangeSelectedHandling: "Disabled",

eventMoveHandling: "Disabled",

eventResizeHandling: "Disabled",

eventDeleteHandling: "Disabled",

eventClickHandling: "Disabled",

eventHoverHandling: "Bubble",

treeEnabled: false,

});

// bubble, with async loading

dp.bubble = new DayPilot.Bubble({

cssClassPrefix: "bubble_default",



onLoad: function(args) {

var ev = args.source;

args.async = true; // notify manually using .loaded()

// simulating slow server-side load

setTimeout(function() {

args.html = "<div style='font-weight:bold'>" + ev.text() + "</div><div>$startTx: " + ev.start().toString("$formatDate ") + "</div><div>$endTx: " + ev.end().toString("$formatDate ") + "</div><div>Id: " + ev.id() + "</div>";

args.loaded();

}, 50);

}

});



dp.resources = [ { "name" : "$V_titleResource", "id" : "available" }];

dp.events.list = [$V_event];

dp.init();

</script>

EOT;

echo $html;

?>


media_availability.php (graph representing the LIST of media availability)



<?php

// Mostrar, en gráfico de Daypilot, los recursos disponibles y los tiempos en que están disponibles en el rango de estudio.

// Show, in Daypilot chart, the resources available and the times they are available in the study range.

$V_limitDateMin = $_SESSION['limitDateMin'];

$V_limitDateMax = $_SESSION['limitDateMax'];

$V_availability_where = $_SESSION['availability_where'];

$V_label_head_reservations = GetCustomLabel ("ADD_RESERVATIONS");

$date_range_evaluations_min = $_SESSION['config'][array_search('DATE_RANGE_EVALUATIONS_MIN', array_column($_SESSION['config'], 'name'))][value];

$date_range_evaluations_max = $_SESSION['config'][array_search('DATE_RANGE_EVALUATIONS_MAX', array_column($_SESSION['config'], 'name'))][value];

$date = new DateTime(now());

$V_now = strtotime($date->format('d-m-Y H:i:s')."$date_range_evaluations_min days");

$V_now = date("Y-m-d",$V_now)."T00:00:01";

$V_tot_day = $date_range_evaluations_max - $date_range_evaluations_min;

if ($_SESSION['language'] == 'Spanish') {

$language = 'es-es'; // Spanish

$range_row = 20;

$formatDate = "dd/MM/yyyy HH:mm";

$formatDatePHP = "d/m/Y H:i";

$startTx = 'Inicio';

$endTx = 'Fin';

} else {

$language = 'en-us'; // English

$range_row = 40;

$formatDate = "MM/dd/yyyy HH:mm";

$formatDatePHP = "m/d/Y H:i";

$startTx = 'Start';

$endTx = 'End';

}

$V_resources = '';

$V_event = '';

$strSQL = "

SELECT distinct

media.idmedia,

-- media.type_media_idtype_media,

media.code,

media.title,

media.description,

media.owner_id,

-- type_media.code,

-- type_media.title,

type_media.color,

users.login,

users.username

FROM media

INNER JOIN availability ON media.idmedia = availability.media_idmedia

INNER JOIN type_media ON media.type_media_idtype_media = type_media.idtype_media

INNER JOIN users ON media.owner_id = users.user_id

where

availability.startDate <= '$V_limitDateMax'

and availability.endDate >= '$V_limitDateMin'

";

if ($V_availability_where <> ''){ // Filter?

$strSQL .= "and ".$V_availability_where ;

}

$strSQL .= " order by media.code ";

$rsSQL = db_query($strSQL,$conn);

while ($data1 = db_fetch_array($rsSQL)) {

$V_resources .= "{ \"name\" : \""."<b>".$data1['code']."</b>"." - ".$data1['title']."\", \"id\" : \"".$data1['code']."\"}, \n";

$V_idmedia = $data1['idmedia'];

$strSQL2 = "

SELECT

availability.idavailability,

available_block.idavailable_block idavailable_block,

available_block.startDate startDate,

available_block.endDate endDate

FROM availability

INNER JOIN available_block ON (availability.idavailability = available_block.availability_idavailability and availability.media_idmedia = $V_idmedia)

WHERE

availability.startDate <= '$V_limitDateMax'

and availability.endDate >= '$V_limitDateMin' ";

$rsSQL2 = db_query($strSQL2,$conn);

while ($data2 = db_fetch_array($rsSQL2)) {

$V_start = date($formatDatePHP,strtotime($data2['startDate']));

$V_end = date($formatDatePHP,strtotime($data2['endDate']));

$V_color = $data1['color'];

$V_event .= "

{

\"start\": \"".$data2['startDate']."\",

\"end\": \"".$data2['endDate']."\",

\"id\": \"".$data2['idavailable_block']."\",

\"resource\": \"".$data1['code']."\",

\"text\": \"(".$V_start.' - '.$V_end.")\",

\"barColor\": \"$V_color\"

},";

}

}

if (strlen($V_resources) <> 0) {

$V_resources = substr($V_resources, 0, -1); // rest last comma

}

if (strlen($V_event) <> 0) {

$V_event = substr($V_event, 0, -1); // rest last comma

}

// ---------------------------------------------- Template of javascript ---------------------------------

$html = <<<EOT

<!-- daypilot libraries -->

<script src="daypilot/js/daypilot-all.min.js?v=2019.4.4160" type="text/javascript"></script>

<div id="dp"></div>

<script>

var dp = new DayPilot.Scheduler("dp", {

cellWidthSpec: "Fixed",

cellWidth: $range_row,

autoScroll: "Disabled",

locale: "$language",

timeHeaders: [{"groupBy":"Day"},{"groupBy":"Hour"}],

scale: "Hour",

startDate: "$V_now",

days: $V_tot_day,

// days: DayPilot.Date.today().daysInMonth(),

// startDate: DayPilot.Date.today().firstDayOfMonth(),

showNonBusiness: false,

businessBeginsHour: 8,

businessEndsHour: 21,

eventHeight: 30,

eventMovingStartEndEnabled: true,

timeRangeSelectedHandling: "Disabled",

eventMoveHandling: "Disabled",

eventResizeHandling: "Disabled",

eventDeleteHandling: "Disabled",

eventClickHandling: "Enabled",

eventHoverHandling: "Bubble",

treeEnabled: false,

});

// bubble, with async loading

dp.bubble = new DayPilot.Bubble({

onLoad: function(args) {

var ev = args.source;

args.async = true; // notify manually using .loaded()

// simulating slow server-side load

setTimeout(function() {

args.html = "<div style='font-weight:bold'>" + ev.resource() + "</div><div>$startTx: " + ev.start().toString("$formatDate ") + "</div><div>$endTx: " + ev.end().toString("$formatDate ") + "</div><div>Id: " + ev.id() + "</div>";

args.loaded();

}, 50);

}

});

dp.onEventClicked = function(args) {

console.log('Select: '+args.e.text());

var block = args.e.id();

var url = "v_reservations_add.php?idBlock="+block;

var header = '<h2 data-itemtype="view_header" data-itemid="view_header" data-pageid="10">'+'$V_label_head_reservations '+'</h2>' ;

window.popup = Runner.displayPopup({

url: url,

width: 800,

height: 550,

header: header

});

};



dp.resources = [$V_resources];

dp.events.list = [$V_event];

dp.init();

</script>

EOT;

echo $html;

?>


reservations_view_cancellation.php (graphic that represents the LIST of existing reservations, the query and, if applicable, its cancellation)



<?php

// Mostrar, en gráfico de Daypilot, los recursos reservador y los tiempos en que están reservados en el rango de estudio.

// Show, in Daypilot chart, the reserve resources and the times they are reserved in the study range.

$V_limitDateMin = $_SESSION['limitDateMin'];

$V_limitDateMax = $_SESSION['limitDateMax'];

$V_reservations_where = $_SESSION['reservations_where'];

$V_label_head_reservations = GetCustomLabel ("VIEW_RESERVATIONS");

$date_range_evaluations_min = $_SESSION['config'][array_search('DATE_RANGE_EVALUATIONS_MIN', array_column($_SESSION['config'], 'name'))][value];

$date_range_evaluations_max = $_SESSION['config'][array_search('DATE_RANGE_EVALUATIONS_MAX', array_column($_SESSION['config'], 'name'))][value];

$date = new DateTime(now());

$V_now = strtotime($date->format('d-m-Y H:i:s')."$date_range_evaluations_min days");

$V_now = date("Y-m-d",$V_now)."T00:00:01";

$V_tot_day = $date_range_evaluations_max - $date_range_evaluations_min;

if ($_SESSION['language'] == 'Spanish') {

$language = 'es-es'; // Spanish

$range_row = 20;

$formatDate = "dd/MM/yyyy HH:mm";

$formatDatePHP = "d/m/Y H:i";

$startTx = 'Inicio';

$endTx = 'Fin';

$userTx = 'Usuario';

} else {

$language = 'en-us'; // English

$range_row = 40;

$formatDate = "MM/dd/yyyy HH:mm";

$formatDatePHP = "m/d/Y H:i";

$startTx = 'Start';

$endTx = 'End';

$userTx = 'User';

}

$V_resources = '';

$V_event = '';

$strSQL = "

SELECT distinct

media.idmedia,

-- media.type_media_idtype_media,

media.code,

media.title,

media.description,

media.owner_id,

-- type_media.code,

-- type_media.title,

type_media.color

FROM media

INNER JOIN reservations ON media.idmedia = reservations.media_idmedia

INNER JOIN type_media ON media.type_media_idtype_media = type_media.idtype_media

where

reservations.startDate <= '$V_limitDateMax'

and reservations.endDate >= '$V_limitDateMin'

";

if ($V_reservations_where <> ''){ // Filter?

$strSQL .= "and ".$V_reservations_where ;

}

$strSQL .= " order by media.code ";

$rsSQL = db_query($strSQL,$conn);

while ($data1 = db_fetch_array($rsSQL)) {

$V_resources .= "{ \"name\" : \""."<b>".$data1['code']."</b>"." - ".$data1['title']."\", \"id\" : \"".$data1['code']."\"}, \n";

$V_idmedia = $data1['idmedia'];

$strSQL2 = "

SELECT

reservations.idreservations,

-- reservations.media_idmedia,

-- reservations.users_user_id,

reservations.startDate startDate,

reservations.endDate endDate,

users.user_id,

users.login,

users.username

FROM reservations

INNER JOIN users ON (reservations.users_user_id = users.user_id)

WHERE

reservations.media_idmedia = $V_idmedia

and reservations.startDate <= '$V_limitDateMax'

and reservations.endDate >= '$V_limitDateMin' ";

$rsSQL2 = db_query($strSQL2,$conn);

while ($data2 = db_fetch_array($rsSQL2)) {

$V_start = date($formatDatePHP,strtotime($data2['startDate']));

$V_end = date($formatDatePHP,strtotime($data2['endDate']));

$V_color = $data1['color'];

$V_event .= "

{

\"start\": \"".$data2['startDate']."\",

\"end\": \"".$data2['endDate']."\",

\"id\": \"".$data2['idreservations']."\",

\"resource\": \"".$data1['code']."\",

\"text\": \"".$data2['login']."\",

\"user\": \"".$data2['login'].' - '.$data2['username']."\",

\"barColor\": \"$V_color\"

},";

}

}

if (strlen($V_resources) <> 0) {

$V_resources = substr($V_resources, 0, -1); // rest last comma

}

if (strlen($V_event) <> 0) {

$V_event = substr($V_event, 0, -1); // rest last comma

}

// ---------------------------------------------- Template of javascript ---------------------------------

$html = <<<EOT

<!-- daypilot libraries -->

<script src="daypilot/js/daypilot-all.min.js?v=2019.4.4160" type="text/javascript"></script>

<div id="dp"></div>

<script>

var dp = new DayPilot.Scheduler("dp", {

cellWidthSpec: "Fixed",

cellWidth: $range_row,

autoScroll: "Disabled",

locale: "$language",

timeHeaders: [{"groupBy":"Day"},{"groupBy":"Hour"}],

scale: "Hour",

startDate: "$V_now",

days: $V_tot_day,

// days: DayPilot.Date.today().daysInMonth(),

// startDate: DayPilot.Date.today().firstDayOfMonth(),

showNonBusiness: false,

businessBeginsHour: 8,

businessEndsHour: 21,

eventHeight: 30,

eventMovingStartEndEnabled: true,

timeRangeSelectedHandling: "Disabled",

eventMoveHandling: "Disabled",

eventResizeHandling: "Disabled",

eventDeleteHandling: "Disabled",

eventClickHandling: "Enabled",

eventHoverHandling: "Bubble",

treeEnabled: false,

});

// bubble, with async loading

dp.bubble = new DayPilot.Bubble({

onLoad: function(args) {

var ev = args.source;

args.async = true; // notify manually using .loaded()

// simulating slow server-side load

setTimeout(function() {

args.html = "<div style='font-weight:bold'>" + ev.resource() + "</div><div>$userTx: " + ev.text() + "</div><div>$startTx: " + ev.start().toString("$formatDate ") + "</div><div>$endTx: " + ev.end().toString("$formatDate ") + "</div><div>Id: " + ev.id() + "</div>";

args.loaded();

}, 50);

}

});

dp.onEventClicked = function(args) {

console.log('Select: '+args.e.text());

var reservation = args.e.id();

var url = "v_reservations_view.php?editid1="+reservation;

var header = '<h2 data-itemtype="view_header" data-itemid="view_header" data-pageid="10">'+'$V_label_head_reservations '+'</h2>' ;

window.popup = Runner.displayPopup({

url: url,

width: 800,

height: 550,

header: header

});

};



dp.resources = [$V_resources];

dp.events.list = [$V_event];

dp.init();

</script>

EOT;

echo $html;

?>


For any questions or what you need, contact me via email [email="fernandohumanes@gmail.com"]fernandohumanes@gmail.com[/email]
In my portal the sources and copy of the Database, so that you can install it on your computers.

fhumanes author 3/22/2020

Hi:
I have updated the PHPRunner 10.2 project with simple changes that affect the interface, to try to make it easier for users.
Greetings,
fernando

jadachDevClub member 3/24/2020

Outstanding work.

D
DealerModulesDevClub member 3/24/2020

Hi Fernando,

Just wanted to thank you for the detail that you put in all of your posts.
Thanks again for sharing!

Paul

fhumanes author 3/26/2020

Hi
Thank you very much for your nice comments.
If in any case it is useful for your work, I feel very satisfied with it.
A hug,
fernando