fhumanes author
 In the current global pandemic situation, almost all companies and public services have had to resort to appointment management to maintain social distance between people. This example is a possible Pre-Appointment management system or at least that is how I wanted to identify it. The simplest example is thinking about the needs of medical services, although I have tried to make it valid for any other need. Functional requirements When I have been thinking about what a company requires for this management, I have defined:
- I have created a "Business Object", which I have called "Reserve", which is the unit to which we are going to associate the appointment management gaps. This "Object" can be a Doctor, a Medical Service, a Registration Unit, a Bank Agent, etc., any Object that requires a list of people to attend to.
- These "Reserves" will be associated with 2 levels of grouping. In the system I have associated "Company" and "Department", but it could be any other structure.
- The "Reserve" record must have the data required to establish the gaps in the schedule of the Prior Appointment.
- The analysis of available gaps must be very easy to identify and manage, with the possibility that it can be facilitated in a self-management system (that the user requests the date and time of the appointment). The possibility of requesting an appointment date for any day and time of those available should be offered.
- Also, the system must offer lists or counts of gaps or appointments that have been closed as of the required date.
Solution DEMO: http://fhumanes.com/citations User and password: admin / admin The example works for the English and Spanish languages. Once we have identified, the menu will appear with all the options.
 The main options are those in the "Citations" group and from any of them you can go to the appointment reservation management and the list of agreed appointments.
 The "Reserves" require a short name or password, a color for your identification, your name and some information that is required for planning agendas:
- Initial or high date of the resource. Before this date, nothing can be scheduled.
- Final date. After this date nothing can be scheduled.
- Start time of the agenda. This and the following 2 data set agenda hours.
- End time of the agenda.
- Time that the gaps in the agenda will last.
 The "Planning" records define the date ranges that are established to create the agenda. For each "Reserves", a start date and end date must be established. There are controls so that there are no overlapping dates and so that you do not exceed the date of the "Reserves". While it is not active, it can be modified and even deleted, but once it is active (and the agenda has been created) it no longer allows the Planning to be modified or deleted.
 The agenda or appointment slot has basic data and 3 fields will remain to be completed:
- Name.-Details of the person who has signed the appointment.
- Description.- Any other information that is provided to the appointment.
- Busy? .- When the space in the agenda has been occupied (automatically) it is set to 1.
 In the tables of "Companies", "Departments" and "Reserves", all of them have a "Calendar" button, which takes us to the presentation of the agenda with the available spaces. The available appointments will be from the "Reserves" according to where we have pressed the button. We may be interested in the available appointments of a doctor, a service, a department or a hospital.
 We will be able to scroll through a calendar where we will provide information on the appointments that are free. It shows the first 3 available and the total number of those it cannot show. By clicking on the link of the others, a list of all available appointments for that day appears. You only need to click on one of them to start the request for that appointment.
 In the "popup" window that appears when an appointment is selected, the basic data of the agenda and the date and time of the appointment appear, allowing us to enter the name of the person in the appointment and a description field that can be completed with the purpose of the appointment.
 As we have been able to see the agendas available by "Company", "Department" and "Reserve", you can get the list of scheduled appointments, if required, obtain a list of them. Technical Solution I have used 2 plugins that you can download from my portal (Color and Toogle). For the presentation of the calendar I have used the JavaScript library FullCalendar https://fullcalendar.io/. A very good library for everything that has to do with calendars and plans. I briefly explain some codes, so you can see the simplicity of the example. control_plannig.php - Date controls to validate planning
