Files
hotel/modules/frontdesk/frontdesk.php
DanielS f3b1838402 Add frontdesk: simple "Rezeption" page and staff profile
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>
2026-11-12 00:26:13 +01:00

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'));
}
}