所以我正在建造一个假日综合体的预订系统(类似于酒店,但不是房间有各种各样的公寓)。为避免双重预订,系统需要检查特定公寓是否在潜在客人选择的日期范围内预订,如果没有任何问题则继续进行,或者如果选择的日期是其中一部分,则通知他们更改日期或公寓一组日期。我试图弄清楚如何检查所选日期是否属于先前选择的日期范围 例如:如果已预订日期范围08/09/2015 - 08/12/2015,然后选择日期范围08/10/2015 - 08/15/2015,则客人会收到选择新的通知日期或其他公寓,否则如果选择的日期范围是08/15/2015 - 08/20/2015,则表格将被处理。
到目前为止我的预订系统:
<?php
if ($_POST) {
if (isset($_POST['proceedtopaypal'])){
$apartment = $_POST['apartment'];
$name = $_POST['name'];
$surname = $_POST['surname'];
$email = $_POST['email'];
$address = $_POST['address'];
$mobile = $_POST['mobile'];
$pax = $_POST['pax'];
$address = $_POST['address'];
$remarks = $_POST['remarks'];
$day_from = $_POST['day_from'];
$month_from = $_POST['month_from'];
$year_from = $_POST['year_from'];
$booking_from = $year_from."-".$month_from."-".$day_from;
$day_to = $_POST['day_to'];
$month_to = $_POST['month_to'];
$year_to = $_POST['year_to'];
$booking_to = $year_to."-".$month_to."-".$day_to;
$no_of_nights = abs(strtotime($booking_to) - strtotime($booking_from));
$days = floor($no_of_nights / (60*60*24));
printf("%d nights\n", $days);
$validdate = false;
$buttonpressed = false;
$nodate='<p>date does not exist.</p>\n';
$noinfo='<p>please fill in the missing information.</p>\n';
$baddate='<p>selected dates is already booked.</p>\n';
$thankyou='<p>thank you for your reservation.<br>a confirmation email will be sent shortly</p>\n';
$window = '';
function IsInjected($str)
{
$injections = array('(\n+)',
'(\r+)',
'(\t+)',
'(%0A+)',
'(%0D+)',
'(%08+)',
'(%09+)'
);
$inject = join('|', $injections);
$inject = "/$inject/i";
if(preg_match($inject,$str))
{
return true;
}
else
{
return false;
}
}
if ($booking_from == (($day_from == "31") && ($month_from == "2")) || (($day_from == "31") && ($month_from == "4")) || (($day_from == "31") && ($month_from == "6")) || (($day_from == "31") && ($month_from == "9")) || (($day_from == "31") && ($month_from == "11")) || (($day_from == "30") && ($month_from == "2")) || (($day_from == "29") && ($month_from == "2") && ($year_from %4 != 0)) ) {
//$window=$nodate;
echo "Date does not exist";
$validdate = true;
}
else if ($booking_to == (($day_to == "31") && ($month_to == "2")) || (($day_to == "31") && ($month_to == "4")) || (($day_to == "31") && ($month_to == "6")) || (($day_to == "31") && ($month_to == "9")) || (($day_to == "31") && ($month_to == "11")) || (($day_to == "30") && ($month_to == "2")) || (($day_to == "29") && ($month_to == "2") && ($year_to %4 != 0)) ) {
//$window=$nodate;
echo "Date does not exist";
$validdate = true;
}
else if (($name == "Name") || ($surname == "surname") || ($email == "Email") || ($address == "Address")) {
//$window=$noinfo;
echo "Missing information";
}
else if (IsInjected($email)) {
echo '<script language="javascript">';
echo 'alert("Email")';
echo '</script>';
}
else if ($validdate == false) {
$final = true;
include 'connect.php';
$sql = "SELECT * FROM booking WHERE ($booking_from BETWEEN date_from AND date_to) OR ($booking_to BETWEEN date_from AND date_to)";
$result = $conn->query($sql);
while ($row = $result->fetch_assoc()) {
if ($apartment == $row['apartmentID'] && $booking_from >= $row['date_from'] && $booking_to <= $row['date_to']){
//$window=$badtime;
echo "Apartment is taken";
$final = false;
}
else {
echo "All OK";
}
}
}
}
}
SQL表具有以下设置:
> BookingID - int
> ApartmentID - int
> ClientID - int
> date_from - date (Format: yyyy-mm-dd)
> date_to - date (Format: yyyy-mm-dd)
> no of nights - int (achieved by subtracting date_from from date_to)
> pax - int (number of people)
> paid - int
可见代码:
<form action="" method="post" id="bookstay">
<input type="hidden" name="apartment" value="<?php get_apartment_text("SELECT apartmentID from apartment_details WHERE apartmentID = ?", "apartmentID"); ?>"/>
<input name='name' class="short-input" type="text" value="Name" onFocus="this.value = ''" />
<input name= 'surname' class="short-input" type="text" value="surname" onFocus="this.value = ''" />
<input name='email' class="long-input" type="text" value="Email" onFocus="this.value = ''" />
<input name='address' class="long-input" type="text" value="Address" onFocus="this.value = ''" />
<input name='mobile' class="short-input" type="text" value="mobile" onFocus="this.value = ''" />
<div class="select" id="peopletostay">
<select name="pax" class="short-input">
<option value="0">people to stay</option>
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
<option value="4">4</option>
<option value="5">5</option>
<option value="6">6</option>
</select>
</div>
<div id="dateofarrival">
date of arrival<br>
<?php include 'date-from.php'; ?>
</div>
<div id="dateofdeparture">
date of departure<br>
<?php include 'date-to.php'; ?>
</div>
<textarea name='remarks'>Extra Remarks</textarea>
</div>
<button type='submit' name='proceedtopaypal'>
</form>
答案 0 :(得分:2)
我不会在booking
表格中包含所有内容,而是制作以下单独的表格:
bookings
- 请注意,使用复数而不是单数是非常标准的,所以如果它没有太多工作,我会改变它。你可以从中删除apartmentId
和number_of_nights
。第一个将由room_nights
表(下面)处理,第二个表示存储在数据库中毫无意义,因为它可以很容易地计算出来。apartments
- 我认为这已经完成了。只需在此处添加有关每间公寓的信息,例如房间数量,描述等。clients
- 我也认为这已经完成了。在此处添加有关客户端的任何信息。room_nights
- 这可以追踪任何一个晚上的完整公寓。您将在每晚公寓满员时添加一个条目。这应仅包含date
,booking_id
和apartment_id
。blocked_rooms
(可选) - 这与room_nights
的工作方式相同,但是它允许您跟踪您想要阻止预订的任何日期而无需实际预订(例如,维护)。然后在任何给定的夜晚查询公寓是否已满,您可以执行以下操作:
SELECT COUNT(*) FROM room_nights
WHERE date >= :check_in
AND date < :check_out
AND apartment_id = ?
如果您还想使用blocked_rooms
,您可以像上面一样使用UNION
在一个查询中完成所有操作。
然后,您可以轻松地将其输出到日历表,其中y轴为公寓,x轴为日期,以显示已预订/空/被阻止的公寓。这就是我在我的程序中所做的:
现在,如果你想让公寓有动态费率,这就是我用过的桌面结构:
rates
表:您可以在此处输入费率名称以及一些限制。
CREATE TABLE `rates` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`rate_name` varchar(50) NOT NULL,
`days_advance_min` int(11) NOT NULL,
`days_advance_max` int(11) NOT NULL,
`booking_date_start` datetime NOT NULL,
`booking_date_end` datetime NOT NULL,
`booking_date_end_unlimited` bit(1) NOT NULL,
`min_people` int(11) NOT NULL,
`max_people` int(11) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `rate_name` (`rate_name`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8
days_advance_*
列是可用费率的最高/最高天数。 booking_date_*
列用于确定何时可以预订此费率。因此,如果您只希望它在特定日期开始使用,那么就把它放在那里。如果没有最终预订日期,booking_date_end_unlimited
只是为了跟踪。您可能不希望将BIT(1)
用于该列,因为它更难以使用。
rates_apartments
将费率与公寓ID相关联的关系表
rate_dates
这是实际的&#34;率&#34;进去。你每天都有一个房价。在任何地方都不需要开始/结束日期,因为您可以在此处添加任何日期:
CREATE TABLE `rate_dates` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`rate_id` int(11) NOT NULL,
`date` date NOT NULL,
`single` decimal(13,4) NOT NULL,
`second_adult` decimal(13,4) NOT NULL,
`third_adult` decimal(13,4) NOT NULL,
`fourth_adult` decimal(13,4) NOT NULL,
`extra_adult` decimal(13,4) NOT NULL,
`extra_child` decimal(13,4) NOT NULL,
`min_nights` int(11) NOT NULL,
`max_nights` int(11) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `rate_id` (`rate_id`,`date`),
UNIQUE KEY `rate_id_3` (`rate_id`,`date`),
KEY `rate_id_2` (`rate_id`),
KEY `date` (`date`),
CONSTRAINT `rate_dates_ibfk_1` FOREIGN KEY (`rate_id`) REFERENCES `rates` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3219 DEFAULT CHARSET=utf8
我认为这里的一切都应该是不言自明的。通过添加single + second_adult + third_adult
等来计算费率,具体取决于人数。如果您不想根据人数改变费率,只需设置一个&#34; rate&#34;价值,你也可以摆脱rates
表中的最小/最大人数。
最后,这是我用来实际获得费率的查询:
// Get available rates for each night
$placeholders = substr(str_repeat('?,', count($dates_stayed)), 0, -1);
$query = "
SELECT
r.id as rate_id,
rrt.room_type_id,
date,
single,
second_adult,
third_adult,
fourth_adult,
extra_adult,
extra_child,
r.min_people as rates_min_people,
r.max_people as rates_max_people,
crt.min_people as crt_min_people,
crt.max_people as crt_max_people
FROM rate_dates rd
LEFT JOIN rates r
ON rd.rate_id = r.id
LEFT JOIN rates_room_types rrt
ON r.id = rrt.rate_id
LEFT JOIN config_room_types crt
ON rrt.room_type_id = crt.id
WHERE
rd.date IN ( $placeholders )
AND booking_date_start <= NOW()
AND (
booking_date_end >= NOW()
OR booking_date_end_unlimited = b'1'
)
AND DATEDIFF(?, NOW()) >= days_advance_min
AND (
days_advance_max = -1
OR DATEDIFF(?, NOW()) <= days_advance_max
)
AND min_nights <= ?
AND min_nights <= ?
AND (
max_nights >= ?
OR max_nights = -1
)
HAVING
? >= rates_min_people
AND ? <= rates_max_people
AND ? >= crt_min_people
AND ? <= crt_max_people";
$stmt = $this->dbh->prepare($query);
config_room_types
表与您的apartments
表类似,因为您可以在费率级别和房间级别限制最小/最大人数。