Browse Source

checkpermission fixes

szollosil 10 months ago
parent
commit
2e354b5454

+ 15 - 7
custom/bbus/class/api_bbus.class.php

@@ -63,6 +63,7 @@ require_once DOL_DOCUMENT_ROOT . '/custom/bbus/class/exchangerateupdater.class.p
 require_once DOL_DOCUMENT_ROOT . '/custom/bbus/class/bbticketvalidationcoords.class.php';
 require_once DOL_DOCUMENT_ROOT . '/custom/bbus/class/api_curl.class.php';
 require_once DOL_DOCUMENT_ROOT . '/custom/bbus/class/roller_handling.class.php';
+require_once DOL_DOCUMENT_ROOT . '/custom/bbus/class/product_sync.class.php';
 
 /**
  * API class for products
@@ -74,6 +75,7 @@ class BBus extends DolibarrApi
 {
 	use CurlApi;
 	use RollerHandling;
+	use ProductSync;
 
 	private $code;
 	private $printingTime;
@@ -641,7 +643,7 @@ class BBus extends DolibarrApi
 		global $user, $db, $conf;
 		ApiBbusLog::appLog("checkPermission_START");
 		$memcached = new Memcached();
-		$memcached->addServer($conf->global->CONF_MEMCACHED, 11211);
+		$memcached->addServer($conf->global->CONF_MEMCACHED, $conf->global->CONF_MEMCACHED_PORT);
 		$key = '"' . $user->api_key . '"';
 
 		$cacheValue = $memcached->get($key);
@@ -724,7 +726,7 @@ class BBus extends DolibarrApi
 	/**
 	 * localCheckAvailablePlacesForCheckPermission
 	 *
-	 * @param  int $product_id			Product rowid
+	 * @param  string $product_id			Product rowid
 	 *
 	 * @return array|mixed Data without useless information
 	 *
@@ -734,7 +736,7 @@ class BBus extends DolibarrApi
 	 * @throws RestException 403
 	 * @throws RestException 404
 	 */