<?php
// Planning range control
$idreserves = $values['reserves_idreserves']; // Master Reserves
// Recover data of Reserves
$sql = "SELECT idreserves, start_date, end_date, active FROM reserves where idreserves = $idreserves";
$resql = db_query($sql,$conn);
if ($resql->num_rows <> 0) { // Found
$master = db_fetch_array($resql);
$master_start_date = $master['start_date'];
$master_end_date = $master['end_date'];
$master_active = $master['active'];
} else {
$message = GetCustomLabel("MASTER_NOT_FOUND");
$return = false;
return;
}
if ( $master_active == 0 ){
$message = GetCustomLabel("MASTER_NOT_ACTIVE");
$return = false;
return;
}
if ( !($values['start_date'] >= $master_start_date and $values['end_date'] <= $master_end_date)) {
$message = GetCustomLabel("MASTER_NOT_RANGE_DATE");
$return = false;
return;
}
if ( !isset($keys['idplanning']) ){ // Is Edit, Key of record
$idplanning = 0;
} else {
$idplanning = $keys['idplanning'];
}
if ( !($values['start_date'] <= $values['end_date']) ) {
$message = GetCustomLabel("RANGE_DATES_DUPLICATED");
$return = false;
return;
}
$start_date = $values['start_date'];
$end_date = $values['end_date'];
// Check if date range is not duplicated
$sql = "
select idplanning from planning
where reserves_idreserves= $idreserves
and idplanning <> $idplanning
and ( start_date <= '$end_date' and end_date >= '$start_date' )
";
$resql = db_query($sql,$conn);
if ($resql->num_rows <> 0) { // Found
$message = GetCustomLabel("RANGE_DATES_DUPLICATED");
$return = false;
return;
}
create_planning.php - Create agendas from planning and reservation data.
<?php
// Create insert into Citation form planning
$idreserves = $values['reserves_idreserves']; // Master Reserves
$idplanning = $values['idplanning']; // Planing
$iduser = $_SESSION['user_id']; //id of Users
$now = now();
// Recover data of Reserves
$sql = "SELECT idreserves, weekends, from_time, to_time, time_by_citation FROM reserves where idreserves = $idreserves";
$resql = db_query($sql,$conn);
if ($resql->num_rows <> 0) { // Found
$master = db_fetch_array($resql);
$master_weekends = $master['weekends'];
$master_from_time = $master['from_time'];
$master_to_time = $master['to_time'];
$master_time_citation = $master['time_by_citation'];
} else {
$message = GetCustomLabel("MASTER_NOT_FOUND");
die($message);
}
$start_date = date('Y-m-d', strtotime($values['start_date'])).' '.$master_from_time;
$end_date = date('Y-m-d', strtotime($values['end_date'])).' '.$master_to_time;
$temp = explode(":", $master_time_citation);
$increment_hour = $temp[0]+0; // Hour
$increment_minute = $temp[1]+0; // Minutes
$increment = '';
if ($increment_hour <> 0 ) { $increment .= ' +'.$increment_hour.' hour'; }
if ($increment_minute <> 0 ) { $increment .= ' +'.$increment_minute.' minutes'; }
$i = $start_date;
while ($i <= $end_date ) { // Loop increment Citations
$day_week = date('N', strtotime($i)); // 1 =domingo y 7 = sábado
If ( $master_weekends == 0 && ( $day_week == 6 || $day_week == 7 )) { // It is the weekend and there is no work on the weekend
$i = date('Y-m-d H:i', strtotime($i. ' +1 day'));
continue;
}
$j = date('Y-m-d H:i', strtotime($i. $increment));
$time_i = substr($i, -5, 5);
$time_j = substr($j, -5, 5);
if ($time_j > $master_to_time ) { // new day
$i = date('Y-m-d', strtotime($i. ' +1 day')).' '.$master_from_time;
continue;
}
// INSERT in DB the citations
$sql="
INSERT into citations
(reserves_idreserves, planning_idplanning, short_name, start_date, end_date, created, updated, creator, modifier)
values ($idreserves,$idplanning,'$time_i','$i','$j', '$now' , '$now' ,$iduser, $iduser)
";
$res=db_exec($sql,$conn);
$i = $j;
}
calendar.php - To display the calendar grid
<?php
global $conn;
/* Session variable
$_SESSION['reserve_id']
$_SESSION['option_calendar'] valor: reserve | company | departament
$_SESSION['language']
$_SESSION['user_id']
$_SESSION['login']
$_SESSION['email']
$_SESSION['username']
$_SESSION['company_id']
$_SESSION['dept_id']
*/
if ($_SESSION['language'] == 'Spanish') {
$language = 'es'; // Spanish
$firstDay = '1'; // Lunes
} else {
$language = 'en'; // English
$firstDay = '0'; // Sun
}
$now = substr(now(),0,10);
$str1 = <<<EOD
<style>
html, body {
margin: 0;
padding: 0;
font-family: Arial, Helvetica Neue, Helvetica, sans-serif;
font-size: 12px;
}
#calendar {
max-width: 900px;
margin: 40px auto;
}
</style>
<meta charset='utf-8' />
<link href='fullcalendar/packages/core/main.css' rel='stylesheet' />
<link href='fullcalendar/packages/daygrid/main.css' rel='stylesheet' />
<link href='fullcalendar/packages/timegrid/main.css' rel='stylesheet' />
<link href='fullcalendar/packages/list/main.css' rel='stylesheet' />
<script src='fullcalendar/packages/core/main.js'></script>
<script src='fullcalendar/packages/interaction/main.js'></script>
<script src='fullcalendar/packages/daygrid/main.js'></script>
<script src='fullcalendar/packages/timegrid/main.js'></script>
<script src='fullcalendar/packages/list/main.js'></script>
<script src='fullcalendar/packages/core/locales-all.min.js'></script>
<script>
var initialLocaleCode = '$language';
var firstDay = '$firstDay';
document.addEventListener('DOMContentLoaded', function() {
var calendarEl = document.getElementById('calendar');
var calendar = new FullCalendar.Calendar(calendarEl, {
plugins: ['interaction', 'dayGrid', 'timeGrid', 'list' ],
header: {
left: 'prev,next today',
center: 'title',
right: 'dayGridMonth,listWeek'
// right: 'dayGridMonth,timeGridWeek,timeGridDay,listWeek'
},
// defaultView: 'dayGridMonth',
defaultDate: '$now',
// timeZone: 'Europe/Madrid', // the default 'local' (unnecessary to specify)
locale: initialLocaleCode,
businessHours: {
// days of week. an array of zero-based day of week integers (0=Sunday)
daysOfWeek: [ 1, 2, 3, 4, 5 ], // Monday - Thursday
startTime: '08:00', // a start time (08am in this example)
endTime: '20:00', // an end time (8pm in this example)
},
weekNumbers: true,
weekNumbersWithinDays: true,
// weekNumberCalculation: 'ISO',
editable: true,
navLinks: true, // can click day/week names to navigate views
eventLimit: true, // allow "more" link when too many events
eventClick: function(info) {
var citation = info.event.id;
var title = info.event.title;
var url = "timetable_edit.php?editid1="+citation;
var header = '<h2 data-itemtype="view_header" data-itemid="view_header" data-pageid="10">'+'Citation: '+ title+'</h2>' ;
/*
var win = Runner.displayPopup( {
url: url,
width: 800,
height: 500,
header: header
});
*/
window.popup = Runner.displayPopup({
url: url,
width: 800,
height: 500,
header: header
});
},
events: {
url: 'calendar_ajax_own.php'
}
});
calendar.render();
});
</script>
<div id='calendar'></div>
EOD;
echo $str1;
?>
calendar_ajax_own.php - To dynamically load available appointments.
<?php
require_once("include/dbcommon.php"); // DataBase PHPRunner
/* Session variable
$_SESSION['option_calendar'] valor: project | user | company | departament | meeting
$_SESSION['language']
$_SESSION['user_id']
$_SESSION['reserve_id']
$_SESSION['login']
$_SESSION['email']
$_SESSION['username']
$_SESSION['company_id']
$_SESSION['dept_id']
* ----------------------------------------------
*/
// Require our Event class and datetime utilities
require 'fullcalendar/php/utils.php';
// Short-circuit if the client did not give us a date range.
if (!isset($_GET['start']) || !isset($_GET['end'])) {
die("Please provide a date range.");
}
// Parse the start/end parameters.
// These are assumed to be ISO8601 strings with no time nor timeZone, like "2013-12-29".
// Since no timeZone will be present, they will parsed as UTC.
$range_start = parseDateTime($_GET['start']);
$range_end = parseDateTime($_GET['end']);
// Parse the timeZone parameter if it is present.
$time_zone ='';
if (isset($_GET['timeZone'])) {
$time_zone = new DateTimeZone($_GET['timeZone']);
}
$start = substr($_GET['start'],0,10).' 00:00:00';
$end = substr($_GET['end'] ,0,10).' 00:00:00';
$now = date('Y-m-d H:i:s', strtotime(now(). ' +2 hour')); // now() + 1
if ( $start < $now ) { // Minimum date of the moment
$start = $now;
}
switch ($_SESSION['option_calendar']) {
case 'reserve':
$sql = "SELECT idcitations id, citations.short_name name, reserves.short_name resource, citations.start_date, citations.end_date, reserves.color
FROM citations
join reserves on (reserves_idreserves = idreserves)
where citations.status = 0 and
reserves_idreserves =" . $_SESSION['reserve_id'] . " and citations.end_date >= '$start' and citations.start_date < '$end'";
break;
case 'company':
$sql = "SELECT idcitations id, citations.short_name name, reserves.short_name resource, citations.start_date, citations.end_date, reserves.color
FROM citations
join reserves on (reserves_idreserves = idreserves)
join companies on (reserves.companies_company_id = companies.company_id)
where citations.status = 0
and companies.company_id =" . $_SESSION['company_id'] . " and citations.end_date >= '$start' and citations.start_date < '$end'";
break;
case 'departament':
$sql = "SELECT idcitations id, citations.short_name name, reserves.short_name resource, citations.start_date, citations.end_date, reserves.color
FROM citations
join reserves on (reserves_idreserves = idreserves)
join departments on (reserves.departments_dept_id = departments.dept_id)
where citations.status = 0
and departments.dept_id =" . $_SESSION['departament_id'] . " and citations.end_date >= '$start' and citations.start_date < '$end'";
break;
}
$resql = db_query($sql,$conn);
// Accumulate an output array of event data arrays.
$output_arrays = array();
while ($data = db_fetch_array($resql)){
$output_arrays[] = array(
'id'=>$data['id'],
'title'=>$data['name'],
'resource'=>$data['resource'],
'start'=>$data['start_date'],
'end'=>$data['end_date'],
'color'=>$data['color']);
}
// Send JSON to the client.
// $str = json_encode($output_arrays);
echo json_encode($output_arrays);
?>
As always, you can contact me for any need at [email="fernandohumanes@gmail.com"]fernandohumanes@gmail.com[/email] Also, as usual, I leave you in my portal all the files you need so that you can install the example on your computers.
|
|