One large-type page for the front desk (Hotel Reservation System > Rezeption, first menu entry): - today's arrivals, departures, guests in house and overdue arrivals, each guest as a card with big room number, name, people, nights, room type and booking source - one obvious button per guest: Einchecken / Auschecken (and "Früher abreisen"); after each action a big confirmation with "Rückgängig" instead of confirm dialogs; Post/Redirect/Get so reload never repeats - uses HotelBookingDetail::changeStatus(), so status history and hooks (casposbridge posts the nights) run as in the order page; check-out does not require payment in QloApps because guests pay at the POS - shows the CASPOS state per guest; other days are read-only - tiles to Belegungsplan and Neue Reservierung (Book Now) - employee profile "Rezeption" that only sees Rezeption, Belegungsplan, Book Now, orders, customers, carts and guest registration cards - docker/test-frontdesk.php: 21 checks with throw-away guests Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
110 lines
4.4 KiB
PHP
110 lines
4.4 KiB
PHP
<?php
|
|
/**
|
|
* Rezeption: one simple, large page for the front desk (arrivals, departures, in house,
|
|
* check-in/out with undo) and an employee profile "Rezeption" that only sees what it needs.
|
|
*/
|
|
|
|
if (!defined('_PS_VERSION_')) {
|
|
exit;
|
|
}
|
|
|
|
class Frontdesk extends Module
|
|
{
|
|
/** back-office pages the "Rezeption" profile may open (class name => edit rights) */
|
|
const PROFILE_TABS = array(
|
|
'AdminFrontDesk' => true,
|
|
'AdminOccupancyPlan' => false,
|
|
'AdminHotelReservationSystemManagement' => false, // parent menu of the two above
|
|
'AdminHotelRoomsBooking' => true, // "Neue Reservierung"
|
|
'AdminParentOrders' => false,
|
|
'AdminOrders' => true, // order created from Book Now, details link
|
|
'AdminGuestRegistration' => true, // Meldeschein / guest registration card
|
|
'AdminCarts' => true, // Book Now builds the booking in a cart
|
|
'AdminParentCustomer' => false,
|
|
'AdminCustomers' => true, // create the guest during a booking
|
|
'AdminAddresses' => true,
|
|
);
|
|
|
|
public function __construct()
|
|
{
|
|
$this->name = 'frontdesk';
|
|
$this->tab = 'administration';
|
|
$this->version = '1.0.0';
|
|
$this->author = 'Zum alten Wasserrad';
|
|
$this->need_instance = 0;
|
|
$this->bootstrap = true;
|
|
parent::__construct();
|
|
|
|
$this->displayName = 'Rezeption';
|
|
$this->description = 'Einfache Tagesansicht für die Rezeption: Anreise, Abreise, Im Haus, Ein- und Auschecken mit großen Knöpfen.';
|
|
$this->ps_versions_compliancy = array('min' => '1.6', 'max' => '1.6.99.99');
|
|
}
|
|
|
|
public function install()
|
|
{
|
|
return parent::install() && $this->installTab() && $this->installProfile();
|
|
}
|
|
|
|
public function uninstall()
|
|
{
|
|
$idTab = (int)Tab::getIdFromClassName('AdminFrontDesk');
|
|
if ($idTab) {
|
|
(new Tab($idTab))->delete();
|
|
}
|
|
return parent::uninstall();
|
|
}
|
|
|
|
protected function installTab()
|
|
{
|
|
if (Tab::getIdFromClassName('AdminFrontDesk')) {
|
|
return true;
|
|
}
|
|
$tab = new Tab();
|
|
$tab->class_name = 'AdminFrontDesk';
|
|
$tab->module = $this->name;
|
|
$tab->id_parent = (int)Tab::getIdFromClassName('AdminHotelReservationSystemManagement');
|
|
foreach (Language::getLanguages(false) as $lang) {
|
|
$tab->name[$lang['id_lang']] = 'Rezeption';
|
|
}
|
|
$tab->add(); // returns initAccess(), false on CLI; the tab exists anyway
|
|
if (!$tab->id) {
|
|
return false;
|
|
}
|
|
// first entry of its menu group
|
|
Db::getInstance()->execute('UPDATE `'._DB_PREFIX_.'tab` SET `position` = `position` + 1 WHERE `id_parent` = '.(int)$tab->id_parent.' AND `id_tab` <> '.(int)$tab->id);
|
|
Db::getInstance()->update('tab', array('position' => 0), '`id_tab` = '.(int)$tab->id);
|
|
return true;
|
|
}
|
|
|
|
/** Profile "Rezeption" with view/edit only on the pages the front desk needs. */
|
|
public function installProfile()
|
|
{
|
|
$idProfile = (int)Db::getInstance()->getValue('SELECT `id_profile` FROM `'._DB_PREFIX_.'profile_lang` WHERE `name` = \'Rezeption\'');
|
|
if (!$idProfile) {
|
|
$profile = new Profile();
|
|
foreach (Language::getLanguages(false) as $lang) {
|
|
$profile->name[$lang['id_lang']] = 'Rezeption';
|
|
}
|
|
if (!$profile->add()) {
|
|
return false;
|
|
}
|
|
$idProfile = (int)$profile->id;
|
|
}
|
|
// start from "no access" for every page, then open the listed ones
|
|
Db::getInstance()->delete('access', '`id_profile` = '.$idProfile);
|
|
$rows = array();
|
|
foreach (Db::getInstance()->executeS('SELECT `id_tab`, `class_name` FROM `'._DB_PREFIX_.'tab`') as $t) {
|
|
$allowed = array_key_exists($t['class_name'], self::PROFILE_TABS);
|
|
$edit = $allowed && self::PROFILE_TABS[$t['class_name']];
|
|
$rows[] = array('id_profile' => $idProfile, 'id_tab' => (int)$t['id_tab'], 'view' => (int)$allowed,
|
|
'add' => (int)$edit, 'edit' => (int)$edit, 'delete' => 0, 'kpi' => 0);
|
|
}
|
|
return Db::getInstance()->insert('access', $rows);
|
|
}
|
|
|
|
public function getContent()
|
|
{
|
|
Tools::redirectAdmin($this->context->link->getAdminLink('AdminFrontDesk'));
|
|
}
|
|
}
|