-	public function localCheckAvailablePlacesForCheckPermission($product_id)
+	public function localCheckAvailablePlacesForCheckPermission($product_id, $hotelsales = 0)
 	{
 		$date_from = $this->getCutOffTimeDate($product_id);
 		$sql = "SELECT 
@@ -742,12 +744,18 @@ class BBus extends DolibarrApi
 			FROM llx_actioncomm as ac 
 			LEFT JOIN llx_actioncomm_extrafields as ace ON ace.fk_object = ac.id
 			INNER JOIN llx_eventwizard_eventdetails as ed ON ac.fk_element = ed.rowid
-			INNER JOIN llx_eventwizard_eventproduct as ep ON ep.fk_eventdetails = ac.fk_element
-			WHERE ac.code = 'AC_EVENT'
-			AND ep.fk_product = {$product_id}
+			INNER JOIN llx_eventwizard_eventproduct as ep ON ep.fk_eventdetails = ac.fk_element";
+			if($hotelsales !== 0){
+				$sql .= " INNER JOIN llx_product_extrafields as pre ON pre.fk_object = ep.fk_product";
+			}
+			$sql .= " WHERE ac.code = 'AC_EVENT'";
+			if($hotelsales !== 0){
+				$sql .= " AND pre.hotelsales = 1";
+			}
+			$sql .= " AND ep.fk_product IN ({$product_id})
 			AND ac.datep > '{$date_from}' 
 			ORDER BY ac.datep ASC";
-		//ApiBbusLog::appLog($sql);
+		ApiBbusLog::appLog($sql);
 
 		$result = $this->db->query($sql);
 		return $this->db->num_rows($result) > 0 ? 1 : 0;

+ 81 - 0
custom/bbus/class/product_sync.class.php

@@ -0,0 +1,81 @@
+<?php
+trait ProductSync
+{
+    private $productJSON;
+    private $productPriceJSON;
+    private $productExtrafieldsJSON;
+
+    /**
+	 * Product syncronisation
+	 * 
+	 * @return array|mixed|string Data without useless information
+	 * 
+	 * @url POST Sync
+	 */
+    public function Sync()
+    {
+        $this->BBUSProductJSON();
+        $this->curlRunner('bbus/syncproduct', '', 'POST', true);
+        //$this->BBUSProductPriceJSON();
+        //$this->BBUSProductExtrafieldsJSON();
+        //print_r($this->productJSON);
+        exit;
+        return 'OK';
+    }
+
+    private function BBUSProductJSON(): void {
+        $sql = "SELECT * FROM llx_product WHERE rowid > 5000";
+        $this->productJSON = $this->CreateJSON($sql);
+    }
+
+    private function BBUSProductPriceJSON(): void {
+        $sql = "SELECT * FROM llx_product_price WHERE fk_object > 5000";
+        $this->productPriceJSON = $this->CreateJSON($sql);
+    }
+    
+    private function BBUSProductExtrafieldsJSON(): void {
+        $sql = "SELECT * FROM llx_product_extrafields WHERE fk_object > 5000";
+        $this->productExtrafieldsJSON = $this->CreateJSON($sql);
+    }
+
+    private function CreateJSON($sql): string
+    {
+        global $db;
+        $array = [];
+        $JSON = '';
+        $result = $db->query($sql);
+        if ($db->num_rows($result) > 0) {
+            while ($row = $db->fetch_object($result)) {
+                $array[] = $row;
+            }
+            $JSON = json_encode($array);
+        }
+        return $JSON;
+    }
+
+    private function decodeJSON($JSON):array{
+        if($JSON !== ''){
+            return json_decode($JSON);
+        }
+        return [];
+    } 
+
+    /**
+	 * syncproduct
+	 *
+	 * @param  int $product_id			Product rowid
+	 *
+	 * @return array|mixed Data without useless information
+	 *
+	 * @url POST syncproduct
+	 *
+	 * @throws RestException 401
+	 * @throws RestException 403
+	 * @throws RestException 404
+	 */
+	public function syncproduct($JSON)
+	{
+		$products = $this->decodeJSON($JSON);
+        print_r($products);
+	}
+}

+ 348 - 0
custom/bbus/nsu_controller.class.php

@@ -0,0 +1,348 @@
+<?php
+
+require_once DOL_DOCUMENT_ROOT . '/custom/bbus/nsu_controller_helper.class.php';
+require_once DOL_DOCUMENT_ROOT . '/custom/bbus/nsu_log.class.php';
+
+
+class DBARRAPIInvoice extends DolibarrApi
+{
+    public $nsuControllerHelper = new NsuControllerHelper();
+    /**
+     * Invoice/draft
+     * 
+     * @param  array $cart	//product ID => darabszám
+     * @param  boolean $invoice	// Invoice / Receipt
+     * 
+     *
+     * @return array|mixed Data without useless information
+     *
+     * @url POST draft
+     */
+    public function draft(array $cart, boolean $invoice = false, int $billing_id = null)
+    {
+        $array = [];
+        $log_id = ApiNSULog::getLogId();
+        ApiNSULog::invoiceLog("{$log_id}: DBARRAPIInvoice->draft");
+        $dbTransactionID = $this->nsuControllerHelper->generateTransactionID($log_id);
+        $lines = $this->nsuControllerHelper->getProductLines($product_id);
+        $apiInvoiceHelper = new ApiInvoiceHelper;
+		$invoiceObj = $apiInvoiceHelper->createInvoice($invoice, $log_id, $company_invoice);
+		ApiNSULog::invoiceLog("{$log_id} Invoice created");
+		$products = [];
+
+		foreach ($lines as $line) {
+			$invoiceObj = $apiInvoiceHelper->addLineToInvoice($invoiceObj, $line, $log_id);
+
+			$product = $apiInvoiceHelper->loadProductToResult($line);
+			if (!empty($product)) {
+				$products[] = $product;
+			}
+		}
+
+		$invoiceObj->fetch_lines();
+
+		foreach ($products as &$row) {
+			foreach ($invoiceObj->lines as $line) {
+				if ($line->product_ref == $row['ref']) {
+					$row['price'] = $line->multicurrency_total_ttc;
+					$row['total_tva'] = $line->total_tva;
+				}
+			}
+		}
+        return $array;
+    }
+
+    /**
+     * Invoice/createInvoice
+     * 
+     * @param  string $dolibar_transaction_id	//Dolibarr transaction id
+     * @param  string $simple_transaction_id	//Simple Pay transaction id
+     * @param  array $payment	                //Payment array
+     * @param  array $invoice	                //Invoice array
+     * @param  string $log_id	                //logId
+     * 
+     * 
+     *
+     * @return array|mixed Data without useless information
+     *
+     * @url POST createInvoice
+     */
+    public function createInvoice(string $dolibar_transaction_id, string $simple_transaction_id, array $payment, array $invoice, string $log_id)
+    {
+        $array = [];
+        $apiInvoiceHelper = new ApiInvoiceHelper;
+        $invoiceObj = []
+        $invoiceObj = $apiInvoiceHelper->validateInvoice($invoiceObj, $log_id);
+		/**
+		 * set payment
+		 */
+		$apiInvoiceHelper->setPayment($invoiceObj, $payment, $log_id);
+		/**
+		 * save card payment data
+		 */
+		if (!empty($cardPaymentLog)) {
+			$invoiceObj = $apiInvoiceHelper->saveCardPaymentLog($invoiceObj, $cardPaymentLog, $log_id);
+		}
+
+		ApiBbusLog::appLog("{$log_id} Invoice created. ID: {$invoiceObj->id} REF: {$invoiceObj->ref} REQ: {$log_id}");
+		dol_syslog("{$log_id} Invoice created. ID: {$invoiceObj->id} REF: {$invoiceObj->ref} REQ: {$log_id}", LOG_INFO, 0);
+		//$bbApiLock->delete($user);
+
+		ApiBbusLog::appLog("{$log_id}####################################################################");
+		dol_syslog("{$log_id}####################################################################", LOG_INFO, 0);
+
+        $products = [];
+
+		return [
+			'log_id' => $log_id,
+			'invoice' => [
+				'id' => $invoiceObj->id,
+				'ref' => $invoiceObj->ref,
+				'total' => $invoiceObj->multicurrency_total_ttc
+			],
+			'products' => $products,
+		];
+        return $array;
+    }
+
+    /**
+     * Invoice/list 
+     *
+     * @param  int $backenduser_id  //ID of the backenduser
+
+     * @return array|mixed Data without useless information
+     *
+     * @url GET list
+     */
+    public function list($backenduser_id)
+    {
+        $array = [];
+        $sql = "SELECT * FROM llx_facture as f INNER JOIN llx_facture_extrafields as fe ON fe.fk_facture = f.rowid WHERE fe.backenduser_id = {$backenduser_id}";
+        $array = $this->nsuControllerHelper->getObject($sql);
+        return $array;
+    }
+
+    /**
+     * Invoice/details
+     * 
+     * @param  int $facture_id	//Facture rowid
+     * 
+     *
+     * @return array|mixed Data without useless information
+     *
+     * @url GET details
+     */
+    public function deatils(int $facture_id)
+    {
+        global $db;
+        $factureObj = new Facture($db);
+        $result = $factureObj->fetch($facture_id);
+        if($db->num_rows($result) > 0){
+            return $factureObj;
+        }
+        return [];
+    }
+
+    /**
+     * Invoice/resend
+     * 
+     * @param  int $facture_id	//Facture rowid
+     * 
+     *
+     * @return array|mixed Data without useless information
+     *
+     * @url GET resend
+     */
+    public function resend(int $facture_id)
+    {
+        $array = [];
+        $note = "";
+        $this->nsuControllerHelper->emailSender($note, $array);
+    }
+}
+
+class DBARRAPIBilling extends DolibarrApi
+{
+    public $nsuControllerHelper = new NsuControllerHelper();
+    /**
+     * billing/create
+     * 
+     * @param  string $name
+     * @param  string $city
+     * @param  int $zip
+     * @param  string $town
+     * @param  int $currency
+     * @param  string $currencyCode
+     * 
+     * @return array|mixed Data without useless information
+     *
+     * @url POST create
+     */
+    public function create(string $name, string $city, int $zip, string $town, int $currency, string $currencyCode)
+    {
+        $array = [];
+        global $db, $user;
+        $ThirdPartyObj = new Societe($db);
+        $ThirdPartyObj->nom = $name;
+        $ThirdPartyObj->entity = 1;
+        $ThirdPartyObj->address = $city;
+        $ThirdPartyObj->zip = $zip;
+        $ThirdPartyObj->town = $town;
+        $ThirdPartyObj->fk_multicurrency = $currency;
+        $ThirdPartyObj->multicurrency_code = $currencyCode;
+        $result = $ThirdPartyObj->create($user);
+        if($result){
+            return $ThirdPartyObj;  # Megnézni, hogy mivel tér vissza és mit kell visszaadni.
+        }
+        return $array;
+    }
+
+    /**
+     * billing/modify
+     * 
+     * @param  int $thirdpartyID
+     * @param  string $name
+     * @param  string $city
+     * @param  int $zip
+     * @param  string $town
+     * @param  int $currency
+     * @param  string $currencyCode
+     * 
+     * @return array|mixed Data without useless information
+     *
+     * @url POST modify
+     */
+    public function modify(int $thirdpartyID, string $name, string $city, int $zip, string $town, int $currency, string $currencyCode)
+    {
+        $array = [];
+        global $db, $user;
+
+        $ThirdParty = new Societe($db);
+        $result = $ThirdPartyObj->fetch($thirdpartyID);
+        $ThirdPartyObj->nom = $name;
+        $ThirdPartyObj->entity = 1;
+        $ThirdPartyObj->address = $city;
+        $ThirdPartyObj->zip = $zip;
+        $ThirdPartyObj->town = $town;
+        $ThirdPartyObj->fk_multicurrency = $currency;
+        $ThirdPartyObj->multicurrency_code = $currencyCode;
+        $result = $ThirdPartyObj->update($user);
+        if($result){
+            return $ThirdPartyObj;  # Megnézni, hogy mivel tér vissza és mit kell visszaadni.
+        }
+        return $array;
+    }
+
+    /**
+     * billing/delete
+     * 
+     * @param  int $thirdpartyID
+     * @param  string $name
+     * @param  string $city
+     * @param  int $zip
+     * @param  string $town
+     * @param  int $currency
+     * @param  string $currencyCode
+     * 
+     * @return array|mixed Data without useless information
+     *
+     * @url POST delete
+     */
+    public function delete(int $thirdpartyID)
+    {
+        global $db, $user;
+
+        $ThirdParty = new Societe($db);
+        $result = $ThirdPartyObj->delete($thirdpartyID);
+        if($result){
+            return true;  # Megnézni, hogy mivel tér vissza és mit kell visszaadni.
+        }
+        return false;
+    }
+}
+
+class DBARRAPIFacilities extends DolibarrApi
+{
+    public $nsuControllerHelper = new NsuControllerHelper();
+    /**
+     * ticket/list
+     * 
+     * @return array|mixed Data without useless information
+     *
+     * @url GET list
+     */
+    public function list()
+    {
+        $array = [];
+        return $array;
+    }
+
+    /**
+     * ticket/details
+     * 
+     * @param  int $facility_id	    //facility ID
+     * 
+     * @return array|mixed Data without useless information
+     *
+     * @url GET details
+     */
+    public function details(int $facility_id)
+    {
+        $array = [];
+        return $array;
+    }
+}
+
+class DBARRAPITicket extends DolibarrApi
+{
+    public $nsuControllerHelper = new NsuControllerHelper();
+    /**
+     * ticket/details
+     * 
+     * @param  int $ticket_id	        //ticket rowid
+     * @param  int $backend_user_id	    //backend_user_id
+     * 
+     *
+     * @return array|mixed Data without useless information
+     *
+     * @url GET details
+     */
+    public function details(int $ticket_id, int $backend_user_id)
+    {
+        $array = [];
+        global $db;
+        $NSUTIcketObj = new NSUTicket($db);
+        $result = $NSUTIcketObj->fetch($ticket_id);
+        if($db->num_rows($result) > 0){
+            return $NSUTIcketObj;
+        }
+        return $array;
+    }
+
+    /**
+     * ticket/tickets
+     * 
+     * @param  int $backenduser_id	    //backend_user_id
+     * 
+     *
+     * @return array|mixed Data without useless information
+     *
+     * @url GET tickets
+     */
+    public function tickets(int $backenduser_id)
+    {
+        $array = [];
+        $facturesArray = DBARRAPIInvoice::list($backenduser_id);
+        if(!empty($facturesArray)){
+            $tmp_factures_array = [];
+            foreach($facturesArray as $facture){
+                $tmp_factures_array[] = $facture['rowid'];
+            }
+            $factures = implode(',', $tmp_factures_array);
+            $sql = "SELECT * FROM llx_nsu_ticket as t WHERE t.fk_facture IN ({$factures})";
+            $array = $this->nsuControllerHelper->getObject($sql);
+        }
+        
+        return $array;
+    }
+}

+ 99 - 0
custom/bbus/nsu_controller_helper.class.php

@@ -0,0 +1,99 @@
+<?php
+class NsuControllerHelper{
+    const EMAIL_TEMPLATE = 'invoiceemail';
+	const GLOBAL_CONF_SEND_TO_EMAIL = 'BBUS_INVOICE_PRINTING_ALERT_EMAIL';
+	
+	const GLOBAL_CONF_EMAIL_FROM = 'GLOBAL_CONF_EMAIL_FROM';
+	const INVOICE_SUBJECT = 'INVOICE_SUBJECT';
+	const INVOICE_DESCRIPTION = 'INVOICE_DESCRIPTION';
+
+    public function getObject($sql){
+        global $db;
+        $array = [];
+        $result = $db->query($sql);
+        if($db->num_rows($result) > 0){
+            while($row = $db->fetch_object($result)){
+                $array[] = $row;
+            }
+        }
+        return  $array;
+    }
+
+    public function generateTransactionID($sendId){
+        $DBARTransactionID = substr(bin2hex(random_bytes(16)), 0, 16);
+        ApiNSULog::invoiceLog("{$sendId}: DBAR Transaction ID: {$DBARTransactionID}");
+        return $DBARTransactionID;
+    }
+
+    public function getProductLines($product_id)
+	{
+        global $db;
+        $lines = [];
+		$productObj = new Product($db);
+		$result = $productObj->fetch($product_id);
+        if($db->num_rows($result) > 0){
+            $lines[] = (array) $productObj;
+        }
+		return $lines;
+	}
+
+    public function emailSender($note, $createdInvoiceArray)
+	{
+		foreach ($createdInvoiceArray as $invoice) {
+			$note_array = [];
+			ApiNSULog::invoiceLog("Start E-mail sending");
+			$note_array = json_decode($note, true);
+			$emailAddress = $note_array['email'];
+
+			$const = new GlobalConst;
+			$emailFrom = $const->load(self::GLOBAL_CONF_EMAIL_FROM);
+			$recipients = $emailAddress;
+			//$recipients = 'szollosi.laszlo@urbanms.hu';
+			if (!empty($recipients) && !empty($emailFrom)) {
+				$emailTemplateHandler = new EmailTemplateHandler;
+				$template = $emailTemplateHandler->load(self::EMAIL_TEMPLATE);
+				$templateObject = new stdClass();
+				foreach ($template as $key => $value) {
+					$templateObject->$key = $value;
+				}
+				if ($templateObject) {
+					$varsInvoice = [
+						'__SUBJECT__' => $const->load(self::INVOICE_SUBJECT),
+						'__DESCRIPTION__' => $const->load(self::INVOICE_DESCRIPTION),
+					];
+					$template = $emailTemplateHandler->prepareTemplate($templateObject, $varsInvoice);
+					$attachment = [DOL_DOCUMENT_ROOT . '/documents/facture/' . $invoice['invoice']['ref'] . '/' . $invoice['invoice']['ref'] . '.pdf'];
+					$mimetype = ['application/pdf'];
+					$mimefilename = [$invoice['invoice']['ref'] . '.pdf'];
+					$mail = new CMailFile(
+						$template->topic,
+						$recipients,
+						$emailFrom,
+						$template->content,
+						$attachment,
+						$mimetype,
+						$mimefilename,
+						//null,
+						//null,
+						//null,
+						'',
+						'',
+						0,
+						1
+					);
+					// Send Email
+					$mail->sendfile();
+					ApiNSULog::invoiceLog('E-mail address: ' . $emailAddress);
+
+					if ($mail->error) {
+						ApiNSULog::invoiceLog($mail->error);
+						// do something...
+						dol_syslog('CRON ALERT EMAIL ERROR: ' . $mail->error, LOG_ERR);
+					} else {
+						ApiNSULog::invoiceLog("E-mail sent");
+					}
+				}
+			}
+		}
+	}
+}

+ 13 - 0
custom/bbus/nsu_log.class.php

@@ -0,0 +1,13 @@
+<?php
+class ApiNSULog
+{
+    public static function getLogId()
+    {
+        return '#' . bin2hex(random_bytes(10)) . '#';
+    }
+    public static function invoiceLog(string $message): void
+    {
+        $dateSuffix = date("Ymd", dol_now());
+        dol_syslog($message, LOG_INFO, 0, '_invoice_' . $dateSuffix);
+    }
+}

+ 248 - 0
custom/booking/reservation.class.php

@@ -0,0 +1,248 @@
+<?php
+class Reservation
+{
+    public $db;
+
+    private $selects = ["area", "facilitie", "profile"];
+
+    private function timelineGenerator($from, $to)
+    {
+        $intervals = [];
+        $startTime = strtotime($from);
+        $endTime = strtotime($to);
+        $index = 0;
+
+        while ($startTime < $endTime) {
+            $start = date("H:i", $startTime);
+            $end = date("H:i", strtotime('+30 minutes', $startTime));
+            $intervals[$index] = "$start - $end";
+            $startTime = strtotime('+30 minutes', $startTime);
+            $index++;
+        }
+        return $intervals;
+    }
+
+    public function generateSelectorInput($id, $selector, $selected)
+    {
+        $this->selectorInputFirstSegment($id);
+        $this->generateOptions($selector, $selected);
+        print '</select>
+        <p id="request_' . $id . '" style="color:red;" class="displayNone">Kötelező kitölteni</p>';
+        if ($id == 'facilitie') {
+            print '</div>';
+        }
+    }
+
+    public function generateSelectorInputForProfiles($id, $selector, $selected)
+    {
+        $this->selectorInputFirstSegment($id);
+        $this->generateOptionsFromArray($selector, $selected);
+        print '</select>
+        <p id="request_' . $id . '" style="color:red;" class="displayNone">Kötelező kitölteni</p>
+        </div></div>';
+    }
+
+    public function generateSelectorDateInput($id, $daterange)
+    {
+        global $langs;
+        print '<div class="box ' . $id . 'Class displayNone">
+            <label for="' . $id . '" class="form-label">' . $langs->trans('DateSelector') . ':</label>
+                <input  type="text" style="height: 28px; width: 200px;" id="date-range" name="daterange" value="' . $daterange . '"><i class="fa fa-calendar" style="margin-left: -20px;"></i>
+        <p id="request_' . $id . '" style="color:red;" class="displayNone">Kötelező kitölteni</p></div>';
+    }
+
+    private function selectorInputFirstSegment($id)
+    {
+        global $langs;
+        $class = $id == 'facilitie' ? '' : 'displayNone';
+        if ($id == 'facilitie') {
+            print '<div class="box ' . $id . 'Class ' . $class . '">';
+        }
+        print '<label for="' . $id . '" class="form-label">' . $id . ' :</label>
+        <select class="flat widthcentpercentminusx maxwidth300" id="' . $id . '" name="' . $id . '" data-select2-id="' . $id . '" tabindex="-1"><option class="optiongrey" value="-1" data-select2-id="33">&nbsp;</option>
+        ';
+    }
+
+    public function generateJavaScriptFirstSection($profile)
+    {
+
+        $script = '<script>var eventSelect = $("#profile");
+        eventSelect.select2();
+        eventSelect.on("change", function(e) {
+            var selectedValue = $(this).val();
+            var selectedText = $(this).find("option:selected").text();';
+        print $script;
+        exit;
+        return $script;
+    }
+
+    public function generateJavascript($profile, $time)
+    {
+
+        $script = 'if (selectedValue == ' . $profile['id'] . ') {';
+        $script .= '
+                $("#' . $profile['frameName'] . '").removeClass("displayNone").addClass("displayBlock");';
+        $script .= '}';
+        $script .= '$("#time1").val("' . $time[0] . '");
+        $("#time2").val("' . $time[1] . '");';
+        return $script;
+    }
+
+    public function generateJavaScriptLastSection($profiles)
+    {
+
+        $script = '});
+        $(document).ready(function() {
+            var areaSelect = $("#area").val();
+            if(areaSelect == -1){
+                $("#area").prop("disabled", true);
+            }
+
+            var profileSelect = $("#profile").val();
+            if(profileSelect == -1){
+                $("#profile").prop("disabled", true);
+            }';
+        foreach ($this->selects as $select) {
+            $script .= '$("#' . $select . '").select2({
+                    dir: "ltr",
+                    width: "resolve",
+                    minimumInputLength: 0,
+                    language: select2arrayoflanguage,
+                    matcher: function(params, data) {
+                        if ($.trim(params.term) === "") {
+                            return data;
+                        }
+                        keywords = (params.term).split(" ");
+                        for (var i = 0; i < keywords.length; i++) {
+                            if (((data.text).toUpperCase()).indexOf((keywords[i]).toUpperCase()) == -1) {
+                                return null;
+                            }
+                        }
+                        return data;
+                    },
+                    theme: "default",
+                    containerCssClass: ":all:",
+                    selectionCssClass: ":all:",
+                    templateResult: function(data, container) {
+                        if (data.element) {
+                            $(container).addClass($(data.element).attr("class"));
+                        }
+                        if (data.id == -1 && $(data.element).attr("data-html") == undefined) {
+                            return "&nbsp;";
+                        }
+                        if ($(data.element).attr("data-html") != undefined) return htmlEntityDecodeJs($(data.element).attr("data-html")); // If property html set, we decode html entities and use this
+                        return data.text;
+                    },
+                    templateSelection: function(selection) {
+                        if (selection.id == -1) return \'<span class="placeholder">\' + selection.text + "</span>";
+                        return selection.text;
+                    },
+                    escapeMarkup: function(markup) {
+                        return markup;
+                    },
+                    dropdownCssClass: "ui-dialog"
+                    });';
+        }
+
+        $script .= 'var eventSelect = $("#' . $select . '");
+        eventSelect.select2();
+        var selectedText = eventSelect.find("option:selected").val();
+        console.log("selectedText: " + selectedText);
+        if (selectedText == -1) {';
+        foreach ($profiles as $profile) {
+            $script .= '$("#' . $profile['frameName'] . '").addClass("displayNone");';
+        }
+        $script .= '}else{';
+        foreach ($profiles as $profile) {
+            foreach ($profiles as $profile) {
+                $script .= 'var profile_' . $profile['name'] . ' = ' . $profile['id'] . ';';
+                $script .= 'if(profile_' . $profile['name'] . ' == selectedText){';
+                $script .= '$("#' . $profile['frameName'] . '").addClass("displayBlock");';
+                $script .= '}else{';
+                $script .= '$("#' . $profile['frameName'] . '").addClass("displayNone");}';
+            }
+        }
+        $script .= '}';
+        $script .= '})</script><!-- generateJavaScriptFirstSection END -->';
+        return $script;
+    }
+
+    public function selectedProfile($profile)
+    {
+        $content = '';
+        if ($profile['type'] == 'H') {
+            $content .= '<div id="' . $profile['frameName'] . '"><p style="text-align: center;">' . $profile['name'] . '</p>';
+            for ($i = 1; $i <= $profile['lines']; $i++) {
+                $Availability = 'LineGreen';
+                $content .= '<div id="' . $profile['idclass'] . $i . '" class="' . $Availability . ' ' . $profile['idclass'] . '" onClick="lineClick(' . $profile['id'] . ',' . $i . ',\'' . $profile['idclass'] . '\')">' . $i . '.</div>';
+                //$content .= '<!-- ' . $profile['idclass'] . ' Line ' . $i . '. JS -->';
+            }
+            $content .= '</div>';
+        }
+        if ($profile['type'] == 'V') {
+            $content .= '<div id="' . $profile['frameName'] . '"><p style="text-align: center;">' . $profile['name'] . '</p>';
+            $content .= '<div id="VerticalContainer">';
+            for ($i = 1; $i <= $profile['lines']; $i++) {
+                $Availability = 'LineGreen';
+                $content .= '<div id="' . $profile['idclass'] . $i . '" class="' . $Availability . ' ' . $profile['idclass'] . '" onClick="lineClick(' . $profile['id'] . ',' . $i . ',\'' . $profile['idclass'] . '\')">' . $i . '.</div>';
+                //$content .= '<!-- ' . $profile['idclass'] . ' Line ' . $i . '. JS -->';
+            }
+            $content .= '</div>';
+            $content .= '</div>';
+        }
+        return $content;
+    }
+
+    public function selectedProfileWithTimes($profile, $times)
+    {
+        $from = $times[0];
+        $to = $times[1];
+        $content = '';
+        $content .= '<div id="' . $profile['frameName'] . '" class="profilesClass"><p style="text-align: center;">' . $profile['name'] . '</p>';
+        foreach ($this->timelineGenerator($from, $to) as $key => $value) {
+            $content .= '<div id="VerticalContainer">';
+            $content .= '<div style="width: 100px; text-align: right; padding-right: 10px;" class="PoloTitle">' . $value . '</div>';
+            $array = [];
+            for ($i = 1; $i <= $profile['lines']; $i++) {
+                $Availability = 'LineGreen';
+                $content .= '<div id="' . $profile['idclass'] . '_' . $key . '_' . $i . '" class="' . $Availability . ' ' . $profile['idclass'] . '" onClick="lineClick(' . $profile['id'] . ',' . $key . ',' . $i . ',\'' . $profile['idclass'] . '\')">&nbsp;</div>';
+                $array[] = 0;
+            }
+            $content .= '<input id="' . $profile['idclass'] . '_' . $key . '" type="hidden" name="' . $profile['idclass'] . '_lines[]" class="" value=' . json_encode($array) . '>';
+            $content .= '<div onClick="lineFullClick(' . $profile['id'] . ',' . $key . ',' . $i . ',\'' . $profile['idclass'] . '\')">&nbsp;<i class="fa fa-arrow-left"></i></div>';
+            $content .= '</div>';
+        }
+        $content .= '</div>';
+        return $content;
+    }
+
+    private function generateOptions($array, $selected)
+    {
+
+        foreach ($array as $Key => $Value) {
+            $selectedString = $Key == $selected ? 'selected' : '';
+            print '<option value="' . $Key . '" ' . $selectedString . '>' . $Value . '</option>';
+        }
+    }
+
+    private function generateOptionsFromArray($array, $selected)
+    {
+        foreach ($array as $item) {
+            $selectedString = $item['id'] == $selected ? 'selected' : '';
+            print '<option value="' . $item['id'] . '" ' . $selectedString . '>' . $item['name'] . '</option>';
+        }
+    }
+
+    public function generateTimerLine($time1Value, $time2Value)
+    {
+        print '<div class="timerClass displayNone" style="margin: 20px 5px 0px 5px; text-align: center; background-color: lightgrey; padding-top: 10px; padding-bottom: 10px;">
+        <button type="button" onclick="adjustTime(\'' . $time1Value . '\',\'decrease\')">-</button>
+        <input type="text" pattern="[0-9]+:[0-9]{2}$" placeholder="hh:mm" id="time1" name="time1" value="' . $time1Value . '">
+        <button type="button" onclick="adjustTime(\'' . $time1Value . '\',\'increase\')">+</button>
+        - 
+        <button type="button" onclick="adjustTime(\'' . $time2Value . '\',\'decrease\')">-</button>
+        <input type="text" pattern="[0-9]+:[0-9]{2}$" placeholder="hh:mm" id="time2" name="time2" value="' . $time2Value . '">
+        <button type="button" onclick="adjustTime(\'' . $time2Value . '\',\'increase\')">+</button>
+        </div>';
+    }
+}

+ 137 - 0
custom/booking/reservation.css

@@ -0,0 +1,137 @@
+.container2 {
+    display: flex;
+    justify-content: space-between;
+    width: 100%;
+}
+
+.box {
+    flex: 1;
+    margin: 0 5px;
+    text-align: center;
+    padding: 10px;
+    background-color: lightgrey;
+}
+
+
+
+.displayNone {
+    display: none !important;
+}
+
+.displayBlock {
+    display: block;
+}
+
+#SwimmingPoolTitle,
+#PoolTitle,
+#PoloTitle {
+    clear: both;
+    display: flex;
+    flex-direction: column;
+    cursor: pointer;
+}
+
+.LineGreen {
+    width: 30px;
+    height: 30px;
+    background-color: lightgreen;
+    border: 2px solid white;
+    cursor: pointer;
+    /*padding: 5px;*/
+}
+
+.LineYellow {
+    width: 30px;
+    background-color: #f5e6ab;
+    padding: 5px;
+}
+
+.LineRed {
+    width: 30px;
+    height: 30px;
+    background-color: #e65054;
+    border: 2px solid white;
+    cursor: pointer;
+    /*padding: 5px;*/
+}
+
+#VerticalContainer {
+    display: flex;
+    justify-content: center;
+    align-items: center;
+    cursor: pointer;
+}
+
+.PoolLine {
+    margin-right: 2px;
+    margin-bottom: 2px;
+}
+
+.PoloLine {
+    margin-right: 2px;
+    margin-bottom: 2px;
+}
+
+.SwimmingPoolLine {
+    margin-right: 2px;
+    margin-bottom: 2px;
+}
+
+td.in-range:not(.end-date) {
+    background-color: #c8e4f1 !important;
+}
+
+.hide {
+    display: none;
+}
+
+.timeSelectBox {
+    display: inline-block;
+    width: 150px;
+    margin: 0 10px 0 0;
+    vertical-align: top;
+    border: 1px silver solid;
+    padding: 5px 10px;
+}
+
+input#date-range {
+    padding: 0 10px;
+}
+
+.time_slider {
+    display: none !important;
+    height: 0px !important;
+}
+
+.butSetDefault {
+    text-decoration: none;
+    text-transform: uppercase;
+    font-weight: bold;
+    margin: 0em 1em;
+    padding: 0.6em 0.7em;
+    display: inline-block;
+    text-align: center;
+    cursor: pointer;
+    color: white;
+    background-color: red;
+    border: 1px solid transparent;
+}
+
+/* hidden checkbox */
+.hidden-checkbox {
+    display: none;
+}
+
+.custom-checkbox-label {
+    display: inline-block;
+    width: 30px;
+    height: 30px;
+    background-color: #e65054; /* Kikapcsolt állapot (piros) */
+    border: 2px solid white;
+    cursor: pointer;
+    transition: background-color 0.3s ease;
+}
+
+.hidden-checkbox:checked + .custom-checkbox-label {
+    background-color: #4caf50; /* Bekapcsolt állapot (zöld) */
+}

+ 590 - 0
custom/booking/reservation.php

@@ -0,0 +1,590 @@
+<?php
+/* Copyright (C) 2001-2004 Rodolphe Quiedeville <rodolphe@quiedeville.org>
+ * Copyright (C) 2003      Eric Seigne          <erics@rycks.com>
+ * Copyright (C) 2004-2018 Laurent Destailleur  <eldy@users.sourceforge.net>
+ * Copyright (C) 2005-2012 Regis Houssin        <regis.houssin@inodbox.com>
+ * Copyright (C) 2011      Juanjo Menent        <jmenent@2byte.es>
+ * Copyright (C) 2014      Cedric GROSS         <c.gross@kreiz-it.fr>
+ * Copyright (C) 2015      Marcos García        <marcosgdf@gmail.com>
+ * Copyright (C) 2017      Open-DSI             <support@open-dsi.fr>
+ * Copyright (C) 2018-2021 Frédéric France      <frederic.france@netlogic.fr>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+
+/**
+ *  \file       htdocs/custom/booking/booking_agenda.php
+ *  \ingroup    agenda
+ *  \brief      Home page of calendar events
+ */
+
+// Load Dolibarr environment
+require '../../main.inc.php';
+require_once DOL_DOCUMENT_ROOT . '/custom/booking/reservation.class.php';
+
+if (isModEnabled('project')) {
+    require_once DOL_DOCUMENT_ROOT . '/core/class/html.formprojet.class.php';
+}
+
+if (!isset($conf->global->AGENDA_MAX_EVENTS_DAY_VIEW)) {
+    $conf->global->AGENDA_MAX_EVENTS_DAY_VIEW = 3;
+}
+
+if (empty($conf->global->AGENDA_EXT_NB)) {
+    $conf->global->AGENDA_EXT_NB = 5;
+}
+$MAXAGENDA = $conf->global->AGENDA_EXT_NB;
+
+$disabledefaultvalues = GETPOST('disabledefaultvalues', 'int');
+
+$check_holiday = GETPOST('check_holiday', 'int');
+$filter = GETPOST("search_filter", 'alpha', 3) ? GETPOST("search_filter", 'alpha', 3) : GETPOST("filter", 'alpha', 3);
+$filtert = GETPOST("search_filtert", "int", 3) ? GETPOST("search_filtert", "int", 3) : GETPOST("filtert", "int", 3);
+$usergroup = GETPOST("search_usergroup", "int", 3) ? GETPOST("search_usergroup", "int", 3) : GETPOST("usergroup", "int", 3);
+$showbirthday = empty($conf->use_javascript_ajax) ? GETPOST("showbirthday", "int") : 1;
+
+// If not choice done on calendar owner (like on left menu link "Agenda"), we filter on user.
+if (empty($filtert) && empty($conf->global->AGENDA_ALL_CALENDARS)) {
+    $filtert = $user->id;
+}
+
+$newparam = '';
+
+$sortfield = GETPOST('sortfield', 'aZ09comma');
+$sortorder = GETPOST('sortorder', 'aZ09comma');
+$page = GETPOSTISSET('pageplusone') ? (GETPOST('pageplusone') - 1) : GETPOST("page", 'int');
+if (empty($page) || $page == -1) {
+    $page = 0;
+}     // If $page is not defined, or '' or -1
+$limit = GETPOST('limit', 'int') ? GETPOST('limit', 'int') : $conf->liste_limit;
+$offset = $limit * $page;
+if (!$sortorder) {
+    $sortorder = "ASC";
+}
+if (!$sortfield) {
+    $sortfield = "a.datec";
+}
+
+// Security check
+$socid = GETPOST("search_socid", "int") ? GETPOST("search_socid", "int") : GETPOST("socid", "int");
+if ($user->socid) {
+    $socid = $user->socid;
+}
+if ($socid < 0) {
+    $socid = '';
+}
+
+$canedit = 1;
+if (empty($user->rights->agenda->myactions->read)) {
+    accessforbidden();
+}
+if (empty($user->rights->agenda->allactions->read)) {
+    $canedit = 0;
+}
+if (empty($user->rights->agenda->allactions->read) || $filter == 'mine') {  // If no permission to see all, we show only affected to me
+    $filtert = $user->id;
+}
+
+$action = GETPOST('action', 'aZ09');
+$time1 = GETPOST('time1', 'none');
+$time2 = GETPOST('time2', 'none');
+$facilitie = GETPOST('facilitie', 'numeric');
+$area = GETPOST('area', 'numeric');
+$profile = GETPOST('profile', 'numeric');
+$daterange = GETPOST('daterange', 'none');
+$addreservation = GETPOST('addreservation', 'numeric');
+
+$mode = GETPOST('mode', 'aZ09');
+if (empty($mode) && preg_match('/show_/', $action)) {
+    $mode = $action;    // For backward compatibility
+}
+
+// Load translation files required by the page
+$langs->loadLangs(array('agenda', 'other', 'commercial'));
+
+// Initialize technical object to manage hooks of page. Note that conf->hooks_modules contains array of hook context
+$hookmanager->initHooks(array('agenda'));
+
+$result = restrictedArea($user, 'agenda', 0, 'actioncomm&societe', 'myactions|allactions', 'fk_soc', 'id');
+if ($user->socid && $socid) {
+    $result = restrictedArea($user, 'societe', $socid);
+}
+
+$reshook = $hookmanager->executeHooks('beforeAgenda', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks
+if ($reshook < 0) {
+    setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
+}
+
+$help_url = 'EN:Module_Agenda_En|FR:Module_Agenda|ES:M&oacute;dulo_Agenda';
+llxHeader('', $langs->trans("Agenda"), $help_url);
+$form = new Form($db);
+$reservation = new Reservation();
+
+$facilities = ["1" => "Gellért fürdő", "2" => "Széchenyi fürdő", "3" => "Lukács fürdő"];
+$area2 = [
+    "1" => ["1" => "Medence_1", "2" => "Medence_2", "3" => "Focipálya"],
+    "2" => ["1" => "Medence_1", "2" => "Medence_2"],
+    "3" => ["1" => "Medence_1", "2" => "Focipálya"]
+];
+$areas = ["1" => "Medence_1", "2" => "Medence_2", "3" => "Focipálya"];
+$profiles = [
+    "1" => ["id" => 1, "idclass" => "SwimmingPoolLine", "name" => "SwimmingPool", "lines" => "6", "type" => 'H', "frameName" => "SwimmingPoolTitle"],
+    "2" => ["id" => 2, "idclass" => "PoolLine", "name" => "Pool", "lines" => "4", "type" => 'V', "frameName" => "PoolTitle"],
+    "3" => ["id" => 3, "idclass" => "PoloLine", "name" => "Polo", "lines" => "3", "type" => 'V', "frameName" => "PoloTitle"]
+];
+
+//print_r($_REQUEST);
+
+if ($addreservation == 1) {
+    print_r($_REQUEST);
+    /* $reservation = new stdClass();
+    $reservation->facilitie = $facilitie;
+    $reservation->area = $area;
+    $reservation->daterange = $daterange;
+    $reservation->profile = $profile;
+    $reservation->fromtime = $time1;
+    $reservation->totime = $time2;
+    print_r($reservation);exit; */
+}
+
+// Fürdő és Medence választás
+print '<div class="container mt-5"><h2>' . $langs->trans("reservationTitle") . '</h2><form id="reservatonForm" name="reservatonForm" onsubmit="return validatePage()">';
+print '<div class="container2">';
+print '<div style="width:100%; text-align:center; margin-top: 20px; margin-bottom: 20px;">
+<button type="button" style="width:25%;margin: 0em; margin-top: 20px;" class="butSetDefault" onclick="setDefault()">' . $langs->trans('SetDefault') . '</button></div>';
+print '</div>';
+
+print '<div class="container2">';
+if ($daterange == '') {
+    $daterange = date("Y-m-d", dol_now()) . ' - ' . date("Y-m-d", dol_now());
+}
+$reservation->generateSelectorInput('facilitie', $facilities, $facilitie);
+print '<div class="box areaClass displayNone"></div>';
+$reservation->generateSelectorDateInput('date', $daterange);
+print '<div class="box profileClass displayNone"></div>';
+print '</div>';
+$time1Value = $time1 == '' ? '06:00' : $time1;
+$time2Value = $time2 == '' ? '22:00' : $time2;
+//$reservation->generateTimerLine($time1Value, $time2Value);
+print '<div class="timerClass displayNone" style="margin: 20px 5px 0px 5px; text-align: center; background-color: lightgrey; padding-top: 10px; padding-bottom: 10px;">
+        <button type="button" onclick="adjustTime(\'time1\',\'decrease\')">-</button>
+        <input style="text-align: center;" type="text" pattern="[0-9]+:[0-9]{2}$" placeholder="hh:mm" id="time1" name="time1" maxlength="5" value="' . $time1Value . '" readonly>
+        <button type="button" onclick="adjustTime(\'time1\',\'increase\')">+</button>
+        - 
+        <button type="button" onclick="adjustTime(\'time2\',\'decrease\')">-</button>
+        <input style="text-align: center;" type="text" pattern="[0-9]+:[0-9]{2}$" placeholder="hh:mm" id="time2" name="time2" maxlength="5" value="' . $time2Value . '" readonly>
+        <button type="button" onclick="adjustTime(\'time2\',\'increase\')">+</button>
+        </div>';
+print '<div class="profileTypeClass"></div>';
+print '<div style="width:100%; margin: 0px 5px 0px 5px;"><button style="width:100%;margin: 0em; margin-top: 20px;" id="addreservation" name="addreservation" type="submit" value="1" class="butAction">Küldés</button></div>';
+print '</div>';
+print '</form></div>';
+?>
+<link rel="stylesheet" type="text/css" href="reservation.css">
+<script>
+    var gen = {
+        setElem: "ok",
+        init: function() {
+            var now = new Date;
+            $("#date-range").attr("date-start", now.toISOString().slice(0, 10));
+            $("#date-range").attr("date-end", now.toISOString().slice(0, 10));
+
+            $(document).on("input", ".timestart", function(event) {
+                if (gen.setElem == "ok") {
+                    gen.setElem = "input";
+                    var elem = $(this);
+                    var a = (elem.val()).split(":");
+                    var b = (elem.parent().find(".durationtime").val()).split(":");
+                    var time = new Date();
+                    time.setHours(parseInt(a[0]), parseInt(a[1]), 00, 000);
+                    time.setMinutes(time.getMinutes() + parseInt(b[1]));
+                    time.setHours(time.getHours() + parseInt(b[0]));
+                    // var c = [time.getHours(), time.getMinutes()];
+                    elem.parent().find(".timeend").val(time.getHours() + ":" + time.getMinutes())
+                    var minutes = [parseInt(a[0]) * 60 + parseInt(a[1]), parseInt(b[0]) * 60 + parseInt(b[1])];
+                    if (isNaN(minutes[0])) {
+                        minutes[0] = 0;
+                    }
+                    if (isNaN(minutes[1])) {
+                        minutes[1] = 0;
+                    }
+                    elem.parent().parent().find(".time_slider").slider("values", 0, minutes[0]);
+                    elem.parent().parent().find(".time_slider").slider("values", 1, minutes[0] + minutes[1]);
+                    elem.parent().find(".timestart").attr("info", minutes[0]);
+                    elem.parent().find(".timeend").attr("info", minutes[0] + minutes[1]);
+                    // elem.parent().find(".durationtime").attr("info",minutes[1]);
+                    gen.setElem = "ok";
+                }
+            });
+            $(document).on("input", ".durationtime", function(event) {
+                if (gen.setElem == "ok") {
+                    gen.setElem = "input";
+                    var elem = $(this);
+                    var a = (elem.parent().find(".timestart").val()).split(":");
+                    var b = (elem.val()).split(":");
+                    var time = new Date();
+                    time.setHours(parseInt(a[0]), parseInt(a[1]), 00, 000);
+                    time.setMinutes(time.getMinutes() + parseInt(b[1]));
+                    time.setHours(time.getHours() + parseInt(b[0]));
+                    // var c = [time.getHours(), time.getMinutes()];
+                    elem.parent().find(".timeend").val(time.getHours() + ":" + time.getMinutes())
+                    var minutes = [parseInt(a[0]) * 60 + parseInt(a[1]), parseInt(b[0]) * 60 + parseInt(b[1])];
+                    if (isNaN(minutes[0])) {
+                        minutes[0] = 0;
+                    }
+                    if (isNaN(minutes[1])) {
+                        minutes[1] = 0;
+                    }
+                    // console.log(minutes);
+                    elem.parent().parent().find(".time_slider").slider("values", 0, minutes[0]);
+                    elem.parent().parent().find(".time_slider").slider("values", 1, minutes[0] + minutes[1]);
+                    elem.parent().find(".timestart").attr("info", minutes[0]);
+                    elem.parent().find(".timeend").attr("info", minutes[0] + minutes[1]);
+                    // elem.parent().find(".durationtime").attr("info",minutes[1]);
+                    gen.setElem = "ok";
+                }
+            });
+
+
+            var option = {
+                //autoUpdateInput: false,
+                locale: {
+                    "format": "YYYY-MM-DD",
+                    cancelLabel: "M&eacute;gse",
+                    applyLabel: "Ok",
+                    "monthNames": [
+                        "janu&aacute;r",
+                        "febru&aacute;r",
+                        "m&aacute;rcius",
+                        "&aacute;prilis",
+                        "m&aacute;jus",
+                        "j&uacute;nius",
+                        "j&uacute;lius",
+                        "augusztus",
+                        "szeptember",
+                        "okt&oacute;ber",
+                        "november",
+                        "december"
+                    ],
+                    "daysOfWeek": [
+                        "Vas",
+                        "H&eacute;",
+                        "Ke",
+                        "Sze",
+                        "Cs&uuml;t",
+                        "P&eacute;",
+                        "Szo"
+                    ],
+                }
+            };
+            $("#date-range").daterangepicker(option, function(start, end, label) {
+                $("#date-range").attr("date-start", start.format("YYYY-MM-DD"));
+                $("#date-range").attr("date-end", end.format("YYYY-MM-DD"));
+            });
+        },
+    };
+    $(function() {
+        gen.init();
+    });
+</script>
+<script type="text/javascript" src="https://cdn.jsdelivr.net/momentjs/latest/moment.min.js"></script>
+<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/daterangepicker/daterangepicker.min.js"></script>
+<link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/npm/daterangepicker/daterangepicker.css">
+<script>
+    $("form").on("keydown", function(event) {
+        if (event.key === "Enter") {
+            event.preventDefault();
+        }
+    });
+    /* document.getElementById("time1").addEventListener("input", function() {
+        let input = this.value.replace(/[^0-9]/g, ""); // Csak számokat enged meg
+        let hours = input.slice(0, 2);
+        let minutes = input.slice(2, 4);
+
+        if (hours.length === 1 && hours > "2") {
+            hours = "0" + hours;
+        } else if (hours.length === 2 && parseInt(hours, 10) > 23) {
+            hours = "23";
+        }
+
+        if (minutes.length === 2 && parseInt(minutes, 10) > 59) {
+            minutes = "59";
+        }
+
+        this.value = hours + (minutes ? ':' + minutes : '');
+    });
+
+    document.getElementById("time2").addEventListener("input", function() {
+        let input = this.value.replace(/[^0-9]/g, ""); // Csak számokat enged meg
+        let hours = input.slice(0, 2);
+        let minutes = input.slice(2, 4);
+
+        if (hours.length === 1 && hours > "2") {
+            hours = "0" + hours;
+        } else if (hours.length === 2 && parseInt(hours, 10) > 23) {
+            hours = "23";
+        }
+
+        if (minutes.length === 2 && parseInt(minutes, 10) > 59) {
+            minutes = "59";
+        }
+
+        this.value = hours + (minutes ? ':' + minutes : '');
+    });
+ */
+    function lineClick(profile, timeline, lineNumber, idclass) {
+        var currentClass = $('#' + idclass + '_' + timeline + '_' + lineNumber).attr('class');
+        if (currentClass.includes('LineRed')) {
+            $('#' + idclass + '_' + timeline + '_' + lineNumber).removeClass('LineRed').addClass('LineGreen');
+            var hiddenInput = document.getElementById(idclass + '_' + timeline);
+            var arr = JSON.parse(hiddenInput.value);
+            arr[lineNumber - 1] = 0;
+            hiddenInput.value = arr;
+            console.log("New value of hidden input:", arr);
+        }
+        if (currentClass.includes('LineGreen')) {
+            $('#' + idclass + '_' + timeline + '_' + lineNumber).removeClass('LineGreen').addClass('LineRed');
+            var hiddenInput = document.getElementById(idclass + '_' + timeline);
+            var arr = JSON.parse(hiddenInput.value);
+            arr[lineNumber - 1] = 1;
+            hiddenInput.value = JSON.stringify(arr);
+            console.log("New value of hidden input:", arr);
+        }
+    }
+
+    function lineFullClick(profile, timeline, lineNumber, idclass) {
+        for (i = 1; i < lineNumber; i++) {
+            var currentClass = $('#' + idclass + '_' + timeline + '_' + i).attr('class');
+            if (currentClass.includes('LineRed')) {
+                $('#' + idclass + '_' + timeline + '_' + i).removeClass('LineRed').addClass('LineGreen');
+                var hiddenInput = document.getElementById(idclass + '_' + timeline);
+                var arr = JSON.parse(hiddenInput.value);
+                arr[i - 1] = 0;
+                hiddenInput.value = JSON.stringify(arr);
+            }
+            if (currentClass.includes('LineGreen')) {
+                $('#' + idclass + '_' + timeline + '_' + i).removeClass('LineGreen').addClass('LineRed');
+                var hiddenInput = document.getElementById(idclass + '_' + timeline);
+                var arr = JSON.parse(hiddenInput.value);
+                arr[i - 1] = 1;
+                hiddenInput.value = JSON.stringify(arr);
+            }
+        }
+    }
+</script>
+<script>
+    function setDefault() {
+        var fullUrl = window.location.origin;
+        window.location.href = fullUrl + "/custom/booking/reservation.php";
+    }
+
+    function adjustTime(inputId, action) {
+        var input = document.getElementById(inputId);
+        var currentTime = input.value || "06:00"; // Alapértelmezett idő, ha nincs megadva
+        var parts = currentTime.split(':');
+        var hours = parseInt(parts[0], 10);
+        var minutes = parseInt(parts[1], 10);
+
+        // Növelés vagy csökkentés 30 perccel
+        if (action === 'increase') {
+            minutes += 30;
+        } else if (action === 'decrease') {
+            minutes -= 30;
+        }
+
+        // Kezelés a túlcsordulásokra
+        if (minutes >= 60) {
+            hours += 1;
+            minutes = minutes % 60;
+        } else if (minutes < 0) {
+            hours -= 1;
+            minutes = 60 + minutes;
+        }
+
+        if (hours >= 24) {
+            hours = 0;
+        } else if (hours < 0) {
+            hours = 23;
+        }
+
+        // Formázás, hogy mindig kétjegyű legyen az óra és perc
+        var formattedTime = ("0" + hours).slice(-2) + ":" + ("0" + minutes).slice(-2);
+        input.value = formattedTime;
+
+        var from = document.getElementById("time1");
+        var to = document.getElementById("time2");
+        var selectedProfileVal = $("#profile").find("option:selected").val();
+
+        var xhrIntervalChange = new XMLHttpRequest();
+        xhrIntervalChange.open("POST", "reservation_intervalchange.php", true);
+        xhrIntervalChange.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
+
+        xhrIntervalChange.send("from=" + encodeURIComponent(from.value) + "&to=" + encodeURIComponent(to.value) + "&profile=" + selectedProfileVal);
+
+        xhrIntervalChange.onload = function() {
+            if (xhrIntervalChange.status === 200) {
+                const profileTypeDiv = document.querySelector('.profileTypeClass');
+                profileTypeDiv.innerHTML = xhrIntervalChange.responseText;
+            } else {
+                alert("Request failed");
+            }
+        };
+        //document.getElementById('reservatonForm').submit();
+    }
+
+    function validatePage() {
+        var selectfac = document.getElementById("facilitie");
+        var selectarea = document.getElementById("area");
+        var selectprof = document.getElementById("profile");
+        var selectdaterange = document.getElementById("date-range");
+
+        if ((!selectfac || selectfac.value == -1) ||
+            (!selectarea || selectarea.value == -1) ||
+            (!selectprof || selectprof.value == -1) ||
+            (!selectdaterange || selectdaterange.value == '')) {
+
+            if (!selectfac || selectfac.value == -1) {
+                $("#request_facilitie").removeClass("displayNone").addClass("displayBlock");
+            } else {
+                $("#request_facilitie").addClass("displayNone");
+            }
+
+            if (!selectarea || selectarea.value == -1) {
+                $("#request_area").removeClass("displayNone").addClass("displayBlock");
+            } else {
+                $("#request_area").addClass("displayNone");
+            }
+
+            if (!selectdaterange || selectdaterange.value == '') {
+                console.log('date-range: ' + (selectdaterange ? selectdaterange.value : 'N/A'));
+                $("#request_date").removeClass("displayNone").addClass("displayBlock");
+            } else {
+                $("#request_date").addClass("displayNone");
+            }
+
+            if (!selectprof || selectprof.value == -1) {
+                $("#request_profile").removeClass("displayNone").addClass("displayBlock");
+            } else {
+                $("#request_profile").addClass("displayNone");
+            }
+
+            return false;
+
+        } else {
+            $("#request_facilitie").addClass("displayNone");
+            $("#request_area").addClass("displayNone");
+            $("#request_date").addClass("displayNone");
+            $("#request_profile").addClass("displayNone");
+            alert('Mentve');
+        }
+
+    }
+
+
+    var facilitiesSelect = $("#facilitie");
+    var areaSelect = $("#area");
+    var profileSelect = $("#profile");
+    var daterangeInput = $("#date-range");
+    facilitiesSelect.select2();
+    areaSelect.select2();
+    profileSelect.select2();
+    facilitiesSelect.on("change", function(e) {
+        var selectedFacilityValue = $(this).val();
+        var selectedFacilityText = $(this).find("option:selected").text();
+        if (selectedFacilityValue == -1) {
+            $("#date-range, #time1, #time2").val("");
+            $("#time1, #time2, #area, #date-range, #profile").prop("disabled", true);
+            var fullUrl = window.location.origin;
+            window.location.href = fullUrl + "/custom/booking/reservation.php";
+        } else {
+            var xhr = new XMLHttpRequest();
+            xhr.open("POST", "reservation_area.php", true);
+            xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
+
+            // Kérés elküldése
+            xhr.send("facilitie=" + encodeURIComponent(selectedFacilityValue) /* + "&email=" + encodeURIComponent('valami2')*/ );
+
+            // Válasz kezelése
+            xhr.onload = function() {
+                if (xhr.status === 200) {
+                    $("#area").prop("disabled", false);
+                    $(".areaClass").removeClass("displayNone").addClass("displayBlock");
+                    const areaDiv = document.querySelector('.areaClass');
+                    areaDiv.innerHTML = xhr.responseText;
+                    var areaSelect = $("#area");
+                    areaSelect.on("change", function(e) {
+                        var selectedAreaVal = $(this).find("option:selected").val();
+                        if (selectedAreaVal == -1) {
+                            $("#time1, #time2").val("").prop("disabled", true);
+                            $(".profilesClass, .profileClass, .timerClass, .dateClass")
+                                .removeClass("displayBlock")
+                                .addClass("displayNone");
+                        } else {
+                            var xhrArea = new XMLHttpRequest();
+                            xhrArea.open("POST", "reservation_profile.php", true);
+                            xhrArea.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
+
+                            xhrArea.send("area=" + encodeURIComponent(selectedAreaVal));
+
+                            xhrArea.onload = function() {
+                                if (xhrArea.status === 200) {
+                                    $(".dateClass").removeClass("displayNone").addClass("displayBlock");
+                                    $("#profile").prop("disabled", false);
+                                    $(".profileClass").removeClass("displayNone").addClass("displayBlock");
+                                    const profileDiv = document.querySelector('.profileClass');
+                                    profileDiv.innerHTML = xhrArea.responseText;
+                                    var profileSelect = $("#profile");
+                                    profileSelect.on("change", function(e) {
+                                        $(".timerClass").removeClass("displayNone").addClass("displayBlock");
+                                        var selectedProfileVal = $(this).find("option:selected").val();
+                                        if (selectedProfileVal == -1) {
+                                            $("#time1, #time2").val("").prop("disabled", true);
+                                            $(".profilesClass").removeClass("displayBlock").addClass("displayNone");
+                                        } else {
+                                            $("#time1").val("06:00");
+                                            $("#time2").val("22:00");
+                                            var selectedProfileText = $(this).find("option:selected").text();
+                                            var xhrProfile = new XMLHttpRequest();
+                                            xhrProfile.open("POST", "reservation_profile_type.php", true);
+                                            xhrProfile.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
+
+                                            xhrProfile.send("profile=" + encodeURIComponent(selectedProfileVal));
+
+                                            xhrProfile.onload = function() {
+                                                if (xhrProfile.status === 200) {
+                                                    const profileTypeDiv = document.querySelector('.profileTypeClass');
+                                                    profileTypeDiv.innerHTML = xhrProfile.responseText;
+                                                } else {
+                                                    alert("Request failed");
+                                                }
+                                            };
+                                        }
+                                    });
+                                } else {
+                                    alert("Request failed");
+                                }
+                            };
+                        }
+                    });
+                } else {
+                    alert("Request failed");
+                }
+            };
+        }
+    });
+    daterangeInput.on("change", function(e) {
+        $("#request_date").removeClass("displayBlock").addClass("displayNone");
+    })
+</script>

+ 29 - 0
custom/booking/reservation_api_reservation.class.php

@@ -0,0 +1,29 @@
+<?php
+
+/**
+ * API class for Reservation
+ *
+ * @access protected
+ * @class  DolibarrApiAccess {@requires user,external}
+ */
+class ApiReservation extends DolibarrApi
+{
+
+    /**
+	 * Report
+	 * 
+	 * @param  int $facility_id	Facility Id
+	 * @param  int $area_id	Area Id
+	 * @param  int $areaLanes Lanes of the area
+	 * 
+	 *
+	 * @return array|mixed Data without useless information
+	 *
+	 * @url POST CreateReport
+	 */
+    public function CreateReport($facility_id, $area_id, $areaLanes)
+	{
+        $array = [];
+		return $array;
+	}
+}

+ 59 - 0
custom/booking/reservation_api_tickets.class.php

@@ -0,0 +1,59 @@
+<?php
+
+/**
+ * API class for Tickets
+ *
+ * @access protected
+ * @class  DolibarrApiAccess {@requires user,external}
+ */
+class ApiTickets extends DolibarrApi
+{
+
+    /**
+	 * TicketPurchase
+	 * 
+	 * @param  int $product_id	Product Id
+	 * 
+	 *
+	 * @return array|mixed Data without useless information
+	 *
+	 * @url POST TicketPurchase
+	 */
+    public function TicketPurchase($product_id)
+	{
+        $array = [];
+		return $array;
+	}
+
+    /**
+	 * Invoice/Receipt resending 
+	 * 
+	 * @param  int $facture_id	Faacture Id
+	 * 
+	 *
+	 * @return array|mixed Data without useless information
+	 *
+	 * @url POST TicketPurchase
+	 */
+    public function FactureResending($facture_id)
+	{
+        $array = [];
+		return $array;
+	}
+
+    /**
+	 * Ticket validation
+	 * 
+	 * @param  int $code	Facture ref and timestamp
+	 * 
+	 *
+	 * @return array|mixed Data without useless information
+	 *
+	 * @url POST ValidateTicket
+	 */
+    public function ValidateTicket($code)
+	{
+        $array = [];
+		return 'OK';
+	}
+}

+ 10 - 0
custom/booking/reservation_area.php

@@ -0,0 +1,10 @@
+<?php
+require_once 'reservation.class.php';
+$reservation = new Reservation();
+$facilitie = $_POST['facilitie'];
+$areas = [
+    "1" => ["1" => "Medence_1", "2" => "Medence_2", "3" => "Focipálya"],
+    "2" => ["1" => "Medence_1", "2" => "Medence_2"],
+    "3" => ["1" => "Medence_1", "2" => "Focipálya"]
+];
+print $reservation->generateSelectorInput('area', $areas[$facilitie], $area);

+ 16 - 0
custom/booking/reservation_intervalchange.php

@@ -0,0 +1,16 @@
+<?php
+require_once 'reservation.class.php';
+$reservation = new Reservation();
+$time1Value = $_POST['from'];
+$time2Value = $_POST['to'];
+$profile = $_POST['profile'];
+
+$profiles = [
+    "1" => ["id" => 1, "idclass" => "SwimmingPoolLine", "name" => "SwimmingPool", "lines" => "6", "type" => 'H', "frameName" => "SwimmingPoolTitle"],
+    "2" => ["id" => 2, "idclass" => "PoolLine", "name" => "Pool", "lines" => "4", "type" => 'V', "frameName" => "PoolTitle"],
+    "3" => ["id" => 3, "idclass" => "PoloLine", "name" => "Polo", "lines" => "3", "type" => 'V', "frameName" => "PoloTitle"]
+];
+
+
+print $reservation->selectedProfileWithTimes($profiles[$profile], [$time1Value, $time2Value]);
+

+ 22 - 0
custom/booking/reservation_profile.php

@@ -0,0 +1,22 @@
+<?php
+require_once 'reservation.class.php';
+$reservation = new Reservation();
+$area = $_POST['area'];
+$profiles = [
+    "1" => [
+        "1" => ["id" => 1, "idclass" => "SwimmingPoolLine", "name" => "SwimmingPool", "lines" => "6", "type" => 'H', "frameName" => "SwimmingPoolTitle"],
+        "2" => ["id" => 2, "idclass" => "PoolLine", "name" => "Pool", "lines" => "4", "type" => 'V', "frameName" => "PoolTitle"],
+        "3" => ["id" => 3, "idclass" => "PoloLine", "name" => "Polo", "lines" => "3", "type" => 'V', "frameName" => "PoloTitle"]
+    ],
+    "2" => [
+        "1" => ["id" => 1, "idclass" => "SwimmingPoolLine", "name" => "SwimmingPool", "lines" => "6", "type" => 'H', "frameName" => "SwimmingPoolTitle"],
+        "2" => ["id" => 2, "idclass" => "PoolLine", "name" => "Pool", "lines" => "4", "type" => 'V', "frameName" => "PoolTitle"],
+        "3" => ["id" => 3, "idclass" => "PoloLine", "name" => "Polo", "lines" => "3", "type" => 'V', "frameName" => "PoloTitle"]
+    ],
+    "3" => [
+        "1" => ["id" => 1, "idclass" => "SwimmingPoolLine", "name" => "SwimmingPool", "lines" => "6", "type" => 'H', "frameName" => "SwimmingPoolTitle"],
+        "2" => ["id" => 2, "idclass" => "PoolLine", "name" => "Pool", "lines" => "4", "type" => 'V', "frameName" => "PoolTitle"],
+        "3" => ["id" => 3, "idclass" => "PoloLine", "name" => "Polo", "lines" => "3", "type" => 'V', "frameName" => "PoloTitle"]
+    ],
+];
+print $reservation->generateSelectorInputForProfiles('profile', $profiles[$area], $profile);

+ 14 - 0
custom/booking/reservation_profile_type.php

@@ -0,0 +1,14 @@
+<?php
+require_once 'reservation.class.php';
+$reservation = new Reservation();
+$profile = $_POST['profile'];
+$profiles = [
+    "1" => ["id" => 1, "idclass" => "SwimmingPoolLine", "name" => "SwimmingPool", "lines" => "6", "type" => 'H', "frameName" => "SwimmingPoolTitle"],
+    "2" => ["id" => 2, "idclass" => "PoolLine", "name" => "Pool", "lines" => "4", "type" => 'V', "frameName" => "PoolTitle"],
+    "3" => ["id" => 3, "idclass" => "PoloLine", "name" => "Polo", "lines" => "3", "type" => 'V', "frameName" => "PoloTitle"]
+];
+$time1Value = $time1 == '' ? '06:00' : $time1;
+$time2Value = $time2 == '' ? '22:00' : $time2;
+
+//print $reservation->generateJavascript( $profiles[$profile], [$time1Value, $time2Value]);
+print $reservation->selectedProfileWithTimes($profiles[$profile], [$time1Value, $time2Value]);

+ 7 - 0
custom/booking/reservation_profile_view.php

@@ -0,0 +1,7 @@
+<?php
+/* $script = $reservation->generateJavaScriptFirstSection($profiles);
+foreach ($profiles as $profile) {
+    print $reservation->selectedProfileWithTimes($profile, [$time1Value, $time2Value]);
+    $script .= $reservation->generateJavascript($profiles, $profile, [$time1Value, $time2Value]);
+}
+$script .= $reservation->generateJavaScriptLastSection($profiles); */

BIN
custom/financialreport/monthlyexport_Luna_Tours_18-10-24-2298700.xlsx


BIN
custom/financialreport/monthlyexport_Luna_Tours_18-10-24-5623960.xlsx


BIN
custom/financialreport/monthlyexport_Luna_Tours_18-10-24-7973750.xlsx