Parcourir la source

cross-shopping fixes

Szollosi.Laszlo il y a 1 an
Parent
commit
4a4c6fa0e7

Fichier diff supprimé car celui-ci est trop grand
+ 479 - 469
custom/bbus/class/api_bbus.class.php


+ 2178 - 0
custom/bbus/class/api_bbus.class_old.php

@@ -0,0 +1,2178 @@
+<?php
+/* Copyright (C) 2015   Jean-François Ferry     <jfefe@aternatik.fr>
+* Copyright (C) 2019   Cedric Ancelin          <icedo.anc@gmail.com>
+*
+* 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.
+*
+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/>.
+*/
+
+use Luracast\Restler\RestException;
+use Sabre\Xml\Element;
+
+
+require_once DOL_DOCUMENT_ROOT . '/product/class/product.class.php';
+require_once DOL_DOCUMENT_ROOT . '/product/stock/class/productlot.class.php';
+require_once DOL_DOCUMENT_ROOT . '/fourn/class/fournisseur.product.class.php';
+require_once DOL_DOCUMENT_ROOT . '/categories/class/categorie.class.php';
+require_once DOL_DOCUMENT_ROOT . '/variants/class/ProductAttribute.class.php';
+require_once DOL_DOCUMENT_ROOT . '/variants/class/ProductAttributeValue.class.php';
+require_once DOL_DOCUMENT_ROOT . '/variants/class/ProductCombination.class.php';
+require_once DOL_DOCUMENT_ROOT . '/variants/class/ProductCombination2ValuePair.class.php';
+require_once DOL_DOCUMENT_ROOT . '/custom/bbus/class/sellproduct.class.php';
+require_once DOL_DOCUMENT_ROOT . '/custom/bbus/class/apiuserhandler.class.php';
+require_once DOL_DOCUMENT_ROOT . '/compta/facture/class/facture.class.php';
+
+require_once DOL_DOCUMENT_ROOT . '/custom/bbus/class/jegy.class.php';
+require_once DOL_DOCUMENT_ROOT . '/custom/bbus/class/bbloginlog.class.php';
+require_once DOL_DOCUMENT_ROOT . '/custom/bbus/class/bbexchangerate.class.php';
+
+require_once DOL_DOCUMENT_ROOT . '/custom/bbus/class/bbticket.class.php';
+require_once DOL_DOCUMENT_ROOT . '/custom/bbus/class/bbdevices.class.php';
+require_once DOL_DOCUMENT_ROOT . '/custom/bbus/class/bbdevicesservicelocation.class.php';
+require_once DOL_DOCUMENT_ROOT . '/custom/bbus/class/bbdevicesservicelocationproduct.class.php';
+require_once DOL_DOCUMENT_ROOT . '/custom/bbus/class/bbticketinvoiceprinting.class.php';
+require_once DOL_DOCUMENT_ROOT . '/custom/bbus/utils/globalconst.class.php';
+require_once DOL_DOCUMENT_ROOT . '/custom/bbus/utils/emailtemplatehandler.php';
+include_once DOL_DOCUMENT_ROOT . '/core/class/CMailFile.class.php';
+require_once DOL_DOCUMENT_ROOT . '/custom/bbus/class/bbticketnaplo.class.php';
+require_once DOL_DOCUMENT_ROOT . '/custom/bbus/class/bbtickethandler.class.php';
+require_once DOL_DOCUMENT_ROOT . '/custom/bbus/class/gpsposition.class.php';
+require_once DOL_DOCUMENT_ROOT . '/custom/bbus/class/userloginnaplo.class.php';
+require_once DOL_DOCUMENT_ROOT . '/custom/bbus/utils/countryhandler.class.php';
+require_once DOL_DOCUMENT_ROOT . '/custom/bbus/utils/entityhandler.class.php';
+require_once DOL_DOCUMENT_ROOT . '/custom/bbus/class/discountnaplo.class.php';
+require_once DOL_DOCUMENT_ROOT . '/custom/settlements/class/groupusers.class.php';
+require_once DOL_DOCUMENT_ROOT . '/custom/rollerstorage/class/packagehistory.class.php';
+require_once DOL_DOCUMENT_ROOT . '/product/inventory/class/inventory.class.php';
+require_once DOL_DOCUMENT_ROOT . '/custom/bbus/class/apiproductlisthelper.class.php';
+require_once DOL_DOCUMENT_ROOT . '/custom/bbus/class/apiinvoicehelper.class.php';
+require_once DOL_DOCUMENT_ROOT . '/custom/bbus/class/ticket_checker.class.php';
+require_once DOL_DOCUMENT_ROOT . '/custom/bbus/class/api_bbus_helper.class.php';
+require_once DOL_DOCUMENT_ROOT . '/custom/bbus/class/api_bbus_log.class.php';
+require_once DOL_DOCUMENT_ROOT . '/custom/bbus/class/bbapilock.class.php';
+require_once DOL_DOCUMENT_ROOT . '/custom/bbus/class/exchangerateupdater.class.php';
+require_once DOL_DOCUMENT_ROOT . '/custom/bbus/class/bbticketvalidationcoords.class.php';
+require_once DOL_DOCUMENT_ROOT . '/custom/bbus/class/api_curl.class.php';
+
+
+
+/**
+ * API class for products
+ *
+ * @access protected
+ * @class  DolibarrApiAccess {@requires user,external}
+ */
+class BBus extends DolibarrApi
+{
+
+	use CurlApi;
+
+	private $code;
+	private $printingTime;
+	private $status = 0;
+	private $device_id;
+	private $service_location_id;
+	private $bbTicketRowId;
+	private $facture_id;
+	private $isValid = true;
+	private User $user;
+
+
+	const EMAIL_TEMPLATE = 'multiticketprinting';
+	const GLOBAL_CONF_SEND_TO_EMAIL = 'BBUS_INVOICE_PRINTING_ALERT_EMAIL';
+	const GLOBAL_CONF_EMAIL_FROM = 'BBUS_INVOICE_PRINTING_ALERT_EMAIL_FROM';
+
+	public function __construct()
+	{
+		global $db, $conf, $user;
+
+		$this->db = $db;
+		$this->user = $user;
+	}
+
+
+	#-------------------------------------------------
+	#	Vásárlási folyamat
+	#-------------------------------------------------
+
+	/**
+	 * Get app config
+	 *
+	 * Return an array with config params.
+	 *
+	 * @return array|mixed Data without useless information
+	 *
+	 * @url GET config
+	 *
+	 * @throws RestException 401
+	 * @throws RestException 403
+	 * @throws RestException 404
+	 */
+	public function config(): array
+	{
+		global $user, $conf;
+		$helper = new ApiBBusHelper();
+		// company
+		$companyData = $helper->getCompany();
+
+		$config = [
+			'exchange_rate' => ExchangeRateUpdater::getExchangeRate(ExchangeRateUpdater::EUR, $conf->entity),
+			'invoice' => [
+				'header' => [
+					'name' => $companyData['company_data']['NOM'],
+					'tax_number' => $companyData['company_data']['TVAINTRA'],
+					'address' => [
+						'zip' => $companyData['company_data']['ZIP'],
+						'city' => $companyData['company_data']['TOWN'],
+						'address' => $companyData['company_data']['ADDRESS']
+					]
+				],
+				'customer' => $helper->getAppCustomers(),
+				'vat_percent' => 27,
+				'entity' => $user->entity,
+				'account_id' => $helper->getAccountRowid($user->entity),
+				'currencies' => $helper->getCurrenciesRowid($user->entity),
+				'payments_mode' => $helper->getPaymentsMode($user->entity)
+			]
+		];
+		ApiBbusLog::appLog("User: {$user->firstname} {$user->lastname} (ID: {$user->id})");
+		ApiBbusLog::appLog(json_encode([
+			'config' => $config
+		]));
+
+
+
+		return $config;
+	}
+
+	/**
+	 * Check user and eventdetail type permissions
+	 *
+	 * Return a result.
+	 *
+	 * @return array|mixed Data without useless information
+	 *
+	 * @url GET checkPermission
+	 */
+	public function checkPermission()
+	{
+		global $user, $db;
+		$permissionArray = [];
+		$groupUsersObj = new GroupUsers($db);
+		$result = $groupUsersObj->fetchAll('desc', 'rowid', 1, 0, ["customsql" => "fk_user = {$user->id}"]);
+		if ($result == -1 || empty($result)) {
+			return $permissionArray;
+		}
+		dol_include_once('/eventwizard/class/eventdetails.class.php');
+		$sqlBasicService = "SELECT pe.basic_service FROM llx_product as p
+			INNER JOIN llx_product_extrafields as pe ON pe.fk_object = p.rowid
+			GROUP BY pe.basic_service";
+		$resultBasicServices = $db->query($sqlBasicService);
+		if ($db->num_rows($resultBasicServices) > 0) {
+			while ($row = $db->fetch_object($resultBasicServices)) {
+				$basicServices[] = $row->basic_service;
+			}
+		}
+		$sqlBasicServicesTable = "SELECT basic_service_id, ref FROM llx_bbus_basicServices ORDER BY basic_service_id ASC";
+		$resultBasicServicesObj = $db->query($sqlBasicServicesTable);
+		if ($db->num_rows($resultBasicServicesObj) > 0) {
+			while ($bsrow = $db->fetch_object($resultBasicServicesObj)) {
+				foreach ($basicServices as $item) {
+					if ($bsrow->basic_service_id == $item && $item != 2) {
+						$permissionArray[$item] = $bsrow->ref;
+					}
+				}
+			}
+		}
+		return $permissionArray;
+	}
+
+	/**
+	 * Products list with children
+	 *
+	 * @param  string $sortfield  			Sort field
+	 * @param  string $sortorder  			Sort order
+	 * @param  int    $limit      			Limit for list
+	 * @param  int    $page       			Page number
+	 * @param  int    $mode       			Use this param to filter list (0 for all, 1 for only product, 2 for only service)
+	 * @param  int    $category   			Use this param to filter list by category
+	 * @param  string $sqlfilters 			Other criteria to filter answers separated by a comma. Syntax example "(t.tobuy:=:0) and (t.tosell:=:1)"
+	 * @param  bool   $ids_only   			Return only IDs of product instead of all properties (faster, above all if list is long)
+	 * @param  int    $variant_filter   		Use this param to filter list (0 = all, 1=products without variants, 2=parent of variants, 3=variants only)
+	 * @param  bool   $pagination_data   	If this parameter is set to true the response will include pagination data. Default value is false. Page starts from 0
+	 * @param  int    $includestockdata		Load also information about stock (slower)
+	 * @return array                			Array of product objects
+	 *
+	 * @url GET /products
+	 *
+	 * @throws RestException 401
+	 * @throws RestException 403
+	 * @throws RestException 404
+	 */
+	public function products($sortfield = 't.ref', $sortorder = 'ASC', $limit = 100, $page = 0, $mode = 0, $category = 0, $sqlfilters = '', $ids_only = false, $variant_filter = 0, $pagination_data = false, $includestockdata = 0): array
+	{
+		if (!DolibarrApiAccess::$user->rights->produit->lire) {
+			throw new RestException(403);
+		}
+		//$sqlfilters .= " AND ef.basic_service < '3'";
+		return (new ApiProductListHelper)->list($sortfield, $sortorder, $limit, $page, $mode, $category, $sqlfilters, $ids_only, $variant_filter, $pagination_data, $includestockdata);
+	}
+
+	/**
+	 * Create invoice
+	 * 
+	 * @param  array 	$invoice			Invoice data
+	 * @param  array 	$lines				Invoice lines
+	 * @param  array 	$payment			Invoice payment
+	 * @param  string 	$cardPaymentLog		Card payment log data
+	 * 
+	 * @return array|mixed Data without useless information
+	 * 
+	 * @url POST /invoice
+	 */
+	public function invoice(array $invoice, array $lines, array $payment, string $cardPaymentLog = '', string $sendId = '')
+	{
+		global $user;
+		$lockLabel = 'CREATE_INVOICE';
+		if (empty($sendId)) {
+			$sendId = substr(md5(rand()), 0, 8);
+		}
+		/**
+		 * LOG SECTION
+		 */
+		ApiBbusLog::appLog("{$sendId} === NEW INVOICE ===");
+		dol_syslog("{$sendId} === NEW INVOICE ===", LOG_INFO, 0);
+		ApiBbusLog::appLog("{$sendId} REQUEST: {$sendId}");
+		dol_syslog("{$sendId} REQUEST: {$sendId}", LOG_INFO, 0);
+		ApiBbusLog::appLog("{$sendId} User: {$user->firstname} {$user->lastname} (ID: {$user->id})");
+		dol_syslog("{$sendId} User: {$user->firstname} {$user->lastname} (ID: {$user->id})", LOG_INFO, 0);
+		ApiBbusLog::appLog("{$sendId} " . json_encode([
+			'invoice' => $invoice,
+			//'lines' => $lines,
+			'payment' => $payment,
+			'cardPaymentLog' => $cardPaymentLog
+		]));
+
+		/**
+		 * CHECK RIGHTS
+		 */
+		if (!DolibarrApiAccess::$user->rights->facture->creer) {
+			ApiBbusLog::appLog("{$sendId} Insufficient rights");
+			throw new RestException(401, 'Insufficient rights');
+		}
+
+
+		$apiInvoiceHelper = new ApiInvoiceHelper;
+		/**
+		 * handle invoice basic data
+		 */
+		$invoiceObj = $apiInvoiceHelper->createInvoice($invoice, $sendId);
+		/**
+		 * handle invoice line(s)
+		 */
+		$products = [];
+
+		foreach ($lines as $line) {
+			$invoiceObj = $apiInvoiceHelper->addLineToInvoice($invoiceObj, $line, $sendId);
+
+			$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->total_ttc;
+					$row['price'] = $line->multicurrency_total_ttc;
+					$row['total_tva'] = $line->total_tva;
+					//$row['total_tva'] = $line->multicurrency_total_tva;
+				}
+			}
+		}
+
+		/**
+		 * validate
+		 */
+		$invoiceObj = $apiInvoiceHelper->validateInvoice($invoiceObj, $sendId);
+		/**
+		 * set payment
+		 */
+		$apiInvoiceHelper->setPayment($invoiceObj, $payment, $sendId);
+		/**
+		 * save card payment data
+		 */
+		if (!empty($cardPaymentLog)) {
+			$invoiceObj = $apiInvoiceHelper->saveCardPaymentLog($invoiceObj, $cardPaymentLog, $sendId);
+		}
+
+		ApiBbusLog::appLog("{$sendId} Invoice created. ID: {$invoiceObj->id} REF: {$invoiceObj->ref} REQ: {$sendId}");
+		dol_syslog("{$sendId} Invoice created. ID: {$invoiceObj->id} REF: {$invoiceObj->ref} REQ: {$sendId}", LOG_INFO, 0);
+		//$bbApiLock->delete($user);
+
+		ApiBbusLog::appLog("{$sendId}####################################################################");
+		dol_syslog("{$sendId}####################################################################", LOG_INFO, 0);
+
+		return [
+			'sendId' => $sendId,
+			'invoice' => [
+				'id' => $invoiceObj->id,
+				'ref' => $invoiceObj->ref,
+				'total' => $invoiceObj->multicurrency_total_ttc
+			],
+			'products' => $products,
+		];
+	}
+
+	/**
+	 * Post invoice ref and creation date for data recording
+	 *
+	 * Return an array with success information.
+	 *
+	 * @param  string $ref	Facture ref
+	 * @param  string $datetime	invoice creation date
+	 * @param  string $type_id	type_id
+	 *
+	 * @return array|mixed Data without useless information
+	 *
+	 * @url POST printdate
+	 *
+	 * @throws RestException 401
+	 * @throws RestException 403
+	 * @throws RestException 404
+	 */
+	public function dateHandler(string $ref, string $datetime, string $type_id = null)
+	{
+		global $user;
+		$helper = new ApiBBusHelper();
+
+
+		if (!DolibarrApiAccess::$user->rights->produit->lire) {
+			ApiBbusLog::appLog("!DolibarrApiAccess::user->rights->produit->lire");
+			throw new RestException(403);
+		}
+		if (empty($ref)) {
+			ApiBbusLog::appLog("Empty ref!");
+			throw new RestException(401, 'Empty ref!');
+		}
+		if (empty($datetime)) {
+			ApiBbusLog::appLog("Empty datetime!");
+			throw new RestException(401, 'Empty datetime!');
+		}
+
+		ApiBbusLog::appLog("=== dateHandler ===");
+		ApiBbusLog::appLog("Facture: {$ref}");
+		
+		$printDate = DateTime::createFromFormat('Y-m-d H:i:s', $datetime);
+		ApiBbusLog::appLog("User: {$user->firstname} {$user->lastname} (ID: {$user->id})");
+		$now = new DateTime('now');
+		$now = (clone $now)->modify('+2 minutes');
+		$validDate = (clone $now)->modify('-5 minutes');
+		$datetime = $printDate->format('Y-m-d H:i:s');
+		$datetime_timestamp = strtotime($datetime);
+
+		if ($validDate <= $printDate && $printDate <= $now) {
+			$server_host = $this->getServerHost($type_id);
+			# Keresztvásárlás
+			if ($server_host == 'excelia') {
+				$this->localDateHandler($ref, $datetime, $datetime_timestamp, $now);
+			} else {
+				ApiBbusLog::appLog("dateHandler: cURL");
+				$this->curlDateHandler($ref, $datetime);
+			}
+		} else {
+			ApiBbusLog::appLog("dateHandler: Invalid date");
+			throw new RestException(401, 'Invalid date');
+		}
+		return 'OK';
+	}
+
+	private function localDateHandler($ref, $datetime, $datetime_timestamp, $now)
+	{
+		global $user;
+		$helper = new ApiBBusHelper();
+		$facture_id = $helper->getFactureIdForInvoicePrinting($ref);
+		if(empty($facture_id)){
+			ApiBbusLog::appLog("localDateHandler: facture_id because cross-shopping");
+			$printedCopies = $this->checkPrintedCopiesWithRef($ref);
+		}else{
+			$printedCopies = $this->checkPrintedCopies($facture_id);
+		}
+		// Leellenőrzöm, hogy a számla volt-e már nyomtatva
+		
+		ApiBbusLog::appLog("printedCopies: {$printedCopies}");
+
+
+		if ($printedCopies == 0) {
+			ApiBbusLog::appLog("printedCopies: no copies");
+			if(empty($facture_id)){
+				$bbTicketsByFacture = $this->getTicketsByInvoiceNumber($ref);
+			}else{
+				$bbTicketsByFacture = $this->getTicketsByFactureId($facture_id);
+			}
+			foreach ($bbTicketsByFacture as $ticket) {
+				// Rogzitem a bbticketinvoiceprinting tablaba a rekordot
+				$helper->setPrintingInvoiceObject($user, $facture_id, $datetime, $datetime_timestamp, $ticket, $ref);
+			}
+		} else {
+			if(empty($facture_id)){
+				$ticketIds = $helper->getTicketIdsForCrossShopping($ref);
+			}else{
+				$ticketIds = $helper->getTicketIdsByFactureId($facture_id);
+			}
+			$ticketObj = new stdClass();
+			foreach ($ticketIds as $key => $value) {
+				// Rogzitem a bbticketinvoiceprinting tablaba a rekordot
+				$ticketObj->id = $key;
+				$ticketObj->ticket_id = $value;
+				$helper->setPrintingInvoiceObject($user, $facture_id, $datetime, $datetime_timestamp, $ticketObj, $ref);
+			}
+			// e-mail küldése
+			$helper->sendMail($facture_id, $datetime, $now->format('Y-m-d H:i:s'));
+			return 'Multiprinting';
+		}
+	}
+
+	private function getTicketsByFactureId($facture_id)
+	{
+		$bbticket = new BbTicket($this->db);
+		$bbTicketsByFacture = $bbticket->fetchAll('', '', 0, 0, ['customsql' => 'fk_facture = ' . intval($facture_id)]);
+		if ($bbTicketsByFacture < 1) {
+			throw new RestException(404, 'BBTicket not found');
+		}
+		return $bbTicketsByFacture;
+	}
+
+	private function getTicketsByInvoiceNumber($ref)
+	{
+		$bbticket = new BbTicket($this->db);
+		$bbTicketsByFacture = $bbticket->fetchAll('', '', 0, 0, ["customsql" => "invoice_number =  '" . $ref . "'"]);
+		if ($bbTicketsByFacture < 1) {
+			ApiBbusLog::appLog("getTicketsByInvoiceNumber: BBTicket not found");
+			throw new RestException(404, 'BBTicket not found');
+		}
+		ApiBbusLog::appLog("getTicketsByInvoiceNumber: I got it");
+		return $bbTicketsByFacture;
+	}
+
+	private function checkPrintedCopies($facture_id)
+	{
+		$bbticketinvoiceprinting = new BbTicketInvoicePrinting($this->db);
+		$copies = $bbticketinvoiceprinting->fetchAll('ASC', 'rowid', 0, 0, ['customsql' => 'fk_facture = ' . intval($facture_id)]);
+		return (is_array($copies)) ? count($copies) : 0;
+	}
+
+	private function checkPrintedCopiesWithRef($ref)
+	{
+		$bbticketinvoiceprinting = new BbTicketInvoicePrinting($this->db);
+		$copies = $bbticketinvoiceprinting->fetchAll('ASC', 'rowid', 0, 0, ["customsql" => "invoice_number = '" . $ref . "'"]);
+		return (is_array($copies)) ? count($copies) : 0;
+	}
+
+	private function curlDateHandler($ref, $datetime)
+	{
+		$params = compact('ref', 'datetime');
+		$datehandlerPostFields = json_encode($params);
+		ApiBbusLog::appLog("dateHandler: {$datehandlerPostFields}");
+		$this->curlRunner('bbus/printdate', $datehandlerPostFields, 'POST', true);
+	}
+
+	/**
+	 * Generate events	 
+	 *
+	 * @return array|mixed Data without useless information
+	 *
+	 * @url GET /getDatetime
+	 *
+	 * @throws RestException 401
+	 * @throws RestException 403
+	 * @throws RestException 404
+	 */
+	public function getDatetime()
+	{
+		$dateArray = [];
+		$now = dol_now();
+		$dateArray = ["timestamp" => $now, "date" => date("Y-m-d", $now), "datetime" => date("Y-m-d H:i:s", $now)];
+		return $dateArray;
+	}
+
+	#-------------------------------------------------
+	#	Egyéb
+	#-------------------------------------------------
+
+	/**
+	 * First ticket validation
+	 * 
+	 * @param  string $code
+	 * 
+	 * @return array|mixed Data without useless information
+	 * 
+	 * @url POST search
+	 */
+
+	public function search($code)
+	{
+		$this->checkUserReadPermission();
+		global $user;
+		$this->code = $code;
+		$this->facture_id = $this->getFactureRowIdByFactureId();
+
+		$sql = "SELECT bt.*, pr.ref as product_ref, pr.label as product_label, btp.printing_date, btp.printing_date_timestamp
+		FROM llx_bbus_bbticketinvoiceprinting as btp
+		INNER JOIN llx_bbus_bbticket AS bt ON bt.rowid = btp.ticket_id
+		INNER JOIN llx_product AS pr ON pr.rowid = bt.ticket_id
+		WHERE btp.fk_facture = {$this->facture_id}
+		  AND btp.printing_date = (
+			SELECT MIN(printing_date)
+			FROM llx_bbus_bbticketinvoiceprinting AS btp2
+			WHERE btp2.fk_facture = {$this->facture_id}
+		)";
+		$ticketsData = $this->db->query($sql);
+		while ($row = pg_fetch_assoc($ticketsData)) {
+			$now = date("Y-m-d H:i:s");
+			if ($row['usage'] == $row['usable_occasions'] && $row['usable_occasions'] != 0) {
+				$this->isValid = false;
+			}
+			if ($row['available_at'] < $now || ((!is_null($row['expire_at']) && !empty($row['expire_at'])) && $row['expire_at'] < $now)) {
+				$this->isValid = false;
+			}
+
+			$row['facture_ref'] = $code;
+			$row['isValid'] = $this->isValid;
+			$sub = [];
+			foreach ($row as $key => $value) {
+				$sub[$key] = $value;
+			}
+			$json[] = $sub;
+		}
+		return $json;
+	}
+
+	/**
+	 * Értékesítések
+	 * 
+	 * @param  date $date	Date
+	 * 
+	 *
+	 * @return array|mixed Data without useless information
+	 *
+	 * @url POST getsaleditems
+	 */
+	public function getsaleditems($date = null)
+	{
+		global $user;
+
+		if (!DolibarrApiAccess::$user->rights->produit->lire) {
+			throw new RestException(403);
+		}
+		//$date = isset($date) ? $date : date("Y-m-d");
+		$date = date("Y-m-d");
+
+		$apiBbusHelper = new ApiBBusHelper();
+		$facturesArray = $apiBbusHelper->getSaledItems($date);
+
+		return $apiBbusHelper->getSaledItemsArray($facturesArray);
+	}
+
+	/** LOG OK
+	 * Get properties of a product object by barcode
+	 *
+	 * Return an array with product information.
+	 *
+	 * @param  string $code	Facture ID and timestamp of printing
+	 *
+	 * @return array|mixed Data without useless information
+	 *
+	 * @url POST ticketinfos
+	 */
+	public function getinfos($code)
+	{
+		global $user;
+		$helper = new ApiBBusHelper();
+		ApiBbusLog::getinfosLog('=== NEW TICKETINFOS ===');
+		ApiBbusLog::getinfosLog("User: {$user->firstname} {$user->lastname} (ID: {$user->id})");
+		ApiBbusLog::getinfosLog("DOLAPIKEY: {$user->api_key}");
+		$ticketsFromBbticketinvoiceprinting = [];
+		$code_and_timstamp = explode('_', $code);
+		$this->code = $code_and_timstamp[0];
+		if (empty($this->code)) {
+			ApiBbusLog::getinfosLog('Code or mac is empty!');
+			ApiBbusLog::getinfosLog('=================');
+			throw new RestException(404, 'Code or mac is empty!');
+		}
+		$this->printingTime = $code_and_timstamp[1];
+		if (empty($this->printingTime)) {
+			ApiBbusLog::getinfosLog('Timestamp is empty!');
+			ApiBbusLog::getinfosLog('=================');
+			throw new RestException(404, 'Timestamp is empty!');
+		}
+		if (!DolibarrApiAccess::$user->rights->bbus->ticket->validation) {
+			ApiBbusLog::getinfosLog('No access: Ticket Validation!');
+			ApiBbusLog::getinfosLog('=================');
+			throw new RestException(403);
+		}
+		ApiBbusLog::getinfosLog("Code: {$this->code}");
+		ApiBbusLog::getinfosLog("Code: {$this->printingTime}");
+
+		//Kikeresem a facture_id-t
+		$facture = new Facture($this->db);
+		$sql = "SELECT * FROM " . $this->db->prefix() . $facture->table_element . " WHERE ref ILIKE '{$this->code}'";
+		$factureResult = $this->db->query($sql);
+		if (pg_num_rows($factureResult) < 1) {
+			ApiBbusLog::getinfosLog('Invoice not found!');
+			ApiBbusLog::getinfosLog('=================');
+			throw new RestException(404, 'Invoice not found!');
+		}
+		while ($row = pg_fetch_assoc($factureResult)) {
+			$selectedFacture_id = $row['rowid'];
+		}
+
+		ApiBbusLog::getinfosLog('Facture ID: ' . (string) $selectedFacture_id);
+
+
+		$sql = "SELECT rowid FROM " . $this->db->prefix() . $facture->table_element . " WHERE fk_facture_source = {$selectedFacture_id} AND type = 2";
+		$res = $this->db->query($sql);
+		if (pg_num_rows($res) > 0) {
+			ApiBbusLog::getinfosLog('Invoice has a Credit account!');
+			ApiBbusLog::getinfosLog('=================');
+			throw new RestException(404, 'Invoice has a Credit account.');
+		}
+
+		// Kikeresem az llx_bbus_bbticketinvoiceprinting táblából a timestamp-hez tartozo jegy Id(ka)t
+		$bbticketinvoiceprinting = new BbTicketInvoicePrinting($this->db);
+		$result = $bbticketinvoiceprinting->fetchAll('', '', 0, 0, ['customsql' => "printing_date_timestamp = '{$this->printingTime}' AND fk_facture = {$selectedFacture_id}"]);
+		$helper->checkResult($result, 'bbticketinvoiceprinting');
+		foreach ($result as $device) {
+			$ticketsFromBbticketinvoiceprinting[] = $device->ticket_id;
+		}
+		$inString = implode(', ', $ticketsFromBbticketinvoiceprinting);
+		//echo $inString;exit;
+		// A ticket_id alapjan, hogy a jegyek kozott szerepel-e es ervenyes-e
+		$bbticket = new BbTicket($this->db);
+		$sql = "SELECT tic.rowid as ticketrowid, tic.*, bbd.*, fac.* FROM " . $this->db->prefix() . $bbticket->table_element . " AS tic
+		INNER JOIN public.llx_product as bbd ON tic.ticket_id = bbd.rowid
+		INNER JOIN public.llx_facture as fac ON tic.fk_facture = fac.rowid
+		WHERE tic.rowid IN ({$inString})";
+		$statement = $this->db->query($sql);
+		while ($row = pg_fetch_assoc($statement)) {
+			$sub = [];
+			foreach ($row as $key => $value) {
+				$sub[$key] = $value;
+			}
+			$json[] = $sub;
+		}
+		ApiBbusLog::getinfosLog('Status: OK!');
+		ApiBbusLog::getinfosLog('=====================');
+		return $json;
+	}
+
+	/**
+	 * Get properties of a product object by barcode
+	 *
+	 * Return an array with product information.
+	 *
+	 *
+	 * @return array|mixed Data without useless information
+	 *
+	 * @url GET product
+	 */
+	public function getProducts()
+	{
+		global $user;
+		$productsArray = [];
+		$products = new Product($this->db);
+		$sql = "SELECT price, default_vat_code, rowid FROM " . $this->db->prefix() . $products->table_element . " WHERE fk_product_type = 1 ORDER BY rowid ASC";
+		$res = $this->db->query($sql);
+		while ($row = pg_fetch_assoc($res)) {
+			$productsArray[$row['rowid']] = $row;
+		}
+		return 'OK';
+	}
+
+	/** LOG OK
+	 * Validate a product bbticket id.
+	 *
+	 * Return an array with product validation data.
+	 *
+	 * @param  string $code	Facture ID and timestamp of printing
+	 * @param  string $ticketid	Ticketid (bbticket rowid)
+	 * @param  string $imei	IMEI (Mobile IMEI number)
+	 *
+	 * @return array|mixed Data without useless information
+	 *
+	 * @url POST ticketvalidationbyphone
+	 */
+	public function validateTicket($code, $ticketid, $imei)
+	{
+		global $user;
+		$logId = ApiBbusLog::getLogId();
+		ApiBbusLog::ticketvalidationByPhone("{$logId} === NEW TICKETVALIDATION BY PHONE ===");
+		ApiBbusLog::ticketvalidationByPhone("{$logId} User: {$user->firstname} {$user->lastname} (ID: {$user->id})");
+		ApiBbusLog::ticketvalidationByPhone("{$logId} DOLAPIKEY: {$user->api_key}");
+		ApiBbusLog::ticketvalidationByPhone("{$logId} code: {$code}");
+		$ticketChecker = new TicketChecker();
+
+
+		$ticketChecker->setCode($code);
+		$ticketChecker->setTimestamp($code, 'ticketvalidationByPhone', $logId);
+		$ticketChecker->SetTicketidFromPhone($ticketid, $logId);
+		$ticketChecker->setImei($imei, $logId);
+
+		$this->checkUserValidatePermission();
+
+		$ticketChecker->setFactureId('ticketvalidationByPhone', $logId);
+		$ticketChecker->checkBbTicketInvoicePrinting();
+		$selectedTicket = $ticketChecker->getDataOfTheSelectedTicket();
+
+		$ticketChecker->setBbTicketRowId($selectedTicket->id);
+
+		$ticketChecker->checkExceptionHandlers($selectedTicket, 'ticketvalidationByPhone', $logId);
+
+		$ticketChecker->setMergedTickets($selectedTicket, 'ticketvalidationByPhone', $logId);
+
+		$ticketChecker->saveData($selectedTicket);
+		ApiBbusLog::ticketvalidationByPhone("{$logId} Status: OK!");
+		ApiBbusLog::ticketvalidationByPhone("{$logId} =================");
+		return 'OK';
+	}
+
+	/** LOG OK
+	 * Get properties of a product object by barcode
+	 *
+	 * Return an array with product information.
+	 *
+	 * @param  string $code	Facture ID and timestamp of printing
+	 * @param  string $mac	MAC adress of the device
+	 *
+	 * @return array|mixed Data without useless information
+	 *
+	 * @url POST barcode
+	 *
+	 * @throws RestException 401
+	 * @throws RestException 403
+	 * @throws RestException 404
+	 */
+
+	public function getByBarcode(string $code, string $mac, string $lat = null, string $lon = null)
+	{
+		global $user;
+		$logId = ApiBbusLog::getLogId();
+		ApiBbusLog::getByBarcode("{$logId} === NEW OBU validation ===");
+		ApiBbusLog::getByBarcode("{$logId} User: {$user->firstname} {$user->lastname} (ID: {$user->id})");
+		ApiBbusLog::getByBarcode("{$logId} DOLAPIKEY: {$user->api_key}");
+		$bbticket = new BbTicket($this->db);
+		$ticketChecker = new TicketChecker();
+
+		if (empty($code) || empty($mac)) {
+			ApiBbusLog::getByBarcode("{$logId} Code or mac is empty!");
+			throw new RestException(404, 'Code or mac is empty!');
+		}
+
+		ApiBbusLog::getByBarcode("{$logId} Code: " . $code);
+		ApiBbusLog::getByBarcode("{$logId} MAC: " . $mac);
+		ApiBbusLog::getByBarcode("{$logId} Latitude: " . $lat);
+		ApiBbusLog::getByBarcode("{$logId} Longitude: " . $lon);
+		$ticketChecker->setMac($mac);
+		$ticketChecker->setCode($code);
+		$ticketChecker->setLat($lat);
+		$ticketChecker->setLon($lon);
+		$ticketChecker->setTimestamp($code, 'getByBarcode', $logId);
+
+		$this->checkUserReadPermission();
+
+		$ticketChecker->setFactureId('getByBarcode', $logId);
+		$ticketChecker->setFilsArray();
+
+		$ticketChecker->setTicketId($logId);
+		$selectedTicket = $ticketChecker->getDataOfTheSelectedTicket();
+
+		$ticketChecker->setBbTicketRowId($selectedTicket->id);
+		$ticketChecker->check5Minutes($logId);
+		$ticketChecker->checkExceptionHandlers($selectedTicket, 'getByBarcode', $logId);
+
+		$ticketChecker->setMergedTickets($selectedTicket, 'getByBarcode', $logId);
+		$ticketChecker->saveCoordinates($logId);
+		$ticketChecker->saveData($selectedTicket);
+
+		ApiBbusLog::getByBarcode("{$logId} Status: OK!");
+		ApiBbusLog::getByBarcode("{$logId} =================");
+		return 'OK';
+	}
+
+	/**
+	 * Save customer data (zip or countrycode) in facture table
+	 *
+	 * Return a result.
+	 *
+	 * @param  string $facture_id	Facture rowid
+	 * @param  string $customerdatazip	Customer data ZIP
+	 * @param  string $customerdatacountrycode	Customer data Countrycode
+	 *
+	 * @return array|mixed Data without useless information
+	 *
+	 * @url POST customerDataHandler
+	 *
+	 * @throws RestException 401
+	 * @throws RestException 403
+	 * @throws RestException 404
+	 */
+	public function customerDataHandler(string $facture_id, string $customerdatazip = null, string $customerdatacountrycode = null)
+	{
+		$helper = new ApiBBusHelper();
+		if (is_null($customerdatazip) && is_null($customerdatacountrycode)) {
+			dol_syslog("Nem sikerult a facture updateje. Ref: " . $this->facture_id, LOG_DEBUG | LOG_INFO | LOG_WARNING | LOG_ERR);
+			throw new RestException(404, 'Empty params');
+		}
+		$sql = "UPDATE " . $this->db->prefix() . "facture_extrafields SET ";
+		$sql .= !is_null($customerdatazip) ? "customer_data_zip = '{$customerdatazip}' " : "customer_data_countrycode = '{$customerdatacountrycode}' ";
+		$sql .= "WHERE fk_object = '{$facture_id}'";
+		$helper->factureUpdate($sql, $facture_id);
+		return "OK";
+	}
+
+	/**
+	 * Create naplo for userlogout
+	 *
+	 * Return a result.
+	 *
+	 * @return array|mixed Data without useless information
+	 *
+	 * @url POST logoutNaploCreator
+	 *
+	 * @throws RestException 401
+	 * @throws RestException 403
+	 * @throws RestException 404
+	 */
+	public function logoutNaploCreator()
+	{
+		global $user, $db;
+		$error = 0;
+		$db->begin();
+		$helper = new ApiBBusHelper();
+
+		$group_user_id = $helper->getGroupUserIdByUserId($user->id);
+		if ($group_user_id == -1) {
+			$error++;
+		}
+		$result = $helper->isLastStatusLogout($user);
+		if ($result !== '') {
+			return date('Y-m-d H:i:s', $result);
+		}
+
+		$userLoginNaplo = new UserLoginNaplo($db);
+		$userLoginNaplo->login_logout_status = 1;
+		$userLoginNaplo->user_id = $user->id;
+		$result = $userLoginNaplo->create($user);
+		if ($result < 0) {
+			$error++;
+		}
+
+		$userNaploObj = new UserNaplo($db);
+		$userNaploObj->user_id = $user->id;
+		$userNaploObj->group_user_id = $group_user_id;
+		$userNaploObj->status = 0;
+		$result = $userNaploObj->create($user);
+		if ($result < 0) {
+			$error++;
+		}
+
+		$groupUsersObj = new GroupUsers($db);
+		$sql = "SELECT rowid FROM " . MAIN_DB_PREFIX . "settlements_groupusers WHERE fk_user = {$user->id}";
+		$data = $db->query($sql);
+		$dataArray = pg_fetch_assoc($data);
+		$selectedGroupId = $dataArray['rowid'];
+		if (isset($selectedGroupId)) {
+			$resultKickOff = $groupUsersObj->deleteLine($user, $selectedGroupId);
+			if (!$resultKickOff) {
+				$error++;
+			}
+		}
+
+		if ($error) {
+			$db->rollback();
+		}
+		$db->commit();
+		return 'OK';
+	}
+
+	/**
+	 * Get the discount unit From Product
+	 *
+	 * Return a result.
+	 *
+	 * @param  int $product_id			Product rowid
+	 * 
+	 * @return string discount unit
+	 *
+	 * @url POST getDiscountUnit
+	 *
+	 * @throws RestException 401
+	 * @throws RestException 403
+	 * @throws RestException 404
+	 */
+	public function getDiscountUnit(int $product_id)
+	{
+		global $db, $user;
+		$ProductObj = new Product($db);
+		$ProductObj->fetch($product_id);
+		return $ProductObj->array_options['discount_period'];
+	}
+
+	/**
+	 * Create naplo for Discount
+	 *
+	 * Return a result.
+	 *
+	 * @param  int $facture_id			Facture rowid
+	 * @param  int $product_id			Product rowid
+	 * @param  int $discount			Discount
+	 * @param  string $discount_unit	Discount unit
+	 * 
+	 * @return array|mixed Data without useless information
+	 *
+	 * @url POST createDiscountNaplo
+	 *
+	 * @throws RestException 401
+	 * @throws RestException 403
+	 * @throws RestException 404
+	 */
+	public function createDiscountNaplo(int $facture_id, int $product_id, int $discount, string $discount_unit)
+	{
+		global $db, $user;
+		$discountNaploObj = new DiscountNaplo($db);
+		$discountNaploObj->fk_facture = $facture_id;
+		$discountNaploObj->fk_product = $product_id;
+		$discountNaploObj->discount = $discount;
+		$discountNaploObj->discount_unit = $discount_unit;
+		$result = $discountNaploObj->create($user);
+		if ($result < 0) {
+			return false;
+		}
+		return $result;
+	}
+
+	/**
+	 * Get the products from Product
+	 *
+	 * Return a result.
+	 *
+	 * @param  int $entity	entity
+	 * 
+	 * @return array|mixed Data without useless information
+	 *
+	 * @url POST getHotelSalesProducts
+	 *
+	 * @throws RestException 401
+	 * @throws RestException 403
+	 * @throws RestException 404
+	 */
+	public function getHotelSalesProducts(int $entity)
+	{
+		global $db, $user;
+		$sql = "SELECT p.* FROM public.llx_product AS p 
+		INNER JOIN public.llx_product_extrafields as pe ON pe.fk_object = p.rowid
+		WHERE p.entity = {$entity} AND pe.hotelsales = 1";
+		$products = $this->db->query($sql);
+		$row = pg_fetch_all($products);
+		return $row;
+	}
+
+	private function checkUserReadPermission()
+	{
+		if (!DolibarrApiAccess::$user->rights->produit->lire) {
+			throw new RestException(403);
+		}
+	}
+
+	private function checkUserValidatePermission()
+	{
+		if (!DolibarrApiAccess::$user->rights->bbus->ticket->validation) {
+			throw new RestException(403);
+		}
+	}
+
+	private function getFactureRowIdByFactureId()
+	{
+		$facture = new Facture($this->db);
+		$sqlFacture = "SELECT rowid FROM public.llx_facture WHERE ref ILIKE '%{$this->code}%'";
+		$result = $this->db->query($sqlFacture);
+		if (pg_num_rows($result) > 0) {
+			while ($adatok = pg_fetch_assoc($result)) {
+				$factureRowid = $adatok['rowid'];
+			}
+		} else {
+			throw new RestException(404, 'Invoice not found.');
+		}
+		$sql = "SELECT rowid FROM llx_facture WHERE fk_facture_source = {$factureRowid} AND type = 2";
+		$res = $this->db->query($sql);
+		if (pg_num_rows($res) > 0) {
+			throw new RestException(404, 'Invoice has a Credit account.');
+		}
+
+		return $factureRowid;
+	}
+
+	private function saveBbTicketNaplo($user)
+	{
+		$bbTicketNaplo = new BbTicketNaplo($this->db);
+		$bbTicketNaplo->ticket_row_id = $this->bbTicketRowId;
+		$bbTicketNaplo->bbservicelocation_id = isset($this->service_location_id) ? $this->service_location_id : null;
+		$bbTicketNaplo->device_id = isset($this->device_id) ? $this->device_id : null;
+		$bbTicketNaplo->status = $this->status;
+
+
+		if ($bbTicketNaplo->create($user) < 0) {
+			dol_syslog('Nem sikerult menteni a bbticketNaplo tablaba a rekordot.', LOG_DEBUG | LOG_INFO | LOG_WARNING | LOG_ERR);
+			throw new RestException(500, 'Nem sikerult menteni a bbticketNaplo tablaba a rekordot.');
+		}
+	}
+
+	/**
+	 * @param  string $ref	Facture ref
+	 *
+	 * @return array|mixed Data without useless information
+	 *
+	 * @url POST getTicketsByFactureInvoiceNumber
+	 *
+	 * @throws RestException 401
+	 * @throws RestException 403
+	 * @throws RestException 404
+	 */
+	public function getTicketsByFactureInvoiceNumber($ref)
+	{
+		$bbTicketsByFacture = [];
+		$sql = "SELECT rowid as id, ticket_id FROM llx_bbus_bbticket WHERE invoice_number ILIKE '%{$ref}%'";
+		$result = $this->db->query($sql);
+		if ($this->db->num_rows($result) > 0) {
+			while ($row = $this->db->fetch_object($result)) {
+				$bbTicketsByFacture[] = $row;
+			}
+		} else {
+			throw new RestException(404, 'BBTicket not found');
+		}
+		return $bbTicketsByFacture;
+	}
+
+	/**
+	 * @param  string $facture_id	Facture ref
+	 *
+	 * @return array|mixed Data without useless information
+	 *
+	 * @url POST getRefFromFacture
+	 *
+	 * @throws RestException 401
+	 * @throws RestException 403
+	 * @throws RestException 404
+	 */
+	public function getRefFromFacture(string $facture_id)
+	{
+		global $user;
+		$facture = new Facture($this->db);
+		$sql = "SELECT ref FROM " . $this->db->prefix() . $facture->table_element . " WHERE rowid = " . $facture_id;
+		$res = $this->db->query($sql);
+		while ($adatok = pg_fetch_assoc($res)) {
+			print_r($adatok['ref']);
+			exit;
+		}
+
+		return 'OK';
+	}
+
+	/**
+	 * Get properties of a product object by barcode
+	 *
+	 * Return an array with product information.
+	 *
+	 * @param  string $barcode            Barcode of element
+	 * @param  int    $includestockdata   Load also information about stock (slower)
+	 * @param  bool   $includesubproducts Load information about subproducts
+	 * @param  bool   $includeparentid    Load also ID of parent product (if product is a variant of a parent product)
+	 * @param  bool   $includetrans		  Load also the translations of product label and description
+	 *
+	 * @return array|mixed Data without useless information
+	 *
+	 * @url GET profileimage/{id}
+	 *
+	 * @throws RestException 401
+	 * @throws RestException 403
+	 * @throws RestException 404
+	 */
+	public function getUserImage(int $id)
+	{
+		$image = null;
+		$dolApiKey = $_SERVER['HTTP_DOLAPIKEY'] ?? null;
+
+		if (empty($dolApiKey)) {
+			throw new RestException(401, 'Access not allowed');
+		}
+
+		$user = (new ApiUserHandler)->getUser($id, $dolApiKey);
+		if (empty($user->photo)) {
+			throw new RestException(404, 'Photo not found');
+		} else {
+			$originalFile = get_exdir(0, 0, 0, 0, $user, 'user') . 'photos/' . $user->photo;
+			$originalFile = DOL_DOCUMENT_ROOT . '/documents/users/' . $originalFile;
+
+			$filename = basename($originalFile);
+			$originalFileOsEncoded = dol_osencode($originalFile); // New file name encoded in OS encoding charset
+
+			$fileContent = file_get_contents($originalFileOsEncoded);
+			$image = [
+				'filename' => $filename,
+				'content-type' => dol_mimetype($filename),
+				'filesize' => filesize($originalFile),
+				'content' => base64_encode($fileContent),
+				'encoding' => 'base64'
+			];
+		}
+
+		return $image;
+	}
+
+	/**
+	 * Create invoices from the order
+	 *
+	 * @param int $id_order   		(Row)Id of the order
+	 * @param int $id_soc  			Id of 3th party
+	 * @return array                Response							  
+
+	 * @url POST invoicesFromOrder
+
+	 * @throws RestException 401
+	 * @throws RestException 403
+	 * @throws RestException 404
+	 */
+	public function invoicesFromOrder(int $id_order, int $id_soc = 0): array
+	{
+		// echo ini_get('memory_limit');
+		// exit;
+		if (!DolibarrApiAccess::$user->rights->facture->creer) {
+			throw new RestException(401, "Insuffisant rights");
+		}
+
+		require_once DOL_DOCUMENT_ROOT . '/compta/facture/class/facture.class.php';
+		// Standard or deposit invoice, not from a Predefined template invoice
+		// Si facture standard
+		$this->now = time();
+		$this->invoices = [];
+
+		$element == 'order';
+		$element = $subelement = 'commande';
+
+		//etalon obj:
+
+		$object = new Facture($this->db);
+		// $extrafields = new ExtraFields($db);
+		$defaultDevSocId = 1;
+		$this->defaultSocId = (isset($_ENV['DEFAULT_SOCID']) && (int) $_ENV['DEFAULT_SOCID']) ? (int) $_ENV['DEFAULT_SOCID'] : $defaultDevSocId;
+
+		$object->socid = (empty((int) $id_soc)) ? $this->defaultSocId : (int) $id_soc;
+		$object->type = null;
+		$object->ref = null;
+		$object->date = $this->now;
+		// $object->date_pointoftax 	= $date_pointoftax;
+		// $object->note_public		= trim(GETPOST('note_public', 'restricthtml'));
+		// $object->note_private = trim(GETPOST('note_private', 'restricthtml'));
+		// $object->ref_client			= GETPOST('ref_client');
+		$object->model_pdf = null;
+		// $object->fk_project			= GETPOST('projectid', 'int');
+		// $object->cond_reglement_id	= (GETPOST('type') == 3 ? 1 : GETPOST('cond_reglement_id'));
+		// $object->mode_reglement_id	= GETPOST('mode_reglement_id');
+		// $object->fk_account = GETPOST('fk_account', 'int');
+		// $object->amount = price2num(GETPOST('amount'));
+		// $object->remise_absolue		= price2num(GETPOST('remise_absolue'), 'MU');
+		// $object->remise_percent		= price2num(GETPOST('remise_percent'), '', 2);
+		// $object->fk_incoterms = GETPOST('incoterm_id', 'int');
+		// $object->location_incoterms = GETPOST('location_incoterms', 'alpha');
+		// $object->multicurrency_code = GETPOST('multicurrency_code', 'alpha');
+		// $object->multicurrency_tx   = GETPOST('originmulticurrency_tx', 'int');
+
+		$object->fetch_thirdparty();
+
+		// If creation from another object of another module (Example: origin=propal, originid=1)
+
+		$object->origin = $element;
+		$object->origin_id = $id_order;
+
+		// Possibility to add external linked objects with hooks
+		$object->linked_objects[$object->origin] = $object->origin_id;
+		// link with order if it is a shipping invoice
+
+		if (is_array($_POST['other_linked_objects']) && !empty($_POST['other_linked_objects'])) {
+			$object->linked_objects = array_merge($object->linked_objects, $_POST['other_linked_objects']);
+		}
+
+		//
+		dol_include_once('/' . $element . '/class/' . $subelement . '.class.php');
+		$classname = ucfirst($subelement);
+		$srcobject = new $classname($this->db);
+
+		$result = $srcobject->fetch($id_order);
+		if ($result > 0) {
+			$lines = $srcobject->lines;
+			if (empty($lines) && method_exists($srcobject, 'fetch_lines')) {
+				$srcobject->fetch_lines();
+				$lines = $srcobject->lines;
+			}
+			/*
+																																																													  // If we create a standard invoice with a percent, we change amount by changing the qty
+																																																													  if (is_array($lines)) {
+																																																													  foreach ($lines as $line) {
+																																																													  // We keep ->subprice and ->pa_ht, but we change the qty
+																																																													  $line->qty = price2num($line->qty * $valuestandardinvoice / 100, 'MS');
+																																																													  }
+																																																													  }
+																																																													  */
+			$fk_parent_line = 0;
+			$num = count($lines);
+			$invNum = 0;
+
+			for ($i = 0; $i < $num; $i++) {
+				// if (!in_array($lines[$i]->id, $selectedLines)) {
+				// continue; // Skip unselected lines
+				// }
+
+				//!!! create invoice by line:
+				$quantity = $lines[$i]->qty;
+				for ($j = 0; $j < $quantity; $j++) {
+					$this->invoices[$invNum] = clone $object;
+					if ($id = $this->invoices[$invNum]->create(DolibarrApiAccess::$user)) {
+						$this->invoices[$invNum]->update_price(1, 'auto', 0, $mysoc);
+
+						$label = (!empty($lines[$i]->label) ? $lines[$i]->label : '');
+						$desc = (!empty($lines[$i]->desc) ? $lines[$i]->desc : $lines[$i]->libelle);
+						if ($this->invoices[$invNum]->situation_counter == 1) {
+							$lines[$i]->situation_percent = 0;
+						}
+
+						if ($lines[$i]->subprice < 0 && empty($conf->global->INVOICE_KEEP_DISCOUNT_LINES_AS_IN_ORIGIN)) {
+							// Negative line, we create a discount line
+							require_once DOL_DOCUMENT_ROOT . '/core/class/discount.class.php';
+							$discount = new DiscountAbsolute($db);
+							$discount->fk_soc = $this->invoices[$invNum]->socid;
+							$discount->amount_ht = abs($lines[$i]->total_ht);
+							$discount->amount_tva = abs($lines[$i]->total_tva);
+							$discount->amount_ttc = abs($lines[$i]->total_ttc);
+							$discount->tva_tx = $lines[$i]->tva_tx;
+							$discount->fk_user = DolibarrApiAccess::$user->id;
+							$discount->description = $desc;
+							$discount->multicurrency_subprice = abs($lines[$i]->multicurrency_subprice);
+							$discount->multicurrency_amount_ht = abs($lines[$i]->multicurrency_total_ht);
+							$discount->multicurrency_amount_tva = abs($lines[$i]->multicurrency_total_tva);
+							$discount->multicurrency_amount_ttc = abs($lines[$i]->multicurrency_total_ttc);
+
+							$discountid = $discount->create(DolibarrApiAccess::$user);
+							if ($discountid > 0) {
+								$result = $this->invoices[$invNum]->insert_discount($discountid); // This include link_to_invoice
+							} else {
+								setEventMessages($discount->error, $discount->errors, 'errors');
+								$error++;
+								break;
+							}
+						} else {
+							// Positive line
+							$product_type = ($lines[$i]->product_type ? $lines[$i]->product_type : 0);
+
+							// Date start
+							$date_start = false;
+							if ($lines[$i]->date_debut_prevue) {
+								$date_start = $lines[$i]->date_debut_prevue;
+							}
+							if ($lines[$i]->date_debut_reel) {
+								$date_start = $lines[$i]->date_debut_reel;
+							}
+							if ($lines[$i]->date_start) {
+								$date_start = $lines[$i]->date_start;
+							}
+
+							// Date end
+							$date_end = false;
+							if ($lines[$i]->date_fin_prevue) {
+								$date_end = $lines[$i]->date_fin_prevue;
+							}
+							if ($lines[$i]->date_fin_reel) {
+								$date_end = $lines[$i]->date_fin_reel;
+							}
+							if ($lines[$i]->date_end) {
+								$date_end = $lines[$i]->date_end;
+							}
+
+							// Reset fk_parent_line for no child products and special product
+							if (($lines[$i]->product_type != 9 && empty($lines[$i]->fk_parent_line)) || $lines[$i]->product_type == 9) {
+								$fk_parent_line = 0;
+							}
+
+							// Extrafields
+							if (method_exists($lines[$i], 'fetch_optionals')) {
+								$lines[$i]->fetch_optionals();
+								$array_options = $lines[$i]->array_options;
+							}
+
+							$tva_tx = $lines[$i]->tva_tx;
+							if (!empty($lines[$i]->vat_src_code) && !preg_match('/\(/', $tva_tx)) {
+								$tva_tx .= ' (' . $lines[$i]->vat_src_code . ')';
+							}
+
+							// View third's localtaxes for NOW and do not use value from origin.
+							// TODO Is this really what we want ? Yes if source is template invoice but what if proposal or order ?
+							$localtax1_tx = get_localtax($tva_tx, 1, $this->invoices[$invNum]->thirdparty);
+							$localtax2_tx = get_localtax($tva_tx, 2, $this->invoices[$invNum]->thirdparty);
+
+							$result = $this->invoices[$invNum]->addline(
+								$desc,
+								$lines[$i]->subprice,
+								// $lines[$i]->qty,
+								1,
+								$tva_tx,
+								$localtax1_tx,
+								$localtax2_tx,
+								$lines[$i]->fk_product,
+								$lines[$i]->remise_percent,
+								$date_start,
+								$date_end,
+								0,
+								$lines[$i]->info_bits,
+								$lines[$i]->fk_remise_except,
+								'HT',
+								0,
+								$product_type,
+								$lines[$i]->rang,
+								$lines[$i]->special_code,
+								$this->invoices[$invNum]->origin,
+								$lines[$i]->rowid,
+								$fk_parent_line,
+								$lines[$i]->fk_fournprice,
+								$lines[$i]->pa_ht,
+								$label,
+								$array_options,
+								$lines[$i]->situation_percent,
+								$lines[$i]->fk_prev_id,
+								$lines[$i]->fk_unit,
+								0,
+								'',
+								1
+							);
+
+							if ($result > 0) {
+								$lineid = $result;
+							} else {
+								$lineid = 0;
+								$error++;
+								break;
+							}
+
+							// Defined the new fk_parent_line
+							if ($result > 0 && $lines[$i]->product_type == 9) {
+								$fk_parent_line = $result;
+							}
+						}
+					}
+
+					$invNum++;
+				}
+			}
+		} else {
+			setEventMessages($srcobject->error, $srcobject->errors, 'errors');
+			$error++;
+		}
+		$num = count($this->invoices);
+		$return = [
+			'validated' => []
+		];
+		// $used_mem = round(memory_get_usage(false) / 1024 / 1024); //mb
+		// $used_mem = round(memory_get_usage(true) / 1024 / 1024); //mb
+		// echo $used_mem. " / ".$allowed_mem; 
+		// echo ini_get('memory_limit');
+		// exit;
+
+		for ($i = 0; $i < $num; $i++) {
+
+			//!!! validation
+			// $idwarehouse = 0;
+			// $notrigger = 0;
+			// $result = $this->invoices[$i]->validate(DolibarrApiAccess::$user, '', $idwarehouse, $notrigger);
+			$id = $this->invoices[$i]->id;
+			$result = $this->invoices[$i]->validate(DolibarrApiAccess::$user, '', null);
+			if ($result >= 0) {
+				// Define output language
+				if (empty($conf->global->MAIN_DISABLE_PDF_AUTOUPDATE)) {
+					global $langs;
+					$outputlangs = $langs;
+					$newlang = '';
+					if (!empty($conf->global->MAIN_MULTILANGS) && empty($newlang) && GETPOST('lang_id', 'aZ09')) {
+						$newlang = GETPOST('lang_id', 'aZ09');
+					}
+					if (!empty($conf->global->MAIN_MULTILANGS) && empty($newlang)) {
+						$newlang = $this->invoices[$i]->thirdparty->default_lang;
+					}
+					if (!empty($newlang)) {
+						$outputlangs = new Translate("", $conf);
+						$outputlangs->setDefaultLang($newlang);
+						$outputlangs->load('products');
+					}
+					$model = $this->invoices[$i]->model_pdf;
+
+					$ret = $this->invoices[$i]->fetch($id); // Reload to get new records
+					// PDF
+					$hidedetails = (!empty($conf->global->MAIN_GENERATE_DOCUMENTS_HIDE_DETAILS)) ? 1 : 0;
+					$hidedesc = (!empty($conf->global->MAIN_GENERATE_DOCUMENTS_HIDE_DESC)) ? 1 : 0;
+					$hideref = (!empty($conf->global->MAIN_GENERATE_DOCUMENTS_HIDE_REF)) ? 1 : 0;
+					$result = $this->invoices[$i]->generateDocument($model, $outputlangs, $hidedetails, $hidedesc, $hideref);
+					if ($result < 0) {
+						//...
+						// setEventMessages($this->invoices[$i]->error, $this->invoices[$i]->errors, 'errors');
+					}
+				}
+			} else {
+				// if (count($this->invoices[$i]->errors)) {
+				// setEventMessages(null, $this->invoices[$i]->errors, 'errors');
+				// } else {
+				// setEventMessages($this->invoices[$i]->error, $this->invoices[$i]->errors, 'errors');
+				// }
+			}
+
+			// if ($result == 0) {
+			// throw new RestException(304, 'Error nothing done. May be object is already validated');
+			// }
+			// if ($result < 0) {
+			// throw new RestException(500, 'Error when validating Invoice: '.$this->invoice->error);
+			// }
+
+			// $this->invoices[$i] = $this->invoicees[$i]->fetch($id);
+			if (!$this->invoices[$i]) {
+				throw new RestException(404, 'Invoice not found');
+			}
+
+			$this->invoices[$i] = parent::_cleanObjectDatas($this->invoices[$i]);
+			unset($this->invoices[$i]->note);
+			unset($this->invoices[$i]->address);
+			unset($this->invoices[$i]->barcode_type);
+			unset($this->invoices[$i]->barcode_type_code);
+			unset($this->invoices[$i]->barcode_type_label);
+			unset($this->invoices[$i]->barcode_type_coder);
+			unset($this->invoices[$i]->canvas);
+
+
+			if (!DolibarrApi::_checkAccessToResource('facture', $id)) {
+				throw new RestException(401, 'Access not allowed for login ' . DolibarrApiAccess::$user->login);
+			}
+
+			$return['validated'][] = $this->invoices[$i]->ref;
+		}
+		return $return;
+	}
+
+	/**
+	 * Jegy generálás -> (order?->) invoice -> payment -> jegy -> qr on the bill
+	 *
+	 * Return an array with prcess information.
+	 *
+	 * @param  array $orderDetails			Order details
+	 *
+	 * @return array|mixed Data without useless information
+	 *
+	 * @url POST order
+	 *
+	 * @throws RestException 401
+	 * @throws RestException 403
+	 * @throws RestException 404
+	 */
+	public function jegy(array $orderDetails)
+	{
+		$return = [
+			"request" => $orderDetails
+		];
+		$Jegy = new Jegy();
+		$return['hash'] = [
+			$Jegy->generate_hash(),
+			$Jegy->generate_hash(1),
+			$Jegy->generate_hash(20),
+			$Jegy->generate_hash(50),
+			$Jegy->generate_hash(100),
+		];
+
+		return $return;
+	}
+
+	/**
+	 * Get groupId for REACT
+	 *
+	 * Return an ID.
+	 *
+	 * @return integer Data without useless information
+	 *
+	 * @url GET getGroupId
+	 *
+	 * @throws RestException 401
+	 * @throws RestException 403
+	 * @throws RestException 404
+	 */
+	public function getGroupId(): array
+	{
+		global $user, $db;
+		$sql = "SELECT fk_settlements_group FROM public.llx_settlements_groupusers WHERE fk_user = {$user->id} ORDER BY rowid DESC LIMIT 1";
+		$result = $db->query($sql);
+		while ($row = pg_fetch_assoc($result)) {
+			return $row;
+		}
+		return [];
+	}
+
+	/**
+	 * Insert a row into login log table
+	 *
+	 * @param  string $login		Login name
+	 *
+	 * @return array|mixed Data without useless information
+	 *
+	 * @url POST savelogin
+	 *
+	 * @throws RestException 404
+	 */
+	public function saveLogin(string $login)
+	{
+		$error = 0;
+		$this->db->begin();
+		$user = new User($this->db);
+		//$user->fetch(0, $login, 0, 0, 1);
+		$user->fetch(0, $login, 0, 0);
+		if (empty($user->id)) {
+			throw new RestException(404, 'User not found');
+		}
+
+		$log = new BbLoginLog($this->db);
+		$log->entity = 1;
+		$log->description = 'Login from App';
+		$id = $log->create($user);
+		if ($id < 1) {
+			$error++;
+			throw new RestException(500, 'Log failure');
+		}
+
+		$now = dol_now();
+
+		$userremoteip = getUserRemoteIP();
+
+		$sql = "UPDATE " . $this->db->prefix() . "user SET";
+		$sql .= " datepreviouslogin = datelastlogin,";
+		$sql .= " ippreviouslogin = iplastlogin,";
+		$sql .= " datelastlogin = '" . $this->db->idate($now) . "',";
+		$sql .= " iplastlogin = '" . $this->db->escape($userremoteip) . "',";
+		$sql .= " tms = tms"; // La date de derniere modif doit changer sauf pour la mise a jour de date de derniere connexion
+		$sql .= " WHERE rowid = " . ((int) $user->id);
+		$resql = $this->db->query($sql);
+		if (!$resql) {
+			$error++;
+			$this->error = $this->db->lasterror() . ' sql=' . $sql;
+		}
+		if (!$error) {
+			$this->db->commit();
+			return 'OK';
+		} else {
+			$this->db->rollback();
+		}
+	}
+
+	/**
+	 * Receive GPS coordinates of the device
+	 *
+	 * @param string  $licplate	License plate of the vehicle
+	 * @param string  $lat	GPS latitude coordinate
+	 * @param string  $lon	GPS longitude coordinate
+	 *
+	 * @return string|mixed Data without useless information
+	 *
+	 * @url GET /gps_coords
+	 *
+	 * @throws RestException 401
+	 * @throws RestException 403
+	 * @throws RestException 404
+	 * @throws RestException 500
+	 */
+	public function gpsCoords(string $licplate, string $lat, string $lon): string
+	{
+		if (!(new GpsPosition)->save($licplate, $lat, $lon)) {
+			throw new RestException(500, 'Save failure');
+		}
+
+		return 'OK';
+	}
+
+	/**
+	 * Receive GPS coordinates of the device
+	 *
+	 * @param string  $licplate	License plate of the vehicle
+	 * @param string  $lat	GPS latitude coordinate
+	 * @param string  $lon	GPS longitude coordinate
+	 *
+	 * @return string|mixed Data without useless information
+	 *
+	 * @url POST /gps_position
+	 *
+	 * @throws RestException 401
+	 * @throws RestException 403
+	 * @throws RestException 404
+	 * @throws RestException 500
+	 */
+	public function gpsPosition(string $licplate, string $lat, string $lon): string
+	{
+		if (!(new GpsPosition)->save($licplate, $lat, $lon)) {
+			throw new RestException(500, 'Save failure');
+		}
+
+		return 'OK';
+	}
+
+	/**
+	 * List of countries
+	 *
+	 * Return an array with country name and code.
+	 *
+	 * @param string $lang
+	 * @param string $search
+	 * 
+	 * @return array|mixed Data without useless information
+	 *
+	 * @url GET /countries
+	 *
+	 * @throws RestException 401
+	 * @throws RestException 403
+	 * @throws RestException 404
+	 */
+	public function countries(string $lang = 'hu', string $search = ''): array
+	{
+		return (new CountryHandler)->getCountries($lang, $search);
+	}
+
+	/**
+	 * List of entities
+	 *
+	 * Return an array with companies data.
+	 *
+	 * @return array|mixed Data without useless information
+	 *
+	 * @url GET /entities
+	 *
+	 * @throws RestException 401
+	 * @throws RestException 403
+	 * @throws RestException 404
+	 */
+	public function entities(): array
+	{
+		return (new EntityHandler)->getEntities();
+	}
+
+	/**
+	 * List of assets received
+	 *
+	 * Return an array with assets received.
+	 *
+	 * @return array|mixed Data without useless information
+	 *
+	 * @url GET /assets_received
+	 *
+	 * @throws RestException 401
+	 * @throws RestException 403
+	 * @throws RestException 404
+	 */
+	public function assetsReceived(): array
+	{
+		global $user, $db;
+
+		$packageHistory = new PackageHistory($db);
+		$inventoryObj = new Inventory($db);
+		$sql = "SELECT pt.device_id, i.ref, i.title, ie.unique_identifier, 
+		(SELECT ph.date_creation FROM " . $this->db->prefix() . $packageHistory->table_element . " as ph WHERE user_id = {$user->id} AND DATE(ph.date_creation) = CURRENT_DATE
+		ORDER BY ph.rowid DESC LIMIT 1) AS ph_date_creation
+		FROM llx_settlements_packagetool pt
+		INNER JOIN llx_inventory as i ON i.rowid = pt.device_id
+		INNER JOIN llx_inventory_extrafields as ie ON ie.fk_object = i.rowid
+		WHERE pt.package_id = (SELECT ph.package_id FROM public.llx_rollerstorage_packagehistory as ph WHERE user_id = {$user->id}
+		AND DATE(ph.date_creation) = CURRENT_DATE
+		ORDER BY ph.rowid DESC LIMIT 1)
+		ORDER BY pt.rowid DESC";
+		//print $sql;exit;
+		$result = $db->query($sql);
+		$changeSql = "SELECT ref, title FROM " . $this->db->prefix() . $inventoryObj->table_element . " WHERE ref ILIKE '%Change%'";
+		$resultCh = $db->query($changeSql);
+		if ($result > 0 && $resultCh > 0) {
+			while ($row = $db->fetch_object($result)) {
+				$row = (array) $row;
+				$date = $row['ph_date_creation'];
+				$device[] = [
+					"name" => isset($row['title']) ? $row['title'] : '',
+					"sku" => isset($row['unique_identifier']) ? $row['unique_identifier'] : ''
+				];
+			}
+			$change = [];
+			while ($rowCh = $db->fetch_object($resultCh)) {
+				$rowCh = (array) $rowCh;
+				$ChangeArray = explode('_', $rowCh['ref']);
+				$key = isset($ChangeArray[1]) ? strtolower($ChangeArray[1]) : '';
+				if (!empty($key)) {
+					$change[$key] = isset($rowCh['title']) ? $rowCh['title'] : '';
+				}
+			}
+		} else {
+			return [];
+		}
+
+		return [
+			'date' => $date,
+			'devices' => $device,
+			'change' => $change
+		];
+	}
+
+	/**
+	 * Save card payment log
+	 *
+	 * @param string $invoice_ref
+	 * @param string $data
+	 * 
+	 * @return array|mixed Data without useless information
+	 *
+	 * @url POST /cardpaymentlog
+	 *
+	 * @throws RestException 401
+	 * @throws RestException 403
+	 * @throws RestException 404
+	 */
+	public function cardPaymentLog(string $invoice_ref, string $data)
+	{
+		$result = 'OK';
+
+		$facture = new Facture($this->db);
+		if ($facture->fetch(0, $invoice_ref) > 0) {
+			$facture->array_options['options_payment_log'] = $data;
+			$facture->updateExtraField('payment_log');
+
+			$json = json_decode($data, true);
+			if (!empty($json['authorization_number'])) {
+				$sql = "
+					UPDATE " . MAIN_DB_PREFIX . "paiement 
+					SET num_paiement='" . $json['authorization_number'] . "' 
+					WHERE rowid=(
+						SELECT fk_paiement 
+						FROM " . MAIN_DB_PREFIX . "paiement_facture 
+						WHERE fk_facture={$facture->id}
+					)
+				";
+				$this->db->query($sql);
+			}
+		} else {
+			$result = 'Missing invoice';
+		}
+
+		return $result;
+	}
+
+	/**
+	 * Products list with children
+	 *
+	 * @param  string $sortfield  			Sort field
+	 * @param  string $sortorder  			Sort order
+	 * @param  int    $limit      			Limit for list
+	 * @param  int    $page       			Page number
+	 * @param  int    $mode       			Use this param to filter list (0 for all, 1 for only product, 2 for only service)
+	 * @param  int    $category   			Use this param to filter list by category
+	 * @param  string $sqlfilters 			Other criteria to filter answers separated by a comma. Syntax example "(t.tobuy:=:0) and (t.tosell:=:1)"
+	 * @param  bool   $ids_only   			Return only IDs of product instead of all properties (faster, above all if list is long)
+	 * @param  int    $variant_filter   		Use this param to filter list (0 = all, 1=products without variants, 2=parent of variants, 3=variants only)
+	 * @param  bool   $pagination_data   	If this parameter is set to true the response will include pagination data. Default value is false. Page starts from 0
+	 * @param  int    $includestockdata		Load also information about stock (slower)
+	 * @return array                			Array of product objects
+	 *
+	 * @url GET /productshotel
+	 *
+	 * @throws RestException 401
+	 * @throws RestException 403
+	 * @throws RestException 404
+	 */
+	public function productshotel($sortfield = 't.ref', $sortorder = 'ASC', $limit = 100, $page = 0, $mode = 0, $category = 0, $sqlfilters = '', $ids_only = false, $variant_filter = 0, $pagination_data = false, $includestockdata = 0): array
+	{
+		if (!DolibarrApiAccess::$user->rights->produit->lire) {
+			throw new RestException(403);
+		}
+
+		return (new ApiProductListHelper)->listhotel($sortfield, $sortorder, $limit, $page, $mode, $category, $sqlfilters, $ids_only, $variant_filter, $pagination_data, $includestockdata);
+	}
+
+	/**
+	 * Get the saled factures data by user
+	 * 
+	 * @param  string 	$date			Date
+	 * 
+	 * @return array|mixed Data without useless information
+	 * 
+	 * @url POST /saledfacturesbyuser
+	 */
+	function saledfacturesbyuser(string $date)
+	{
+		global $user, $db;
+		$date = date("Y-m-d", dol_now());
+		$fulldate = date("Y-m-d H:i:s", dol_now());
+		$apiBbusHelper = new ApiBBusHelper();
+		$from = $apiBbusHelper->getGroupLoginDate($date);
+		$to = $apiBbusHelper->getGroupLogout($date, $from);
+		$array = [];
+		if (strtotime($fulldate) > strtotime($to)) {
+			return $array;
+		}
+		$sql = "SELECT 
+		f.rowid as facture_rowid, 
+		f.ref AS facture_ref, 
+		f.datec, 
+		f.multicurrency_code, 
+		pa.libelle, 
+		pai.note AS transaction_id, 
+		fdet.fk_product AS product_id,  
+		pr.label AS product_label, 
+		pr.ref AS product_ref, 
+		pr.description, 
+		pass.fk_product_pere AS bundle_id, 
+		pr2.label AS bundle_label, 
+		pr2.ref AS bundle_ref, 
+		fdet.multicurrency_total_tva AS base_tva, 
+		fdet.multicurrency_total_ttc AS base_ttc, 
+		fdete.discount_percent, 
+		fdete.discount_hours, 
+		pr.default_vat_code, 
+		f.multicurrency_total_ttc AS bundle_ttc, 
+		(SELECT rate FROM llx_multicurrency_rate AS mc WHERE mc.fk_multicurrency = f.fk_multicurrency AND mc.entity = {$user->entity} ORDER BY mc.rowid DESC LIMIT 1) AS rate,
+		(SELECT date_start FROM llx_eventwizard_eventhistory AS evev WHERE evev.fk_facture = f.rowid) AS date_start
+				FROM llx_facture AS f
+				INNER JOIN llx_facture_extrafields AS fe ON fe.fk_object = f.rowid
+				INNER JOIN llx_c_paiement AS pa ON pa.id = f.fk_mode_reglement
+				INNER JOIN llx_paiement_facture AS pafa ON pafa.fk_facture = f.rowid
+				INNER JOIN llx_paiement AS pai ON pai.rowid = pafa.fk_paiement
+				INNER JOIN llx_facturedet AS fdet ON fdet.fk_facture = f.rowid
+				INNER JOIN llx_product AS pr ON pr.rowid = fdet.fk_product
+				left JOIN llx_product_association AS pass ON pass.fk_product_fils = pr.rowid
+				LEFT JOIN llx_product AS pr2 ON pr2.rowid = pass.fk_product_pere
+				LEFT JOIN llx_facturedet_extrafields AS fdete ON fdet.rowid = fdete.fk_object
+				WHERE f.datec BETWEEN '{$from}' AND '{$to}' 
+				AND f.fk_user_closing = $user->id
+				ORDER BY f.rowid DESC";
+		//print $sql;exit;
+		$data = $db->query($sql);
+		if ($db->num_rows($data > 0)) {
+
+			while ($row = $db->fetch_object($data)) {
+				$tmpArray = (array) $row;
+				if ($tmpArray['transaction_id'] != '') {
+					$jsonArray = json_decode($tmpArray['transaction_id']);
+					$row->transaction_id = $jsonArray->card_transaction_id;
+				}
+				$row->bundle_id = $row->bundle_id == '' ? $row->product_id : $row->bundle_id;
+				$row->bundle_label = $row->bundle_label == '' ? $row->product_label : $row->bundle_label;
+				$row->bundle_ref = $row->bundle_ref == '' ? $row->product_ref : $row->bundle_ref;
+				$array[$row->facture_rowid]['ref'] = $row->facture_ref;
+				$array[$row->facture_rowid]['bundle_name'] = $row->bundle_label;
+				$array[$row->facture_rowid]['currency'] = $row->multicurrency_code;
+				$array[$row->facture_rowid]['total_price'] = $row->bundle_ttc;
+				$array[$row->facture_rowid]['type'] = $row->libelle;
+				$array[$row->facture_rowid]['transaction_id'] = $row->transaction_id;
+				$array[$row->facture_rowid]['rate'] = $row->rate;
+				$array[$row->facture_rowid]['date'] = $row->datec;
+				$array[$row->facture_rowid]['lines'][$row->product_id] = (array) $row;
+			}
+			return $array;
+		} else {
+			return $array;
+		}
+	}
+
+	/**
+	 * List of assets received
+	 *
+	 * Return an array with assets received.
+	 *
+	 * @return array|mixed Data without useless information
+	 *
+	 * @url GET /getAllUsersOfTheGroup
+	 *
+	 * @throws RestException 401
+	 * @throws RestException 403
+	 * @throws RestException 404
+	 */
+	public function getAllUsersOfTheGroup(): array
+	{
+		global $user, $db;
+		$array = [];
+		$sql = "SELECT u.rowid, u.firstname, u.lastname, u.login, ue.nickname, u.email, u.office_phone, u.user_mobile, u.personal_mobile   FROM llx_settlements_groupusers AS gu
+		INNER JOIN llx_user_extrafields as ue ON ue.fk_object = gu.fk_user
+		INNER JOIN llx_user as u ON u.rowid = gu.fk_user
+		WHERE gu.fk_settlements_group = (SELECT gu2.fk_settlements_group FROM llx_settlements_groupusers as gu2 WHERE gu2.fk_user = {$user->id})";
+		$data = $db->query($sql);
+		while ($row = $db->fetch_object($data)) {
+			$array[] = [
+				'id' => $row->rowid,
+				'name' => $row->firstname . ' ' . $row->lastname,
+				'login' => $row->login,
+				'email' => $row->email,
+				'nickname' => $row->nickname ? $row->nickname : '',
+				'office_phone' => $row->office_phone,
+				'user_mobile' => $row->user_mobile,
+				'personal_mobile' => $row->personal_mobile
+			];
+		}
+		return $array;
+	}
+
+	#-------------------------------------------------
+	#	Event generator
+	#-------------------------------------------------
+
+	/**
+	 * Generate events	 
+	 *
+	 * @return array|mixed Data without useless information
+	 *
+	 * @url GET /genEvents
+	 *
+	 * @throws RestException 401
+	 * @throws RestException 403
+	 * @throws RestException 404
+	 */
+	public function genEvents()
+	{
+		$period = new DatePeriod(
+			new DateTime('2024-07-16'),
+			new DateInterval('P1D'),
+			new DateTime('2024-10-16')
+		);
+
+		$size = 30;
+		$buffer = 5;
+
+		$dates = [];
+
+		foreach ($period as $date) {
+			if (rand(0, 1)) {
+				$eventDate = $date->format('Y-m-d');
+				$eventTimes = array_rand(
+					array_flip([
+						'09:00',
+						'10:00',
+						'11:00',
+						'12:00',
+						'13:00',
+						'14:00',
+						'15:00',
+						'16:00',
+						'17:00',
+						'18:00',
+						'19:00',
+						'20:00'
+					]),
+					rand(1, 12)
+				);
+				/* 				print $eventDate;
+																													print "\r\n";
+																													print_r($eventTimes); */
+				if (is_array($eventTimes)) {
+					foreach ($eventTimes as $eventTime) {
+						$duration = rand(1, 3);
+						$dates[$eventDate][] = [
+							'start' => $eventTime,
+							'duration' => '0' . $duration . ':00:00',
+						];
+					}
+				}
+			}
+		}
+
+		//print_r($dates);exit;
+
+
+		$eventdetail_id = 1;
+		$dates = ['dates' => $dates, 'id_eventdetails' => $eventdetail_id];
+
+		dol_include_once('/eventwizard/class/eventdetails.class.php');
+
+		$object = new EventDetails($this->db);
+		$object->fetch($eventdetail_id);
+		$object->genEvents($dates, $eventdetail_id);
+
+		//print_r($dates);exit;
+
+		return [];
+	}
+
+	/**
+	 * Generate events	 
+	 *
+	 * @return array|mixed Data without useless information
+	 *
+	 * @url GET /updateeventextrafields
+	 *
+	 * @throws RestException 401
+	 * @throws RestException 403
+	 * @throws RestException 404
+	 */
+	public function updateEventsExtrafields()
+	{
+		$sql = "SELECT ac.id FROM llx_actioncomm as ac 
+		LEFT JOIN llx_actioncomm_extrafields as ace ON ace.fk_object = ac.id
+		WHERE ac.code = 'AC_EVENT'
+		AND ace.max_num IS NULL";
+		$result1 = $this->db->query($sql);
+		while ($row1 = $this->db->fetch_object($result1)) {
+			print_r($row1);
+			$participants = rand(1, 20);
+			$sql2 = "INSERT INTO llx_actioncomm_extrafields (fk_object, max_num, buffer, participants)
+			VALUES ({$row1->id}, 30, 5, $participants)";
+			$result = $this->db->query($sql2);
+		}
+	}
+
+	#-------------------------------------------------
+	#	Facture generator
+	#-------------------------------------------------
+
+	/**
+	 * Generate factures	 
+	 * 
+	 * @return array|mixed Data without useless information
+	 *
+	 * @url POST /generateFactures
+	 *
+	 * @throws RestException 401
+	 * @throws RestException 403
+	 * @throws RestException 404
+	 */
+	public function generateFactures()
+	{
+		$numberOfFactures = 1;
+
+		for ($i = 0; $i < $numberOfFactures; $i++) {
+			$currencyRand = rand(0, 1);
+			$currencyText = [0 => 'HUF', 1 => 'EUR'];
+			$currencyNumber = [0 => 3, 1 => 5];
+
+			$reglementRand = rand(14, 15);
+			//$reglementRand = rand(106, 107); ## STAGING
+			$mode_reglement_id = $reglementRand;
+			$paymentid = $reglementRand;
+			$accountid = [0 => 4, 1 => 5];
+
+			$deduction = rand(1, 5) == 3 ? 1 : null;
+			$storno = rand(1, 5) == 1 ? 1 : null;
+
+			$invoice = ["mode_reglement_id" => $mode_reglement_id, "array_options_app_facture" => 1, "array_options_commission_deduction" => $deduction, "array_options_marked_for_storno" => $storno, "multicurrency_code" => $currencyText[$currencyRand], "fk_multicurrency" => $currencyNumber[$currencyRand], "array_options_customer_data_zip" => null];
+			$linesHUFBundle = [
+				["desc" => "", "subprice" => "787.4015", "qty" => 1, "tva_tx" => "27.0", "localtax1_tx" => "0.000", "localtax2_tx" => "0.000", "fk_product" => "102", "remise_percent" => "0", "date_start" => "", "date_end" => "", "fk_code_ventilation" => 0, "info_bits" => "0", "fk_remise_except" => null, "product_type" => "1", "rang" => "-1", "special_code" => "0", "fk_parent_line" => null, "fk_fournprice" => null, "pa_ht" => "0.00000000", "label" => "", "array_options" => [], "situation_percent" => "100", "fk_prev_id" => null, "fk_unit" => null, "price_base_type" => "HT"],
+				["desc" => "", "subprice" => "13333.3333", "qty" => 1, "tva_tx" => "5.0", "localtax1_tx" => "0.000", "localtax2_tx" => "0.000", "fk_product" => "108", "remise_percent" => "0", "date_start" => "", "date_end" => "", "fk_code_ventilation" => 0, "info_bits" => "0", "fk_remise_except" => null, "product_type" => "1", "rang" => "-1", "special_code" => "0", "fk_parent_line" => null, "fk_fournprice" => null, "pa_ht" => "0.00000000", "label" => "", "array_options" => [], "situation_percent" => "100", "fk_prev_id" => null, "fk_unit" => null, "price_base_type" => "HT"]
+			];
+
+			$linesEURBundle = [
+				["desc" => "", "subprice" => "2.3622", "qty" => 1, "tva_tx" => "27.0", "localtax1_tx" => "0.000", "localtax2_tx" => "0.000", "fk_product" => "101", "remise_percent" => "0", "date_start" => "", "date_end" => "", "fk_code_ventilation" => 0, "info_bits" => "0", "fk_remise_except" => null, "product_type" => "1", "rang" => "-1", "special_code" => "0", "fk_parent_line" => null, "fk_fournprice" => null, "pa_ht" => "0.00000000", "label" => "", "array_options" => [], "situation_percent" => "100", "fk_prev_id" => null, "fk_unit" => null, "price_base_type" => "HT"],
+				["desc" => "", "subprice" => "33.3333", "qty" => 1, "tva_tx" => "5.0", "localtax1_tx" => "0.000", "localtax2_tx" => "0.000", "fk_product" => "107", "remise_percent" => "0", "date_start" => "", "date_end" => "", "fk_code_ventilation" => 0, "info_bits" => "0", "fk_remise_except" => null, "product_type" => "1", "rang" => "-1", "special_code" => "0", "fk_parent_line" => null, "fk_fournprice" => null, "pa_ht" => "0.00000000", "label" => "", "array_options" => [], "situation_percent" => "100", "fk_prev_id" => null, "fk_unit" => null, "price_base_type" => "HT"]
+			];
+
+			$linesEURSimple = [
+				["desc" => "", "subprice" => "12.5984", "qty" => 1, "tva_tx" => "27.0", "localtax1_tx" => "0.000", "localtax2_tx" => "0.000", "fk_product" => "132", "remise_percent" => "0", "date_start" => "", "date_end" => "", "fk_code_ventilation" => 0, "info_bits" => "0", "fk_remise_except" => null, "product_type" => "1", "rang" => "-1", "special_code" => "0", "fk_parent_line" => null, "fk_fournprice" => null, "pa_ht" => "0.00000000", "label" => "", "array_options" => [], "situation_percent" => "100", "fk_prev_id" => null, "fk_unit" => null, "price_base_type" => "HT"],
+			];
+
+			$linesArray = [
+				0 => $linesEURBundle,
+				1 => $linesEURSimple,
+				2 => $linesHUFBundle
+			];
+			if ($currencyRand == 1) {
+				$lineRand = rand(0, 1);
+				$lines = $linesArray[$lineRand];
+			} else {
+				$lines = $linesArray[2];
+			}
+
+			$payment = ["datepaye" => time(), "paymentid" => $paymentid, "closepaidinvoices" => "yes", "accountid" => $accountid[$currencyRand]];
+			$comment = "{\"timestamp\":\"1704241200\",\"merchant_id\":\"000000000014202\",\"acquirer_id\":\"88105000003\",\"operation_number\":\"000037\",\"termid\":\"36002058\",\"pan\":\"428312******1789\",\"exp\":\"****\",\"stan\":\"000007\",\"authorization_number\":\"282597\",\"trans_type\":\"CLI\",\"amount\":\"2.0\",\"cvm\":\"2\",\"billnumber\":\"AcTbHmcWsMGcF6Nf\",\"card_transaction_id\":\"AcTbHmcWsMGcF6Nf\"}";
+			$payment['comment'] = $reglementRand == 15 ? '' : $comment;
+			//$payment['comment'] = $reglementRand == 107 ? '' : $comment;  ## STAGING
+
+			$cardPaymentLog = "";
+
+			/*  			print_r($invoice);
+															print_r($lines);
+															print_r($payment);
+															exit; */
+
+			$invoiceNumber = $this->invoice($invoice, $lines, $payment, $cardPaymentLog, $sendId = '');
+			$ref = $invoiceNumber['invoice']['ref'];
+			$datetime = date("Y-m-d H:i:s", $payment['datepaye']);
+			$multiprint = rand(1, 5);
+			$this->dateHandler($ref, $datetime);
+			if ($multiprint == 2 || $multiprint == 3) {
+				$prints = rand(1, 5);
+				$dateofprint = $payment['datepaye'];
+				for ($i = 0; $i < $prints; $i++) {
+					$dateofprint = strtotime('+5 seconds', $dateofprint);
+					$datetime = date("Y-m-d H:i:s", $dateofprint);
+					$this->dateHandler($ref, $datetime);
+				}
+			}
+		}
+		return 'OK';
+	}
+
+	#-------------------------------------------------
+	#	CURL
+	#-------------------------------------------------
+
+	/**
+	 * Check Printed copies
+	 *
+	 * Return an array with details
+	 *
+	 * @return 	array|mixed data without useless information
+	 *
+	 * @param 	string 	$ref			//selected evet from llx_event
+	 * 
+	 * @url	POST curlCheckPrintedCopies
+	 * @throws RestException 401 Not allowed
+	 * @throws RestException 404 Not found
+	 */
+	public function curlCheckPrintedCopies(string $ref)
+	{
+		$bbticketinvoiceprinting = new BbTicketInvoicePrinting($this->db);
+		$copies = $bbticketinvoiceprinting->fetchAll('ASC', 'rowid', 0, 0, ["customsql" => "invoice_number ILIKE '%{$ref}%'"]);
+		return (is_array($copies)) ? count($copies) : 0;
+	}
+
+	/**
+	 * @param 	string 	$datetime
+	 * @param 	string 	$datetime_timestamp
+	 * @param 	array 	$ticket
+	 * @param 	string 	$ref
+	 * 
+	 * 
+	 * @return array|mixed Data without useless information
+	 *
+	 * @url POST curlSetPrintingInvoiceObject
+	 *
+	 * @throws RestException 401
+	 * @throws RestException 403
+	 * @throws RestException 404
+	 */
+	public function curlSetPrintingInvoiceObject(string $datetime, string $datetime_timestamp, array $ticket, string $ref)
+	{
+		global $user;
+		$helper = new ApiBBusHelper();
+		$helper->setPrintingInvoiceObject($user, null, $datetime, $datetime_timestamp, (object)$ticket, $ref);
+	}
+}

+ 3 - 2
custom/bbus/class/api_curl.class.php

@@ -10,11 +10,12 @@ trait CurlApi
 
 	private function curlInit($route, $postFields = '', $request = 'POST')
 	{
+		global $conf;
 		$curl = curl_init();
 
 		curl_setopt_array($curl, array(
 			//CURLOPT_URL => 'http://dolibarr-bbusdev-imap-cron-soap/api/index.php/' . $route,
-			CURLOPT_URL => 'http://bbusdevszollosil/api/index.php/' . $route,
+			CURLOPT_URL => $conf->global->CURL_ROUTE . $route,
 			CURLOPT_RETURNTRANSFER => true,
 			CURLOPT_VERBOSE => true,
 			CURLOPT_SSL_VERIFYPEER => false,
@@ -28,7 +29,7 @@ trait CurlApi
 			CURLOPT_USERAGENT => "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.0.3705; .NET CLR 1.1.4322)",
 			CURLOPT_POSTFIELDS => $postFields,
 			CURLOPT_HTTPHEADER => array(
-				'DOLAPIKEY: VXG0isGJwn0U2WJ17dkN27vV3blH64xr',
+				'DOLAPIKEY: ' . $conf->global->CURL_USER_DOLAPIKEY,
 				'Content-Type: application/json'
 			),
 		));

+ 20 - 0
custom/bbus/class/apiinvoicehelper.class.php

@@ -35,6 +35,7 @@ class ApiInvoiceHelper
 		$this->apiInvoice->loadData($invoice);
 		$this->apiInvoice->prepareData();
 		$this->apiInvoice->validate();
+		ApiBbusLog::appLog("{$sendId} - createInvoice_________END - " . microtime(true));
 		return $this->apiInvoice->create();
 	}
 
@@ -106,6 +107,20 @@ class ApiInvoiceHelper
 		return $lines;
 	}
 
+	function getProductLinesWithoutDiscount($product_id)
+	{
+		ApiBbusLog::appLog("getProductLinesWithoutDiscount: {$product_id}");
+
+		$productObj = new Product($this->db);
+		$result = $productObj->fetch($product_id);
+		$productObj->fk_product = $product_id;
+		$productObj->subprice = $productObj->price_ttc;
+		$productObj->qty = 1;
+		$productObj->array_options['options_discount_hours'] = null;
+		$productObj->array_options['options_discount_percent'] = null;
+		$lines[] = (array) $productObj;
+		return $lines;
+	}
 
 	/**
 	 * Validate invoice
@@ -395,15 +410,19 @@ class ApiInvoice implements ApiInvoiceData
 	 */
 	public function setPayment(Facture $invoice, array $data, string $sendId): int
 	{
+		ApiBbusLog::appLog("ApiinvoiceHelper: setPayment function");
+
 		global $db;
 
 		if (isModEnabled('banque')) {
 			if (empty($data['accountid'])) {
+				ApiBbusLog::appLog("ApiinvoiceHelper: setPayment accountid error");
 				throw new RestException(400, 'Account ID is mandatory');
 			}
 		}
 
 		if (empty($data['paymentid'])) {
+			ApiBbusLog::appLog("ApiinvoiceHelper: setPayment paymentid error");
 			throw new RestException(400, 'Payment ID or Payment Code is mandatory');
 		}
 
@@ -443,6 +462,7 @@ class ApiInvoice implements ApiInvoiceData
 		$paymentobj->note_private = (is_array($data['comment'])) ? json_encode($data['comment']) : $data['comment'];
 
 		$paymentId = $paymentobj->create(DolibarrApiAccess::$user, ($data['closepaidinvoices'] == 'yes' ? 1 : 0)); // This include closing invoices
+		ApiBbusLog::appLog("paymentId created");
 
 
 		if ($paymentId < 0) {

+ 2 - 0
custom/bbus/class/apiproductlisthelper.class.php

@@ -26,6 +26,8 @@ class ApiProductListHelper
      */
     public function list($sortfield = "t.ref", $sortorder = 'ASC', $limit = 100, $page = 0, $mode = 0, $category = 0, $sqlfilters = '', $ids_only = false, $variant_filter = 0, $pagination_data = false, $includestockdata = 0): array
     {
+		ApiBbusLog::eventLog("{$sqlfilters}");
+
         $obj_ret = array();
 
 		//$socid = DolibarrApiAccess::$user->socid ? DolibarrApiAccess::$user->socid : '';

+ 218 - 219
custom/bbus/core/triggers/interface_99_modBBus_BBusTriggers.class.php

@@ -101,13 +101,12 @@ class InterfaceBBusTriggers extends DolibarrTriggers
 
 
 		if ($action == 'LINEBILL_INSERT') {
-
 		}
 		/* 		var_dump('Ez mar kint van.');
 								  echo $object->fk_facture;
 								  echo $object->fk_product;
 								  exit;
-						   */// Put here code you want to execute when a Dolibarr business events occurs.
+						   */ // Put here code you want to execute when a Dolibarr business events occurs.
 		// Data and type of action are stored into $object and $action
 
 		// You can isolate code for each action in a separate method: this method should be named like the trigger in camelCase.
@@ -120,9 +119,8 @@ class InterfaceBBusTriggers extends DolibarrTriggers
 			);
 
 			return call_user_func($callback, $action, $object, $user, $langs, $conf);
-		}
-		;
-		
+		};
+
 		//print $action . '<br>';
 		//print_r($object);
 		//print $object->context['createcreditnotefrominvoice'];
@@ -131,13 +129,14 @@ class InterfaceBBusTriggers extends DolibarrTriggers
 		// Or you can execute some code here
 		switch ($action) {
 			case 'LINEBILL_INSERT':
-					$productObj = new Product($this->db);
-					$productObj->fetch($object->fk_product);
-					//if($productObj->array_options['options_basic_service'] == '1' || $productObj->array_options['options_basic_service'] == '2'){
-						$bbTicketHandler = new BbTicketHandler();
-						$bbTicketHandler->addTicket($object, $action);
-					//}
-					break;
+				$productObj = new Product($this->db);
+				$productObj->fetch($object->fk_product);
+				if ($productObj->array_options['options_basic_service'] == '3') {
+					ApiBbusLog::appLog("LINEBILL_INSERT->basic_service = " . $productObj->array_options['options_basic_service']);
+					$bbTicketHandler = new BbTicketHandler();
+					$bbTicketHandler->addTicket($object, $action);
+				}
+				break;
 
 			case 'LINEBILL_DELETE':
 				$bbTicketHandler = new BbTicketHandler();
@@ -146,10 +145,10 @@ class InterfaceBBusTriggers extends DolibarrTriggers
 
 			case 'BILL_PAYED':
 				//if ($object->code == "AC_BILL_PAYED") {
-					$commissionHandler = new CommissionHandler();
-					$commissionHandler->updateCommission($object);
-					//$apiBookingCLass = new BookingApi();
-					//$apiBookingCLass->saveEventData($object->event_id, $object->id, $object->fk_eventproduct);
+				$commissionHandler = new CommissionHandler();
+				$commissionHandler->updateCommission($object);
+				//$apiBookingCLass = new BookingApi();
+				//$apiBookingCLass->saveEventData($object->event_id, $object->id, $object->fk_eventproduct);
 				//}
 				break;
 			case 'LOGOUTCHANGENAPLO_CREATE':
@@ -159,208 +158,208 @@ class InterfaceBBusTriggers extends DolibarrTriggers
 				$userLoginNaplo->date_creation = $object->corrected_date;
 				$userLoginNaplo->update($user);
 				break;
-			// Users
-			//case 'USER_CREATE':
-			//case 'USER_MODIFY':
-			//case 'USER_NEW_PASSWORD':
-			//case 'USER_ENABLEDISABLE':
-			//case 'USER_DELETE':
-
-			// Actions
-			//case 'ACTION_MODIFY':
-			//case 'ACTION_CREATE':
-			//case 'ACTION_DELETE':
-
-			// Groups
-			//case 'USERGROUP_CREATE':
-			//case 'USERGROUP_MODIFY':
-			//case 'USERGROUP_DELETE':
-
-			// Companies
-			//case 'COMPANY_CREATE':
-			//case 'COMPANY_MODIFY':
-			//case 'COMPANY_DELETE':
-
-			// Contacts
-			//case 'CONTACT_CREATE':
-			//case 'CONTACT_MODIFY':
-			//case 'CONTACT_DELETE':
-			//case 'CONTACT_ENABLEDISABLE':
-
-			// Products
-			//case 'PRODUCT_CREATE':
-			//case 'PRODUCT_MODIFY':
-			//case 'PRODUCT_DELETE':
-			//case 'PRODUCT_PRICE_MODIFY':
-			//case 'PRODUCT_SET_MULTILANGS':
-			//case 'PRODUCT_DEL_MULTILANGS':
-
-			//Stock mouvement
-			//case 'STOCK_MOVEMENT':
-
-			//MYECMDIR
-			//case 'MYECMDIR_CREATE':
-			//case 'MYECMDIR_MODIFY':
-			//case 'MYECMDIR_DELETE':
-
-			// Customer orders
-			//case 'ORDER_CREATE':
-			//case 'ORDER_MODIFY':
-			//case 'ORDER_VALIDATE':
-			//case 'ORDER_DELETE':
-			//case 'ORDER_CANCEL':
-			//case 'ORDER_SENTBYMAIL':
-			//case 'ORDER_CLASSIFY_BILLED':
-			//case 'ORDER_SETDRAFT':
-			//case 'LINEORDER_INSERT':
-			//case 'LINEORDER_UPDATE':
-			//case 'LINEORDER_DELETE':
-
-			// Supplier orders
-			//case 'ORDER_SUPPLIER_CREATE':
-			//case 'ORDER_SUPPLIER_MODIFY':
-			//case 'ORDER_SUPPLIER_VALIDATE':
-			//case 'ORDER_SUPPLIER_DELETE':
-			//case 'ORDER_SUPPLIER_APPROVE':
-			//case 'ORDER_SUPPLIER_REFUSE':
-			//case 'ORDER_SUPPLIER_CANCEL':
-			//case 'ORDER_SUPPLIER_SENTBYMAIL':
-			//case 'ORDER_SUPPLIER_DISPATCH':
-			//case 'LINEORDER_SUPPLIER_DISPATCH':
-			//case 'LINEORDER_SUPPLIER_CREATE':
-			//case 'LINEORDER_SUPPLIER_UPDATE':
-			//case 'LINEORDER_SUPPLIER_DELETE':
-
-			// Proposals
-			//case 'PROPAL_CREATE':
-			//case 'PROPAL_MODIFY':
-			//case 'PROPAL_VALIDATE':
-			//case 'PROPAL_SENTBYMAIL':
-			//case 'PROPAL_CLOSE_SIGNED':
-			//case 'PROPAL_CLOSE_REFUSED':
-			//case 'PROPAL_DELETE':
-			//case 'LINEPROPAL_INSERT':
-			//case 'LINEPROPAL_UPDATE':
-			//case 'LINEPROPAL_DELETE':
-
-			// SupplierProposal
-			//case 'SUPPLIER_PROPOSAL_CREATE':
-			//case 'SUPPLIER_PROPOSAL_MODIFY':
-			//case 'SUPPLIER_PROPOSAL_VALIDATE':
-			//case 'SUPPLIER_PROPOSAL_SENTBYMAIL':
-			//case 'SUPPLIER_PROPOSAL_CLOSE_SIGNED':
-			//case 'SUPPLIER_PROPOSAL_CLOSE_REFUSED':
-			//case 'SUPPLIER_PROPOSAL_DELETE':
-			//case 'LINESUPPLIER_PROPOSAL_INSERT':
-			//case 'LINESUPPLIER_PROPOSAL_UPDATE':
-			//case 'LINESUPPLIER_PROPOSAL_DELETE':
-
-			// Contracts
-			//case 'CONTRACT_CREATE':
-			//case 'CONTRACT_MODIFY':
-			//case 'CONTRACT_ACTIVATE':
-			//case 'CONTRACT_CANCEL':
-			//case 'CONTRACT_CLOSE':
-			//case 'CONTRACT_DELETE':
-			//case 'LINECONTRACT_INSERT':
-			//case 'LINECONTRACT_UPDATE':
-			//case 'LINECONTRACT_DELETE':
-
-			// Bills
-			//case 'BILL_CREATE':
-			//case 'BILL_MODIFY':
-			//case 'BILL_VALIDATE':
-			//case 'BILL_UNVALIDATE':
-			//case 'BILL_SENTBYMAIL':
-			//case 'BILL_CANCEL':
-			//case 'BILL_DELETE':
-			//case 'BILL_UNPAYED':
-			//case 'BILL_PAYED':
-
-			//case 'LINEBILL_UPDATE':
-			//case 'LINEBILL_DELETE':
-
-			//Supplier Bill
-			//case 'BILL_SUPPLIER_CREATE':
-			//case 'BILL_SUPPLIER_UPDATE':
-			//case 'BILL_SUPPLIER_DELETE':
-			//case 'BILL_SUPPLIER_PAYED':
-			//case 'BILL_SUPPLIER_UNPAYED':
-			//case 'BILL_SUPPLIER_VALIDATE':
-			//case 'BILL_SUPPLIER_UNVALIDATE':
-			//case 'LINEBILL_SUPPLIER_CREATE':
-			//case 'LINEBILL_SUPPLIER_UPDATE':
-			//case 'LINEBILL_SUPPLIER_DELETE':
-
-			// Payments
-			//case 'PAYMENT_CUSTOMER_CREATE':
-			//case 'PAYMENT_SUPPLIER_CREATE':
-			//case 'PAYMENT_ADD_TO_BANK':
-			//case 'PAYMENT_DELETE':
-
-			// Online
-			//case 'PAYMENT_PAYBOX_OK':
-			//case 'PAYMENT_PAYPAL_OK':
-			//case 'PAYMENT_STRIPE_OK':
-
-			// Donation
-			//case 'DON_CREATE':
-			//case 'DON_UPDATE':
-			//case 'DON_DELETE':
-
-			// Interventions
-			//case 'FICHINTER_CREATE':
-			//case 'FICHINTER_MODIFY':
-			//case 'FICHINTER_VALIDATE':
-			//case 'FICHINTER_DELETE':
-			//case 'LINEFICHINTER_CREATE':
-			//case 'LINEFICHINTER_UPDATE':
-			//case 'LINEFICHINTER_DELETE':
-
-			// Members
-			//case 'MEMBER_CREATE':
-			//case 'MEMBER_VALIDATE':
-			//case 'MEMBER_SUBSCRIPTION':
-			//case 'MEMBER_MODIFY':
-			//case 'MEMBER_NEW_PASSWORD':
-			//case 'MEMBER_RESILIATE':
-			//case 'MEMBER_DELETE':
-
-			// Categories
-			//case 'CATEGORY_CREATE':
-			//case 'CATEGORY_MODIFY':
-			//case 'CATEGORY_DELETE':
-			//case 'CATEGORY_SET_MULTILANGS':
-
-			// Projects
-			//case 'PROJECT_CREATE':
-			//case 'PROJECT_MODIFY':
-			//case 'PROJECT_DELETE':
-
-			// Project tasks
-			//case 'TASK_CREATE':
-			//case 'TASK_MODIFY':
-			//case 'TASK_DELETE':
-
-			// Task time spent
-			//case 'TASK_TIMESPENT_CREATE':
-			//case 'TASK_TIMESPENT_MODIFY':
-			//case 'TASK_TIMESPENT_DELETE':
-			//case 'PROJECT_ADD_CONTACT':
-			//case 'PROJECT_DELETE_CONTACT':
-			//case 'PROJECT_DELETE_RESOURCE':
-
-			// Shipping
-			//case 'SHIPPING_CREATE':
-			//case 'SHIPPING_MODIFY':
-			//case 'SHIPPING_VALIDATE':
-			//case 'SHIPPING_SENTBYMAIL':
-			//case 'SHIPPING_BILLED':
-			//case 'SHIPPING_CLOSED':
-			//case 'SHIPPING_REOPEN':
-			//case 'SHIPPING_DELETE':
-
-			// and more...
+				// Users
+				//case 'USER_CREATE':
+				//case 'USER_MODIFY':
+				//case 'USER_NEW_PASSWORD':
+				//case 'USER_ENABLEDISABLE':
+				//case 'USER_DELETE':
+
+				// Actions
+				//case 'ACTION_MODIFY':
+				//case 'ACTION_CREATE':
+				//case 'ACTION_DELETE':
+
+				// Groups
+				//case 'USERGROUP_CREATE':
+				//case 'USERGROUP_MODIFY':
+				//case 'USERGROUP_DELETE':
+
+				// Companies
+				//case 'COMPANY_CREATE':
+				//case 'COMPANY_MODIFY':
+				//case 'COMPANY_DELETE':
+
+				// Contacts
+				//case 'CONTACT_CREATE':
+				//case 'CONTACT_MODIFY':
+				//case 'CONTACT_DELETE':
+				//case 'CONTACT_ENABLEDISABLE':
+
+				// Products
+				//case 'PRODUCT_CREATE':
+				//case 'PRODUCT_MODIFY':
+				//case 'PRODUCT_DELETE':
+				//case 'PRODUCT_PRICE_MODIFY':
+				//case 'PRODUCT_SET_MULTILANGS':
+				//case 'PRODUCT_DEL_MULTILANGS':
+
+				//Stock mouvement
+				//case 'STOCK_MOVEMENT':
+
+				//MYECMDIR
+				//case 'MYECMDIR_CREATE':
+				//case 'MYECMDIR_MODIFY':
+				//case 'MYECMDIR_DELETE':
+
+				// Customer orders
+				//case 'ORDER_CREATE':
+				//case 'ORDER_MODIFY':
+				//case 'ORDER_VALIDATE':
+				//case 'ORDER_DELETE':
+				//case 'ORDER_CANCEL':
+				//case 'ORDER_SENTBYMAIL':
+				//case 'ORDER_CLASSIFY_BILLED':
+				//case 'ORDER_SETDRAFT':
+				//case 'LINEORDER_INSERT':
+				//case 'LINEORDER_UPDATE':
+				//case 'LINEORDER_DELETE':
+
+				// Supplier orders
+				//case 'ORDER_SUPPLIER_CREATE':
+				//case 'ORDER_SUPPLIER_MODIFY':
+				//case 'ORDER_SUPPLIER_VALIDATE':
+				//case 'ORDER_SUPPLIER_DELETE':
+				//case 'ORDER_SUPPLIER_APPROVE':
+				//case 'ORDER_SUPPLIER_REFUSE':
+				//case 'ORDER_SUPPLIER_CANCEL':
+				//case 'ORDER_SUPPLIER_SENTBYMAIL':
+				//case 'ORDER_SUPPLIER_DISPATCH':
+				//case 'LINEORDER_SUPPLIER_DISPATCH':
+				//case 'LINEORDER_SUPPLIER_CREATE':
+				//case 'LINEORDER_SUPPLIER_UPDATE':
+				//case 'LINEORDER_SUPPLIER_DELETE':
+
+				// Proposals
+				//case 'PROPAL_CREATE':
+				//case 'PROPAL_MODIFY':
+				//case 'PROPAL_VALIDATE':
+				//case 'PROPAL_SENTBYMAIL':
+				//case 'PROPAL_CLOSE_SIGNED':
+				//case 'PROPAL_CLOSE_REFUSED':
+				//case 'PROPAL_DELETE':
+				//case 'LINEPROPAL_INSERT':
+				//case 'LINEPROPAL_UPDATE':
+				//case 'LINEPROPAL_DELETE':
+
+				// SupplierProposal
+				//case 'SUPPLIER_PROPOSAL_CREATE':
+				//case 'SUPPLIER_PROPOSAL_MODIFY':
+				//case 'SUPPLIER_PROPOSAL_VALIDATE':
+				//case 'SUPPLIER_PROPOSAL_SENTBYMAIL':
+				//case 'SUPPLIER_PROPOSAL_CLOSE_SIGNED':
+				//case 'SUPPLIER_PROPOSAL_CLOSE_REFUSED':
+				//case 'SUPPLIER_PROPOSAL_DELETE':
+				//case 'LINESUPPLIER_PROPOSAL_INSERT':
+				//case 'LINESUPPLIER_PROPOSAL_UPDATE':
+				//case 'LINESUPPLIER_PROPOSAL_DELETE':
+
+				// Contracts
+				//case 'CONTRACT_CREATE':
+				//case 'CONTRACT_MODIFY':
+				//case 'CONTRACT_ACTIVATE':
+				//case 'CONTRACT_CANCEL':
+				//case 'CONTRACT_CLOSE':
+				//case 'CONTRACT_DELETE':
+				//case 'LINECONTRACT_INSERT':
+				//case 'LINECONTRACT_UPDATE':
+				//case 'LINECONTRACT_DELETE':
+
+				// Bills
+				//case 'BILL_CREATE':
+				//case 'BILL_MODIFY':
+				//case 'BILL_VALIDATE':
+				//case 'BILL_UNVALIDATE':
+				//case 'BILL_SENTBYMAIL':
+				//case 'BILL_CANCEL':
+				//case 'BILL_DELETE':
+				//case 'BILL_UNPAYED':
+				//case 'BILL_PAYED':
+
+				//case 'LINEBILL_UPDATE':
+				//case 'LINEBILL_DELETE':
+
+				//Supplier Bill
+				//case 'BILL_SUPPLIER_CREATE':
+				//case 'BILL_SUPPLIER_UPDATE':
+				//case 'BILL_SUPPLIER_DELETE':
+				//case 'BILL_SUPPLIER_PAYED':
+				//case 'BILL_SUPPLIER_UNPAYED':
+				//case 'BILL_SUPPLIER_VALIDATE':
+				//case 'BILL_SUPPLIER_UNVALIDATE':
+				//case 'LINEBILL_SUPPLIER_CREATE':
+				//case 'LINEBILL_SUPPLIER_UPDATE':
+				//case 'LINEBILL_SUPPLIER_DELETE':
+
+				// Payments
+				//case 'PAYMENT_CUSTOMER_CREATE':
+				//case 'PAYMENT_SUPPLIER_CREATE':
+				//case 'PAYMENT_ADD_TO_BANK':
+				//case 'PAYMENT_DELETE':
+
+				// Online
+				//case 'PAYMENT_PAYBOX_OK':
+				//case 'PAYMENT_PAYPAL_OK':
+				//case 'PAYMENT_STRIPE_OK':
+
+				// Donation
+				//case 'DON_CREATE':
+				//case 'DON_UPDATE':
+				//case 'DON_DELETE':
+
+				// Interventions
+				//case 'FICHINTER_CREATE':
+				//case 'FICHINTER_MODIFY':
+				//case 'FICHINTER_VALIDATE':
+				//case 'FICHINTER_DELETE':
+				//case 'LINEFICHINTER_CREATE':
+				//case 'LINEFICHINTER_UPDATE':
+				//case 'LINEFICHINTER_DELETE':
+
+				// Members
+				//case 'MEMBER_CREATE':
+				//case 'MEMBER_VALIDATE':
+				//case 'MEMBER_SUBSCRIPTION':
+				//case 'MEMBER_MODIFY':
+				//case 'MEMBER_NEW_PASSWORD':
+				//case 'MEMBER_RESILIATE':
+				//case 'MEMBER_DELETE':
+
+				// Categories
+				//case 'CATEGORY_CREATE':
+				//case 'CATEGORY_MODIFY':
+				//case 'CATEGORY_DELETE':
+				//case 'CATEGORY_SET_MULTILANGS':
+
+				// Projects
+				//case 'PROJECT_CREATE':
+				//case 'PROJECT_MODIFY':
+				//case 'PROJECT_DELETE':
+
+				// Project tasks
+				//case 'TASK_CREATE':
+				//case 'TASK_MODIFY':
+				//case 'TASK_DELETE':
+
+				// Task time spent
+				//case 'TASK_TIMESPENT_CREATE':
+				//case 'TASK_TIMESPENT_MODIFY':
+				//case 'TASK_TIMESPENT_DELETE':
+				//case 'PROJECT_ADD_CONTACT':
+				//case 'PROJECT_DELETE_CONTACT':
+				//case 'PROJECT_DELETE_RESOURCE':
+
+				// Shipping
+				//case 'SHIPPING_CREATE':
+				//case 'SHIPPING_MODIFY':
+				//case 'SHIPPING_VALIDATE':
+				//case 'SHIPPING_SENTBYMAIL':
+				//case 'SHIPPING_BILLED':
+				//case 'SHIPPING_CLOSED':
+				//case 'SHIPPING_REOPEN':
+				//case 'SHIPPING_DELETE':
+
+				// and more...
 
 			default:
 				dol_syslog("Trigger '" . $this->name . "' for action '$action' launched by " . __FILE__ . ". id=" . $object->id);
@@ -374,4 +373,4 @@ class InterfaceBBusTriggers extends DolibarrTriggers
 		} */
 		return 0;
 	}
-}
+}

+ 445 - 572
custom/booking/class/api_booking.class.php

@@ -24,11 +24,8 @@ require_once DOL_DOCUMENT_ROOT . '/custom/bbus/class/api_bbus.class.php';
 require_once DOL_DOCUMENT_ROOT . '/custom/bbus/class/api_bbus_log.class.php';
 require_once DOL_DOCUMENT_ROOT . '/custom/bbus/class/apiinvoicehelper.class.php';
 require_once DOL_DOCUMENT_ROOT . '/custom/bbus/class/apiproductlisthelper.class.php';
-require_once DOL_DOCUMENT_ROOT . '/custom/booking/class/eventhelper.class.php';
 require_once DOL_DOCUMENT_ROOT . '/product/class/product.class.php';
 require_once DOL_DOCUMENT_ROOT . '/compta/facture/class/facture.class.php';
-require_once DOL_DOCUMENT_ROOT . '/comm/action/class/actioncomm.class.php';
-require_once DOL_DOCUMENT_ROOT . '/custom/booking/class/preorder.class.php';
 require_once DOL_DOCUMENT_ROOT . '/custom/bbus/class/api_curl.class.php';
 require_once DOL_DOCUMENT_ROOT . '/custom/bbus/class/basicservices.class.php';
 
@@ -45,7 +42,6 @@ require_once DOL_DOCUMENT_ROOT . '/custom/bbus/class/basicservices.class.php';
  */
 class BookingApi extends DolibarrApi
 {
-
 	use CurlApi;
 
 	/**
@@ -68,172 +64,6 @@ class BookingApi extends DolibarrApi
 		// $this->bookinglog = new BookingLog($this->db);
 	}
 
-	#-------------------------------------------------
-	#	Vásárlási folyamat részei
-	#-------------------------------------------------
-
-	/**
-	 * Get all free spaces on a selected date
-	 *
-	 * Return an array with details
-	 *
-	 * @return 	array|mixed data without useless information
-	 *
-	 * @param 	string 	date_from
-	 * @param 	string 	date_to
-	 * @param 	int 	product_id
-	 * @param 	int 	participant_number
-	 * 
-	 * @url	POST getavailablespaces
-	 *
-	 * @throws RestException 401 Not allowed
-	 * @throws RestException 404 Not found
-	 */
-	public function getAvailableSpaces(string $date_from, string $date_to, int $product_id, int $participant_number, string $type_id = null)
-	{
-		ApiBbusLog::appLog("getAvailableSpaces");
-		/* ApiBbusLog::appLog("type_id: {$type_id}");
-		ApiBbusLog::appLog("date_from: {$date_from}");
-		ApiBbusLog::appLog("date_to: {$date_to}");
-		ApiBbusLog::appLog("product_id: {$product_id}");
-		ApiBbusLog::appLog("participant_number: {$participant_number}"); */
-		$basicServices = new BasicServices($this->db);
-		$resultBS = $basicServices->fetch($type_id);
-		if ($basicServices->server_host == 'excelia') {
-			return $this->localAvailablePlaces($date_from, $date_to, $product_id, $participant_number);
-		} else {
-			return $this->curlAvailablePlaces($date_from, $date_to, $product_id, $participant_number);
-		}
-	}
-
-	/**
-	 * First step of the eventhandling
-	 * {"fk_event":669,"reservations":1,"product_id":2,"sendId":"12121212"}
-	 *
-	 * Return an array with details
-	 *
-	 * @return 	array|mixed data without useless information
-	 *
-	 * @param 	int 	$fk_event			//selected evet from llx_event
-	 * @param 	int 	$reservations		//numbers of reservations
-	 * @param 	int 	$product_id			//Product
-	 * @param 	string	$sendId				//ID
-	 * 
-	 * @url	POST firsteventstep
-	 * @access protected
-	 * @throws RestException 401 Not allowed
-	 * @throws RestException 404 Not found
-	 * @throws RestException 506 No available spaces
-	 * 
-	 */
-	public function firstEventStep(int $fk_event, int $reservations, int $product_id, string $sendId)
-	{
-		ApiBbusLog::eventLog("fk_event: {$fk_event}");
-		ApiBbusLog::eventLog("reservations: {$reservations}");
-		ApiBbusLog::eventLog("product_id: {$product_id}");
-		ApiBbusLog::eventLog("sendId: {$sendId}");
-		$eventHelper = new EventHelper;
-		if ($eventHelper->noEmptySpaces($fk_event, $reservations)) {
-			throw new RestException(506, 'No available spaces');
-		}
-
-		if (!DolibarrApiAccess::$user->rights->facture->creer) {
-			ApiBbusLog::eventLog("{$sendId} Insufficient rights");
-			throw new RestException(401, 'Insufficient rights');
-		}
-		/**
-		 * LOG SECTION
-		 */
-		ApiBbusLog::eventLog("{$sendId} === NEW INVOICE ===");
-		dol_syslog("{$sendId} === NEW INVOICE ===", LOG_INFO, 0);
-		ApiBbusLog::eventLog("{$sendId} REQUEST: {$sendId}");
-		dol_syslog("{$sendId} REQUEST: {$sendId}", LOG_INFO, 0);
-		ApiBbusLog::eventLog("{$sendId} User: {$this->user->firstname} {$this->user->lastname} (ID: {$this->user->id})");
-		dol_syslog("{$sendId} User: {$this->user->firstname} {$this->user->lastname} (ID: {$this->user->id})", LOG_INFO, 0);
-		ApiBbusLog::eventLog("{$sendId} " . json_encode([
-			'fk_event' => $fk_event,
-			'reservations' => $reservations,
-			'product_id' => $product_id,
-			'sendId' => $sendId,
-		]));
-
-		$apiInvoiceHelper = new ApiInvoiceHelper;
-		$createdPreOrderOBJ = [];
-
-		for ($i = 1; $i <= $reservations; $i++) {
-			dol_include_once('/comm/action/class/actioncomm.class.php');
-			dol_include_once('/custom/booking/class/preorder.class.php');
-			$apiInvoiceHelper->increaseParticipant($fk_event);
-
-			$lines = $apiInvoiceHelper->getProductLines($product_id);
-			foreach ($lines as $line) {
-				$preOrderObj = new PreOrder($this->db);
-				$preOrderObj->ref = $this->generateRandomString();
-				$preOrderObj->fk_event = $fk_event;
-				$preOrderObj->fk_product = $product_id;
-				$result = $preOrderObj->create($this->user);
-				if ($result > 0) {
-					$createdPreOrderOBJ[] = [
-						'id' => $preOrderObj->id,
-						'ref' => $preOrderObj->ref,
-					];
-				} else {
-					ApiBbusLog::eventLog(json_encode(['error' => $preOrderObj->errors]));
-					ApiBbusLog::eventLog("Unsaved event: " . $fk_event);
-					throw new RestException(401, 'Unsaved event: ' . $fk_event);
-				}
-			}
-		}
-		return $createdPreOrderOBJ;
-	}
-
-	/**
-	 * Validate and save invoice
-	 * {"cardPaymentLog": "","sendId": "Xune5nQb","payment": {"datepaye": 1720005853,"paymentid": 4,"accountid": 2,"closepaidinvoices": "yes"},"preorder": [23]}
-	 *
-	 * Return an array with details
-	 *
-	 * @return 	array|mixed data without useless information
-	 *
-	 * @param 	string	$sendId				sendID
-	 * @param  	array 	$payment			Invoice payment
-	 * @param  	array 	$preorder			preorder
-	 * @param  	array 	$invoice			Invoice
-	 * @param  	string 	$cardPaymentLog		Card payment log data
-	 * 
-	 * @url	POST validateandsaveinvoice
-	 * @access protected
-
-	 * @throws RestException 401 Not allowed
-	 * @throws RestException 404 Not found
-	 * @throws RestException 506 No available spaces
-	 * 
-	 */
-	public function validateandsaveinvoice(string $sendId, array $payment, array $preorder, array $invoice, string $cardPaymentLog = '')
-	{
-		global $user, $db;
-		$createdInvoiceData = [];
-		$apiInvoiceHelper = new ApiInvoiceHelper;
-		$bbusApi = new BBus();
-		foreach ($preorder as $order) {
-			$sql = "SELECT fk_product, fk_event  FROM llx_booking_preorder WHERE rowid = {$order}";
-			//print $sql . "\r\n";
-			$data = $db->query($sql);
-			if ($db->num_rows($data) > 0) {
-				while ($row = $db->fetch_object($data)) {
-					//print_r($row);
-					$lines = $apiInvoiceHelper->getProductLines($row->fk_product);
-					$createdInvoiceArray = $bbusApi->invoice($invoice, $lines, $payment, $cardPaymentLog = '', $sendId = '');
-					$createdInvoiceData[] = $createdInvoiceArray;
-					$bookingHistory = $this->saveEventData((int)$row->fk_event, $createdInvoiceArray['invoice']['ref'], $createdInvoiceArray['invoice']['id']);
-					$this->updateBbticket($bookingHistory, $createdInvoiceArray['invoice']);
-					$this->deletePreorder($preorder);
-				}
-			}
-		}
-		return $createdInvoiceData;
-	}
-
 	//P4NR6zhWHage
 	//!!!types:
 
@@ -692,6 +522,112 @@ class BookingApi extends DolibarrApi
 		return $productsArray;
 	}
 
+	/**
+	 * First step of the eventhandling
+	 *
+	 * Return an array with details
+	 *
+	 * @return 	array|mixed data without useless information
+	 *
+	 * @param 	int 	$type_id			//selected evet from llx_event
+	 * @param 	int 	$fk_event			//selected evet from llx_event
+	 * @param 	int 	$reservations		//numbers of reservations
+	 * @param 	int 	$product_id			//Product
+	 * @param 	string	$sendId				//ID
+	 * 
+	 * @url	POST firsteventstep
+	 * @access protected
+	 * @throws RestException 401 Not allowed
+	 * @throws RestException 404 Not found
+	 * @throws RestException 506 No available spaces
+	 * 
+	 */
+	public function firstEventStep(int $type_id, int $fk_event, int $reservations, int $product_id, string $sendId)
+	{
+		ApiBbusLog::appLog("firstEventStep");
+
+		if (!DolibarrApiAccess::$user->rights->facture->creer) {
+			ApiBbusLog::eventLog("{$sendId} Insufficient rights");
+			throw new RestException(401, 'Insufficient rights');
+		}
+		$this->createLog($sendId, $fk_event, $reservations, $product_id);
+
+
+		$server_host = $this->getServerHost($type_id);
+		if ($server_host == 'excelia') {
+			if ($this->noLocalEmptySpaces($fk_event, $reservations)) {
+				throw new RestException(506, 'No available spaces');
+			}
+			$createdPreOrderOBJ = $this->localcreatedpreorderobj($sendId, $fk_event, $reservations, $product_id);
+		} else {
+			$params = compact('fk_event', 'reservations');
+			$postFields = json_encode($params);
+			$noavailableSpaces = json_decode($this->curlRunner('bookingapi/nolocalemptyspaces', $postFields, 'POST', true))->result;
+			if ($noavailableSpaces) {
+				throw new RestException(506, 'No available spaces');
+			}
+			$params = compact('sendId', 'fk_event', 'reservations', 'product_id');
+			$postFields = json_encode($params);
+			$createdPreOrderOBJ = $this->curlRunner('bookingapi/localcreatedpreorderobj', $postFields, 'POST', true);
+		}
+
+
+		return $createdPreOrderOBJ;
+	}
+
+	function localcreatedpreorderobj($sendId, $fk_event, $reservations, $product_id)
+	{
+		ApiBbusLog::appLog("{$sendId}: localcreatedpreorderobj");
+
+		$apiInvoiceHelper = new ApiInvoiceHelper;
+		$createdPreOrderOBJ = [];
+		for ($i = 1; $i <= $reservations; $i++) {
+			dol_include_once('/comm/action/class/actioncomm.class.php');
+			dol_include_once('/custom/booking/class/preorder.class.php');
+			$apiInvoiceHelper->increaseParticipant($fk_event);
+
+			$lines = $apiInvoiceHelper->getProductLines($product_id);
+			foreach ($lines as $line) {
+				$preOrderObj = new PreOrder($this->db);
+				$preOrderObj->ref = $this->generateRandomString();
+				$preOrderObj->fk_event = $fk_event;
+				$preOrderObj->fk_product = $product_id;
+				$result = $preOrderObj->create($this->user);
+				if ($result > 0) {
+					$createdPreOrderOBJ[] = [
+						'id' => $preOrderObj->id,
+						'ref' => $preOrderObj->ref,
+					];
+				} else {
+					ApiBbusLog::appLog("{$sendId}: " . json_encode(['error' => $preOrderObj->errors]));
+					ApiBbusLog::appLog("{$sendId}: Unsaved event: " . $fk_event);
+					throw new RestException(401, 'Unsaved event: ' . $fk_event);
+				}
+			}
+		}
+		ApiBbusLog::appLog(json_encode($createdPreOrderOBJ));
+		return $createdPreOrderOBJ;
+	}
+
+	function createLog($sendId, $fk_event, $reservations, $product_id)
+	{
+		/**
+		 * LOG SECTION
+		 */
+		ApiBbusLog::eventLog("{$sendId} === NEW INVOICE ===");
+		dol_syslog("{$sendId} === NEW INVOICE ===", LOG_INFO, 0);
+		ApiBbusLog::eventLog("{$sendId} REQUEST: {$sendId}");
+		dol_syslog("{$sendId} REQUEST: {$sendId}", LOG_INFO, 0);
+		ApiBbusLog::eventLog("{$sendId} User: {$this->user->firstname} {$this->user->lastname} (ID: {$this->user->id})");
+		dol_syslog("{$sendId} User: {$this->user->firstname} {$this->user->lastname} (ID: {$this->user->id})", LOG_INFO, 0);
+		ApiBbusLog::eventLog("{$sendId} " . json_encode([
+			'fk_event' => $fk_event,
+			'reservations' => $reservations,
+			'product_id' => $product_id,
+			'sendId' => $sendId,
+		]));
+	}
+
 	function generateRandomString($length = 10)
 	{
 		$characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
@@ -711,17 +647,17 @@ class BookingApi extends DolibarrApi
 	 *
 	 * @return 	array|mixed data without useless information
 	 *
-	 * @param 	string 	$fk_event			//selected evet from llx_event
-	 * @param 	string 	$fk_facture			//facture rowid from llx_facture
-	 * @param 	string 	$fk_eventproduct	//eventproduct rowid from llx_eventwizard_eventproduct
-	 * @param 	string 	$ref
+	 * @param 	int 	$fk_event			//selected evet from llx_event
+	 * @param 	int 	$fk_facture			//facture rowid from llx_facture
+	 * @param 	int 	$fk_eventproduct	//eventproduct rowid from llx_eventwizard_eventproduct
+	 * @param 	string 	$ref				//ref
 	 * 
 	 * @url	POST saveeventdata
 	 * @access protected
 	 * @throws RestException 401 Not allowed
 	 * @throws RestException 404 Not found
 	 */
-	public function saveEventData(string $fk_event, string $ref, string $fk_facture = null, string $fk_eventproduct = null)
+	public function saveEventData(int $fk_event, int $fk_facture = null, int $fk_eventproduct = null, string $ref = null )
 	{
 		dol_include_once('/custom/booking/class/bookinghistory.class.php');
 		dol_include_once('/comm/action/class/actioncomm.class.php');
@@ -731,10 +667,10 @@ class BookingApi extends DolibarrApi
 		if ($this->db->num_rows($result) > 0) {
 			$row = $this->db->fetch_object($result);
 			$BookingHistory = new BookingHistory($this->db);
-			$BookingHistory->fk_event = (int)$fk_event;
-			$BookingHistory->fk_facture = (int)$fk_facture;
+			$BookingHistory->fk_event = $fk_event;
+			$BookingHistory->fk_facture = $fk_facture;
 			$BookingHistory->fk_event_detail = $row->fk_element;
-			$BookingHistory->fk_eventproduct = (int)$fk_eventproduct;
+			$BookingHistory->fk_eventproduct = $fk_eventproduct;
 			$BookingHistory->date_start = strtotime($row->datep);
 			$BookingHistory->date_end = strtotime($row->datep2);
 			$BookingHistory->invoice_number = $ref;
@@ -749,30 +685,239 @@ class BookingApi extends DolibarrApi
 		}
 	}
 
-	public function updateBbticket($fk_booking_history, $invoice)
+	/**
+	 * Validate and save invoice
+	 *
+	 * Return an array with details
+	 *
+	 * @return 	array|mixed data without useless information
+	 *
+	 * @param 	int 	$type_id			Type_id
+	 * @param 	string	$sendId				sendID
+	 * @param  	array 	$payment			Invoice payment
+	 * @param  	array 	$preorder			preorder
+	 * @param  	array 	$invoice			Invoice
+	 * @param  	string 	$cardPaymentLog		Card payment log data
+	 * 
+	 * @url	POST validateandsaveinvoice
+	 * @access protected
+
+	 * @throws RestException 401 Not allowed
+	 * @throws RestException 404 Not found
+	 * @throws RestException 506 No available spaces
+	 * 
+	 */
+	public function validateandsaveinvoice(int $type_id, string $sendId, array $payment, array $preorder, array $invoice, string $cardPaymentLog = '')
 	{
-		global $user;
-		$sql = "SELECT rowid FROM llx_bbus_bbticket WHERE fk_facture = {$invoice['id']}";
-		$data = $this->db->query($sql);
-		if ($this->db->num_rows($data) > 0) {
-			while ($row = $this->db->fetch_object($data)) {
-				$sql = "UPDATE llx_bbus_bbticket
-				SET booking_history_id = {$fk_booking_history}, invoice_number = '{$invoice['ref']}'
-				WHERE rowid = {$row->rowid}";
-				$this->db->query($sql);
+		global $db;
+		$server_host = $this->getServerHost($type_id);
+		$createdInvoiceArray = $this->localValidateAndSaveInvoice($invoice, $preorder, $payment, $cardPaymentLog, $sendId, $server_host);
+		//print_r($createdInvoiceArray);exit;
+		if ($server_host == 'excelia') {
+			ApiBbusLog::appLog("validateandsaveinvoice: Excelia");
+			ApiBbusLog::appLog(json_encode($preorder));
+			//exit;
+			foreach ($preorder as $order) {
+				$sql = "SELECT fk_product, fk_event  FROM llx_booking_preorder WHERE rowid = {$order}";
+				ApiBbusLog::appLog("{$sql}");
+				$data = $db->query($sql);
+				if ($db->num_rows($data) > 0) {
+					while ($row = $db->fetch_object($data)) {
+						$bookingHistory = $this->saveEventData((int)$row->fk_event, $createdInvoiceArray[0]['invoice']['id']);
+						$this->updateBbticket($bookingHistory, $createdInvoiceArray[0]['invoice']);
+						$this->deletePreorder($preorder);
+					}
+				}
+			}
+		} else {
+			foreach ($preorder as $rowid) {
+				ApiBbusLog::appLog("validateandsaveinvoice: Buziiiiiiii");
+				$params = compact('rowid');
+				$postFields = json_encode($params);
+				$preorderArray = $this->curlRunner('bookingapi/localpreorderarray', $postFields, 'POST', true);
+				$saveEventdataPostFields = '{"fk_event":"' . (int)$preorderArray->fk_event . '","ref":"' . $createdInvoiceArray[0]['invoice']['ref'] . '","fk_facture":"' . null . '","fk_eventproduct":"' . null . '"}';
+				$bookingHistory = $this->curlRunner('bookingapi/saveEventData', $saveEventdataPostFields, 'POST', true);
+				$array['fk_booking_history'] = $bookingHistory;
+				$array['invoice'] = $createdInvoiceArray[0]['invoice'];
+				$updateBBticketPostFields = json_encode($array);
+				$this->curlRunner('bookingapi/curlUpdateBbticket', $updateBBticketPostFields, 'POST', true);
+				ApiBbusLog::appLog("validateandsaveinvoice: {$postFields}");
+				$this->curlRunner('bookingapi/curlDeletePreorder', $postFields, 'POST', true);
 			}
 		}
-	}
+		ApiBbusLog::appLog("validateandsaveinvoice: END");
 
-	public function deletePreorder($preorder)
-	{
-		foreach ($preorder as $item) {
-			$sql = "DELETE FROM llx_booking_preorder WHERE rowid = {$item}";
-			$this->db->query($sql);
-		}
+		return $createdInvoiceArray;
 	}
 
-	public function eventErasuer()
+	public function localValidateAndSaveInvoice($invoice, $preorder, $payment, $cardPaymentLog, $sendId, $server_host)
+	{
+		global $user, $db;
+		$createdInvoiceData = [];
+		$apiInvoiceHelper = new ApiInvoiceHelper;
+		$bbusApi = new BBus();
+		foreach ($preorder as $rowid) {
+			$params = compact('rowid');
+			$postFields = json_encode($params);
+			if ($server_host == 'excelia') {
+				ApiBbusLog::appLog("localValidateAndSaveInvoice: Excelia");
+				$preorderArray = $this->localpreorderarray($rowid);
+			} else {
+				$preorderArray = $this->curlRunner('bookingapi/localpreorderarray', $postFields, 'POST', true);
+			}
+			$lines = $apiInvoiceHelper->getProductLinesWithoutDiscount($preorderArray->fk_product);
+			//$lines = $apiInvoiceHelper->createLinesForCrossShopping($preorderArray->fk_product);
+			$createdInvoiceArray = $bbusApi->invoice($invoice, $lines, $payment, $cardPaymentLog = '', $sendId = '');
+			$createdInvoiceData[] = $createdInvoiceArray;
+		}
+		ApiBbusLog::appLog("Visszaküld");
+		$asd = json_encode($createdInvoiceData);
+		ApiBbusLog::appLog("{$asd}");
+
+		return $createdInvoiceData;
+	}
+
+	public function localpreorderarray(int $rowid)
+	{
+		global $user, $db;
+		$result = [];
+		$sql = "SELECT fk_product, fk_event  FROM llx_booking_preorder WHERE rowid = {$rowid}";
+		$data = $db->query($sql);
+		if ($db->num_rows($data) > 0) {
+			while ($row = $db->fetch_object($data)) {
+				$result = $row;
+			}
+		}
+		return $result;
+	}
+
+	/**
+	 * curllocalpreorderarray
+	 *
+	 * Return an array with details
+	 *
+	 * @return 	array|mixed data without useless information
+	 *
+	 * @param 	int 	$rowid			
+	 * 
+	 * @url	POST curllocalpreorderarray
+	 * @access protected
+
+	 * @throws RestException 401 Not allowed
+	 * @throws RestException 404 Not found
+	 * @throws RestException 506 No available spaces
+	 * 
+	 */
+	public function curllocalpreorderarray(int $rowid)
+	{
+		global $user, $db;
+		$result = [];
+		$sql = "SELECT fk_product, fk_event  FROM llx_booking_preorder WHERE rowid = {$rowid}";
+		$data = $db->query($sql);
+		if ($db->num_rows($data) > 0) {
+			while ($row = $db->fetch_object($data)) {
+				$result = $row;
+			}
+		}
+		return $result;
+	}
+
+	public function updateBbticket($fk_booking_history, $invoice)
+	{
+		global $user;
+		$sql = "SELECT rowid FROM llx_bbus_bbticket WHERE fk_facture = {$invoice['id']}";
+		//print $sql;exit;
+		$data = $this->db->query($sql);
+		if (!empty($this->db->error())) {
+			ApiBbusLog::appLog("{$this->db->error()}");
+			throw new RestException(401, "{$this->db->error()}");
+		}
+		if ($this->db->num_rows($data) > 0) {
+			while ($row = $this->db->fetch_object($data)) {
+				$sql = "UPDATE llx_bbus_bbticket
+					SET booking_history_id = {$fk_booking_history}, invoice_number = '{$invoice['ref']}'
+					WHERE rowid = {$row->rowid}";
+				$this->db->query($sql);
+			}
+		} else {
+			ApiBbusLog::appLog("api_booking: updateBbticket error");
+			throw new RestException(401, 'api_booking: updateBbticket error');
+		}
+	}
+
+	/**
+	 * curlupdateBbticket
+	 *
+	 * Return an array with details
+	 *
+	 *
+	 * @param  	int 	$fk_booking_history			preorder
+	 * @param  	array 	$invoice					invoice
+	 * 
+	 * @url	POST curlupdateBbticket
+	 * @access protected
+
+	 * @throws RestException 401 Not allowed
+	 * @throws RestException 404 Not found
+	 * @throws RestException 506 No available spaces
+	 * 
+	 */
+	public function curlupdateBbticket(int $fk_booking_history, array $invoice)
+	{
+		global $user;
+		$sql = "SELECT rowid FROM llx_bbus_bbticket WHERE invoice_number = '{$invoice['id']}'";
+		$data = $this->db->query($sql);
+		if (!empty($this->db->error())) {
+			ApiBbusLog::appLog("{$this->db->error()}");
+			throw new RestException(401, "{$this->db->error()}");
+		}
+		$data = $this->db->query($sql);
+		if ($this->db->num_rows($data) > 0) {
+			while ($row = $this->db->fetch_object($data)) {
+				$sql = "UPDATE llx_bbus_bbticket
+					SET booking_history_id = {$fk_booking_history}, invoice_number = '{$invoice['ref']}'
+					WHERE rowid = {$row->rowid}";
+				$this->db->query($sql);
+			}
+		} else {
+			ApiBbusLog::appLog("api_booking: updateBbticket error");
+			throw new RestException(401, 'api_booking: updateBbticket error');
+		}
+	}
+
+	public function deletePreorder($preorder)
+	{
+		foreach ($preorder as $item) {
+			$sql = "DELETE FROM llx_booking_preorder WHERE rowid = {$item}";
+			$this->db->query($sql);
+		}
+	}
+
+	/**
+	 * curldeletePreorder
+	 *
+	 * Return an array with details
+	 *
+	 *
+	 * @param  	array 	$preorder			preorder
+	 * 
+	 * @url	POST curldeletePreorder
+	 * @access protected
+
+	 * @throws RestException 401 Not allowed
+	 * @throws RestException 404 Not found
+	 * @throws RestException 506 No available spaces
+	 * 
+	 */
+	public function curldeletePreorder($preorder)
+	{
+		foreach ($preorder as $item) {
+			$sql = "DELETE FROM llx_booking_preorder WHERE rowid = {$item}";
+			$this->db->query($sql);
+		}
+	}
+
+	public function eventErasuer()
 	{
 		global $user;
 		$limitDate = date("Y-m-d H:i:s", dol_now() - 1200);
@@ -792,6 +937,7 @@ class BookingApi extends DolibarrApi
 			$dataDelete = $this->db->query($sqlDelete);
 		}
 	}
+
 	/**
 	 * Increase Participants
 	 *
@@ -948,6 +1094,44 @@ class BookingApi extends DolibarrApi
 		];
 	}
 
+	/**
+	 * Get all free spaces on a selected date
+	 *
+	 * Return an array with details
+	 *
+	 * @return 	array|mixed data without useless information
+	 *
+	 * @param 	int 	type_id
+	 * @param 	string 	date_from
+	 * @param 	string 	date_to
+	 * @param 	int 	product_id
+	 * @param 	int 	participant_number
+	 * 
+	 * @url	POST getavailablespaces
+	 *
+	 * @throws RestException 401 Not allowed
+	 * @throws RestException 404 Not found
+	 */
+	public function getAvailableSpaces(int $type_id, string $date_from, string $date_to, int $product_id, int $participant_number)
+	{
+		$server_host = $this->getServerHost($type_id);
+		if ($server_host == 'excelia') {
+			ApiBbusLog::appLog("getAvailableSpaces");
+			return $this->localAvailablePlaces($date_from, $date_to, $product_id, $participant_number);
+		} else {
+			$params = compact('date_from', 'date_to', 'product_id', 'participant_number');
+			$postFields = json_encode($params);
+			return $this->curlRunner('bookingapi/localavailableplaces', $postFields, 'POST', true);
+		}
+	}
+
+	/* 	private function getServerHost($type_id)
+	{
+		$basicServices = new BasicServices($this->db);
+		$resultBS = $basicServices->fetch($type_id);
+		return $basicServices->server_host;
+	} */
+
 	/**
 	 * Get all free spaces on a selected date
 	 *
@@ -965,8 +1149,9 @@ class BookingApi extends DolibarrApi
 	 * @throws RestException 401 Not allowed
 	 * @throws RestException 404 Not found
 	 */
-	public function localAvailablePlaces($date_from, $date_to, $product_id, $participant_number)
+	public function localavailableplaces($date_from, $date_to, $product_id, $participant_number)
 	{
+		ApiBbusLog::appLog("localAvailablePlaces");
 		$array = [];
 		$date = new DateTime($date_to);
 		$date->modify('+1 day');
@@ -1006,165 +1191,115 @@ class BookingApi extends DolibarrApi
 		}
 		return $array;
 	}
-
-	/**
-	 * Get all free spaces on a selected date
-	 *
-	 * Return an array with details
-	 *
-	 * @return 	array|mixed data without useless information
-	 *
-	 * @param 	string 	sendId
-	 * @param 	int 	fk_event
-	 * @param 	int 	reservations
-	 * @param 	int 	product_id
-	 * 
-	 * @url	POST localcreatedpreorderobj
-	 * @access protected
-	 * @throws RestException 401 Not allowed
-	 * @throws RestException 404 Not found
-	 */
-	public function localcreatedpreorderobj($sendId, $fk_event, $reservations, $product_id)
-	{
-		$apiInvoiceHelper = new ApiInvoiceHelper;
-		$createdPreOrderOBJ = [];
-		for ($i = 1; $i <= $reservations; $i++) {
-			dol_include_once('/comm/action/class/actioncomm.class.php');
-			dol_include_once('/custom/booking/class/preorder.class.php');
-			$apiInvoiceHelper->increaseParticipant($fk_event);
-
-			$lines = $apiInvoiceHelper->getProductLines($product_id);
-			foreach ($lines as $line) {
-				$preOrderObj = new PreOrder($this->db);
-				$preOrderObj->ref = $this->generateRandomString();
-				$preOrderObj->fk_event = $fk_event;
-				$preOrderObj->fk_product = $product_id;
-				$result = $preOrderObj->create($this->user);
-				if ($result > 0) {
-					$createdPreOrderOBJ[] = [
-						'id' => $preOrderObj->id,
-						'ref' => $preOrderObj->ref,
-					];
-				} else {
-					ApiBbusLog::eventLog(json_encode(['error' => $preOrderObj->errors]));
-					ApiBbusLog::eventLog("Unsaved event: " . $fk_event);
-					throw new RestException(401, 'Unsaved event: ' . $fk_event);
-				}
-			}
-		}
-		return $createdPreOrderOBJ;
-	}
-
-	/**
-	 * Get all free spaces on a selected date
-	 *
-	 * Return an array with details
-	 *
-	 * @return 	array|mixed data without useless information
-	 *
-	 * @param 	int 	fk_event
-	 * @param 	int 	reservations
-	 * 
-	 * @url	POST nolocalemptyspaces
-	 *
-	 * @throws RestException 401 Not allowed
-	 * @throws RestException 404 Not found
-	 */
-	public function nolocalemptyspaces($fk_event, $reservations)
+	private function noLocalEmptySpaces($event_id, $reservations)
 	{
 		$sql = "SELECT ace.max_num, ace.buffer, ace.participants FROM llx_actioncomm as ac
         INNER JOIN llx_actioncomm_extrafields as ace ON ace.fk_object = ac.id
-        WHERE ac.id = {$fk_event}";
+        WHERE ac.id = {$event_id}";
 		$result = $this->db->query($sql);
 		if ($this->db->num_rows($result) == 0) {
-			return '{"result":1}';
+			return true;
 		}
 		while ($row = $this->db->fetch_object($result)) {
 			if ($row->participants >= $row->max_num) {
-				return '{"result":1}';
+				return true;
 			}
 			if ($row->participants + $reservations > $row->max_num + $row->buffer) {
-				return '{"result":1}';
+				return true;
 			}
 		}
-		return '{"result":0}';
+		return false;
 	}
 
 	/**
-	 * Validate and save invoice
+	 * curlnoLocalEmptySpaces
 	 *
 	 * Return an array with details
 	 *
 	 * @return 	array|mixed data without useless information
 	 *
-	 * @param 	string	$sendId				sendID
-	 * @param  	array 	$payment			Invoice payment
-	 * @param  	array 	$preorder			preorder
-	 * @param  	array 	$invoice			Invoice
-	 * @param  	string 	$cardPaymentLog		Card payment log data
+	 * @param 	int 	$fk_event			
+	 * @param 	int 	$reservations		
 	 * 
-	 * @url	POST localvalidateandsaveinvoice
+	 * @url	POST curlnoLocalEmptySpaces
 	 * @access protected
-
 	 * @throws RestException 401 Not allowed
 	 * @throws RestException 404 Not found
 	 * @throws RestException 506 No available spaces
 	 * 
 	 */
-	public function localValidateAndSaveInvoice($invoice, $preorder, $payment, $cardPaymentLog, $sendId)
+	public function curlnoLocalEmptySpaces($fk_event, $reservations)
 	{
-		global $user, $db;
-		$createdInvoiceData = [];
-		$apiInvoiceHelper = new ApiInvoiceHelper;
-		$bbusApi = new BBus();
-		foreach ($preorder as $order) {
-			$sql = "SELECT fk_product, fk_event  FROM llx_booking_preorder WHERE rowid = {$order}";
-			//print $sql . "\r\n";
-			$data = $db->query($sql);
-			if ($db->num_rows($data) > 0) {
-				while ($row = $db->fetch_object($data)) {
-					//print_r($row);
-					$lines = $apiInvoiceHelper->getProductLines($row->fk_product);
-					$createdInvoiceArray = $bbusApi->invoice($invoice, $lines, $payment, $cardPaymentLog = '', $sendId = '');
-					$createdInvoiceData[] = $createdInvoiceArray;
-					$bookingHistory = $this->saveEventData((int)$row->fk_event, $createdInvoiceArray['invoice']['id']);
-					$this->updateBbticket($bookingHistory, $createdInvoiceArray['invoice']);
-					$this->deletePreorder($preorder);
-				}
+		ApiBbusLog::appLog("curlnoLocalEmptySpaces");
+
+		$sql = "SELECT ace.max_num, ace.buffer, ace.participants FROM llx_actioncomm as ac
+        INNER JOIN llx_actioncomm_extrafields as ace ON ace.fk_object = ac.id
+        WHERE ac.id = {$fk_event}";
+		$result = $this->db->query($sql);
+		if ($this->db->num_rows($result) == 0) {
+			return true;
+		}
+		while ($row = $this->db->fetch_object($result)) {
+			if ($row->participants >= $row->max_num) {
+				return true;
+			}
+			if ($row->participants + $reservations > $row->max_num + $row->buffer) {
+				return true;
 			}
 		}
-		return $createdInvoiceData;
+		return false;
 	}
 
 	/**
-	 * Get back the product_id and event_id from llx_booking_preorder
+	 * curlcreatedpreorderobj
 	 *
 	 * Return an array with details
 	 *
 	 * @return 	array|mixed data without useless information
 	 *
-	 * @param 	int		$rowid				preorder->rowid
+	 * @param 	string 	$sendId			
+	 * @param 	int 	$fk_event			
+	 * @param 	int 	$reservations		
+	 * @param 	int 	$product_id			
 	 * 
-	 * @url	POST localpreorderarray
+	 * @url	POST curlcreatedpreorderobj
 	 * @access protected
-
 	 * @throws RestException 401 Not allowed
 	 * @throws RestException 404 Not found
 	 * @throws RestException 506 No available spaces
 	 * 
 	 */
-	public function localpreorderarray(int $rowid)
+	function curlcreatedpreorderobj($sendId, $fk_event, $reservations, $product_id)
 	{
-		global $user, $db;
-		$result = [];
-		$sql = "SELECT fk_product, fk_event  FROM llx_booking_preorder WHERE rowid = {$rowid}";
-		$data = $db->query($sql);
-		if ($db->num_rows($data) > 0) {
-			while ($row = $db->fetch_object($data)) {
-				$result = $row;
+		ApiBbusLog::appLog("curlcreatedpreorderobj");
+		$apiInvoiceHelper = new ApiInvoiceHelper;
+		$createdPreOrderOBJ = [];
+		for ($i = 1; $i <= $reservations; $i++) {
+			dol_include_once('/comm/action/class/actioncomm.class.php');
+			dol_include_once('/custom/booking/class/preorder.class.php');
+			$apiInvoiceHelper->increaseParticipant($fk_event);
+
+			$lines = $apiInvoiceHelper->getProductLines($product_id);
+			foreach ($lines as $line) {
+				$preOrderObj = new PreOrder($this->db);
+				$preOrderObj->ref = $this->generateRandomString();
+				$preOrderObj->fk_event = $fk_event;
+				$preOrderObj->fk_product = $product_id;
+				$result = $preOrderObj->create($this->user);
+				if ($result > 0) {
+					$createdPreOrderOBJ[] = [
+						'id' => $preOrderObj->id,
+						'ref' => $preOrderObj->ref,
+					];
+				} else {
+					ApiBbusLog::appLog(json_encode(['error' => $preOrderObj->errors]));
+					ApiBbusLog::appLog("Unsaved event: " . $fk_event);
+					throw new RestException(401, 'Unsaved event: ' . $fk_event);
+				}
 			}
 		}
-		return $result;
+		ApiBbusLog::appLog(json_encode($createdPreOrderOBJ));
+		return $createdPreOrderOBJ;
 	}
 
 	/**
@@ -1188,14 +1323,13 @@ class BookingApi extends DolibarrApi
 	 */
 	public function createbbticket(string $product_id, string $datec, string $facture_id)
 	{
-		global $db;
+		global $db, $conf;
 		$sql = "SELECT validperiod, occasions FROM " . $this->db->prefix() . "product_extrafields WHERE fk_object = " . $product_id;
 		$result = $db->query($sql);
 		while ($sqlDataResult = $db->fetch_array($result)) {
 			$validperiod = $sqlDataResult['validperiod'] ? $sqlDataResult['validperiod'] : 366;
 			$occasions = $sqlDataResult['occasions'];
 		}
-		$curlGroup = 10000;
 		$ticket = new BbTicket($db);
 		$ticket->fk_facture = null;
 		$ticket->bundle_id = $product_id;
@@ -1203,7 +1337,7 @@ class BookingApi extends DolibarrApi
 		$ticket->usage = '0';
 		$ticket->available_at = $this->getAvailableAtDate($datec, $validperiod);
 		$ticket->ticket_id = $product_id;
-		$ticket->fk_settlements_group_id = $curlGroup;
+		$ticket->fk_settlements_group_id = $conf->global->CURL_GROUP_ID;
 		$ticket->invoice_number = $facture_id;
 		if ($ticket->create($this->user) == -1) {
 			dol_syslog("Nem sikerult a ticketek mentese");
@@ -1216,265 +1350,4 @@ class BookingApi extends DolibarrApi
 		$available_at = date('Y-m-d H:i:s', strtotime($date . ' +' . $validperiod . ' days'));
 		return $available_at;
 	}
-
-	#-------------------------------------------------
-	#	CURL
-	#-------------------------------------------------
-
-	/**
-	 * Update data in BBticket
-	 *
-	 * Return an array with details
-	 *
-	 * @return 	array|mixed data without useless information
-	 *
-	 * @param 	string 	$fk_booking_history			//selected evet from llx_event
-	 * @param 	array 	$invoice			//facture rowid from llx_facture
-	 * 
-	 * @url	POST curlUpdateBbticket
-	 * @throws RestException 401 Not allowed
-	 * @throws RestException 404 Not found
-	 */
-	public function curlUpdateBbticket($fk_booking_history, $invoice)
-	{
-		global $user;
-		$sql = "SELECT rowid FROM llx_bbus_bbticket WHERE invoice_number = '{$invoice['id']}'";
-		ApiBbusLog::appLog("curlUpdateBbticket SELECT: {$sql}");
-		$data = $this->db->query($sql);
-		if ($this->db->num_rows($data) > 0) {
-			while ($row = $this->db->fetch_object($data)) {
-				$sql = "UPDATE llx_bbus_bbticket
-				SET booking_history_id = {$fk_booking_history}, invoice_number = '{$invoice['ref']}'
-				WHERE rowid = {$row->rowid}";
-				ApiBbusLog::appLog("curlUpdateBbticket UPDATE: {$sql}");
-				$this->db->query($sql);
-			}
-		}
-	}
-
-	/**
-	 * delete preorderrecord
-	 *
-	 * Return an array with details
-	 *
-	 * @return 	array|mixed data without useless information
-	 *
-	 * @param 	string 	$preorder_id			//selected evet from llx_event
-	 * 
-	 * @url	POST curlDeletePreorder
-	 * @throws RestException 401 Not allowed
-	 * @throws RestException 404 Not found
-	 */
-	public function curlDeletePreorder($rowid)
-	{
-		$sql = "DELETE FROM llx_booking_preorder WHERE rowid = {$rowid}";
-		ApiBbusLog::appLog("{$sql}");
-		$this->db->query($sql);
-	}
-
-	/**
-	 * Create BBticket record
-	 *
-	 * Return an array with details
-	 *
-	 * @return 	array|mixed data without useless information
-	 *
-	 * @param 	string		$product_id
-	 * @param 	string		$datec
-	 * @param 	string		$ref
-	 * 
-	 * @url	POST createbbticketmultiprinting
-	 * @access protected
-
-	 * @throws RestException 401 Not allowed
-	 * @throws RestException 404 Not found
-	 * @throws RestException 506 No available spaces
-	 * 
-	 */
-	public function createbbticketmultiprinting(string $product_id, string $datec, string $ref)
-	{
-		global $db;
-		$sql = "SELECT validperiod, occasions FROM " . $this->db->prefix() . "product_extrafields WHERE fk_object = " . $product_id;
-		$result = $db->query($sql);
-		while ($sqlDataResult = $db->fetch_array($result)) {
-			$validperiod = $sqlDataResult['validperiod'] ? $sqlDataResult['validperiod'] : 366;
-			$occasions = $sqlDataResult['occasions'];
-		}
-		$curlGroup = 10000;
-		$ticket = new BbTicket($db);
-		$ticket->fk_facture = null;
-		$ticket->bundle_id = $product_id;
-		$ticket->usable_occasions = $occasions;
-		$ticket->usage = '0';
-		$ticket->available_at = $this->getAvailableAtDate($datec, $validperiod);
-		$ticket->ticket_id = $product_id;
-		$ticket->fk_settlements_group_id = $curlGroup;
-		$ticket->invoice_number = $ref;
-		if ($ticket->create($this->user) == -1) {
-			dol_syslog("Nem sikerult a ticketek mentese");
-		}
-		$array['id'] = $ticket->id;
-		$array['ticket_id'] = $ticket->ticket_id;
-		return $array;
-	}
-
-	#-------------------------------------------------
-	#	OLD functions
-	#-------------------------------------------------
-
-	/**
-	 * Validate and save invoice
-	 * {"facture_id":41968,"cardPaymentLog":"","sendId":"K1pfFPlT","payment":{"datepaye":1716388707,"paymentid":14,"accountid":4,"closepaidinvoices":"yes"}}
-	 *
-	 * Return an array with details
-	 *
-	 * @return 	array|mixed data without useless information
-	 *
-	 * @param  	int 	$facture_id			//facture_id
-	 * @param  	array 	$payment			Invoice payment
-	 * @param  	string 	$cardPaymentLog		Card payment log data
-	 * @param 	string	$sendId				//ID
-	 * 
-	 * @url	POST validateandsaveinvoiceold
-	 * @access protected
-
-	 * @throws RestException 401 Not allowed
-	 * @throws RestException 404 Not found
-	 * @throws RestException 506 No available spaces
-	 * 
-	 */
-	public function validateandsaveinvoiceOld(int $facture_id, array $payment, string $cardPaymentLog = '', string $sendId = '')
-	{
-		global $user;
-		ApiBbusLog::eventLog("{$sendId} === VALIDATE INVOICE ===");
-		dol_syslog("{$sendId} === VALIDATE INVOICE ===", LOG_INFO, 0);
-		ApiBbusLog::eventLog("{$sendId} REQUEST: {$sendId}");
-		dol_syslog("{$sendId} REQUEST: {$sendId}", LOG_INFO, 0);
-		ApiBbusLog::eventLog("{$sendId} User: {$this->user->firstname} {$this->user->lastname} (ID: {$this->user->id})");
-		dol_syslog("{$sendId} User: {$this->user->firstname} {$this->user->lastname} (ID: {$this->user->id})", LOG_INFO, 0);
-		ApiBbusLog::eventLog("{$sendId} " . json_encode([
-			'facture_id' => $facture_id,
-			'payement' => $payment,
-			'cardPayementLog' => $cardPaymentLog,
-			'sendId' => $sendId,
-		]));
-		$products = [];
-		$invoiceObj = new Facture($this->db);
-		$apiInvoiceHelper = new ApiInvoiceHelper;
-		$invoiceObj->fetch($facture_id);
-
-		foreach ($invoiceObj->lines as $line) {
-			$product = $apiInvoiceHelper->loadProductToResult(get_object_vars($line));
-			if (!empty($product)) {
-				$products[] = $product;
-			}
-		}
-
-		foreach ($products as &$row) {
-			foreach ($invoiceObj->lines as $line) {
-				if ($line->product_ref == $row['ref']) {
-					//$row['price'] = $line->total_ttc;
-					$row['price'] = $line->multicurrency_total_ttc;
-					$row['total_tva'] = $line->total_tva;
-					//$row['total_tva'] = $line->multicurrency_total_tva;
-				}
-			}
-		}
-
-		$invoiceObj = $apiInvoiceHelper->validateInvoiceFromPROV($invoiceObj, $sendId, $facture_id);
-		$apiInvoiceHelper->setPaymentFromPROV($invoiceObj, $payment, $sendId);
-		if (!empty($cardPaymentLog)) {
-			$invoiceObj = $apiInvoiceHelper->saveCardPaymentLog($invoiceObj, $cardPaymentLog, $sendId);
-		}
-
-		ApiBbusLog::eventLog("{$sendId} Invoice created. ID: {$invoiceObj->id} REF: {$invoiceObj->ref} REQ: {$sendId}");
-		dol_syslog("{$sendId} Invoice created. ID: {$invoiceObj->id} REF: {$invoiceObj->ref} REQ: {$sendId}", LOG_INFO, 0);
-		//$bbApiLock->delete($user);
-
-		ApiBbusLog::eventLog("{$sendId}####################################################################");
-		dol_syslog("{$sendId}####################################################################", LOG_INFO, 0);
-
-		return [
-			'sendId' => $sendId,
-			'invoice' => [
-				'id' => $invoiceObj->id,
-				'ref' => $invoiceObj->ref,
-				'total' => $invoiceObj->multicurrency_total_ttc
-			],
-			'products' => $products,
-		];
-	}
-
-	/**
-	 * First step of the eventhandling
-	 * {"invoice":{"array_options_app_facture":1,"array_options_customer_data_zip":6782,"multicurrency_code":"HUF","fk_multicurrency":3,"mode_reglement_id":14,"cond_reglement_id":14,"fk_account":4},"fk_event":82586,"reservations":1,"sendId":12121212,"product_id":155}
-	 *
-	 * Return an array with details
-	 *
-	 * @return 	array|mixed data without useless information
-	 *
-	 * @param  array 	$invoice			Invoice data
-	 * @param 	int 	$fk_event			//selected evet from llx_event
-	 * @param 	int 	$reservations		//numbers of reservations
-	 * @param 	int 	$product_id			//Product
-	 * @param 	string	$sendId				//ID
-	 * 
-	 * @url	POST firsteventstepold
-	 * @access protected
-	 * @throws RestException 401 Not allowed
-	 * @throws RestException 404 Not found
-	 * @throws RestException 506 No available spaces
-	 * 
-	 */
-	public function firstEventStepOld(array $invoice, int $fk_event, int $reservations, int $product_id, string $sendId)
-	{
-		$eventHelper = new EventHelper;
-		if ($eventHelper->noEmptySpaces($fk_event, $reservations)) {
-			throw new RestException(506, 'No available spaces');
-		}
-
-		if (!DolibarrApiAccess::$user->rights->facture->creer) {
-			ApiBbusLog::eventLog("{$sendId} Insufficient rights");
-			throw new RestException(401, 'Insufficient rights');
-		}
-		/**
-		 * LOG SECTION
-		 */
-		ApiBbusLog::eventLog("{$sendId} === NEW INVOICE ===");
-		dol_syslog("{$sendId} === NEW INVOICE ===", LOG_INFO, 0);
-		ApiBbusLog::eventLog("{$sendId} REQUEST: {$sendId}");
-		dol_syslog("{$sendId} REQUEST: {$sendId}", LOG_INFO, 0);
-		ApiBbusLog::eventLog("{$sendId} User: {$this->user->firstname} {$this->user->lastname} (ID: {$this->user->id})");
-		dol_syslog("{$sendId} User: {$this->user->firstname} {$this->user->lastname} (ID: {$this->user->id})", LOG_INFO, 0);
-		ApiBbusLog::eventLog("{$sendId} " . json_encode([
-			'invoice' => $invoice,
-			'fk_event' => $fk_event,
-			'reservations' => $reservations,
-			'product_id' => $product_id,
-			'sendId' => $sendId,
-		]));
-
-		$apiInvoiceHelper = new ApiInvoiceHelper;
-		$createdInvoicePROVs = [];
-
-		for ($i = 1; $i <= $reservations; $i++) {
-			dol_include_once('/comm/action/class/actioncomm.class.php');
-			$apiInvoiceHelper->increaseParticipant($fk_event);
-			$invoiceObj = $apiInvoiceHelper->createInvoicePROV($invoice, $sendId);
-			$createdInvoicePROVs[] = [
-				'id' => $invoiceObj->id,
-				'ref' => $invoiceObj->ref,
-			];
-			ApiBbusLog::eventLog("{$sendId} - Invoice PROV created - " . $invoiceObj->id . ' - ' . $invoiceObj->ref);
-			$lines = $apiInvoiceHelper->getProductLines($product_id);
-			foreach ($lines as $line) {
-				$invoiceLineObj = $apiInvoiceHelper->addLineToInvoice($invoiceObj, $line, $sendId);
-				$this->saveEventData($fk_event, $invoiceObj->id, $fk_eventproduct = 1);
-			}
-			$invoiceLineObj->fetch_lines();
-		}
-		print_r($createdInvoicePROVs);
-		exit;
-		return $createdInvoicePROVs;
-	}
 }

+ 1476 - 0
custom/booking/class/api_booking.class_old.php

@@ -0,0 +1,1476 @@
+<?php
+/* Copyright (C) 2015   Jean-François Ferry     <jfefe@aternatik.fr>
+ * Copyright (C) 2023 Deák Ferenc
+ *
+ * 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/>.
+ */
+
+use Luracast\Restler\RestException;
+
+// dol_include_once('/booking/class/bookinglog.class.php');
+
+require_once DOL_DOCUMENT_ROOT . '/custom/bbus/class/api_bbus.class.php';
+require_once DOL_DOCUMENT_ROOT . '/custom/bbus/class/api_bbus_log.class.php';
+require_once DOL_DOCUMENT_ROOT . '/custom/bbus/class/apiinvoicehelper.class.php';
+require_once DOL_DOCUMENT_ROOT . '/custom/bbus/class/apiproductlisthelper.class.php';
+require_once DOL_DOCUMENT_ROOT . '/custom/booking/class/eventhelper.class.php';
+require_once DOL_DOCUMENT_ROOT . '/product/class/product.class.php';
+require_once DOL_DOCUMENT_ROOT . '/compta/facture/class/facture.class.php';
+require_once DOL_DOCUMENT_ROOT . '/comm/action/class/actioncomm.class.php';
+require_once DOL_DOCUMENT_ROOT . '/custom/booking/class/preorder.class.php';
+require_once DOL_DOCUMENT_ROOT . '/custom/bbus/class/api_curl.class.php';
+require_once DOL_DOCUMENT_ROOT . '/custom/bbus/class/basicservices.class.php';
+
+/**
+ * \file    booking/class/api_booking.class.php
+ * \ingroup booking
+ * \brief   File for API management of bookinglog.
+ */
+
+/**
+ * API class for booking bookinglog
+ *
+ * @class  DolibarrApiAccess {@requires user,external}
+ */
+class BookingApi extends DolibarrApi
+{
+
+	use CurlApi;
+
+	/**
+	 * @var BookingLog $bookinglog {@type BookingLog}
+	 */
+	public $bookinglog;
+	private User $user;
+
+	/**
+	 * Constructor
+	 *
+	 * @url     GET /
+	 *
+	 */
+	public function __construct()
+	{
+		global $db, $user;
+		$this->db = $db;
+		$this->user = $user;
+		// $this->bookinglog = new BookingLog($this->db);
+	}
+
+	#-------------------------------------------------
+	#	Vásárlási folyamat részei
+	#-------------------------------------------------
+
+	/**
+	 * Get all free spaces on a selected date
+	 *
+	 * Return an array with details
+	 *
+	 * @return 	array|mixed data without useless information
+	 *
+	 * @param 	string 	date_from
+	 * @param 	string 	date_to
+	 * @param 	int 	product_id
+	 * @param 	int 	participant_number
+	 * 
+	 * @url	POST getavailablespaces
+	 *
+	 * @throws RestException 401 Not allowed
+	 * @throws RestException 404 Not found
+	 */
+	public function getAvailableSpaces(string $date_from, string $date_to, int $product_id, int $participant_number, string $type_id = null)
+	{
+		ApiBbusLog::appLog("getAvailableSpaces");
+		/* ApiBbusLog::appLog("type_id: {$type_id}");
+		ApiBbusLog::appLog("date_from: {$date_from}");
+		ApiBbusLog::appLog("date_to: {$date_to}");
+		ApiBbusLog::appLog("product_id: {$product_id}");
+		ApiBbusLog::appLog("participant_number: {$participant_number}"); */
+		$basicServices = new BasicServices($this->db);
+		$resultBS = $basicServices->fetch($type_id);
+		if ($basicServices->server_host == 'excelia') {
+			return $this->localAvailablePlaces($date_from, $date_to, $product_id, $participant_number);
+		} else {
+			return $this->curlAvailablePlaces($date_from, $date_to, $product_id, $participant_number);
+		}
+	}
+
+	/**
+	 * First step of the eventhandling
+	 * {"fk_event":669,"reservations":1,"product_id":2,"sendId":"12121212"}
+	 *
+	 * Return an array with details
+	 *
+	 * @return 	array|mixed data without useless information
+	 *
+	 * @param 	int 	$fk_event			//selected evet from llx_event
+	 * @param 	int 	$reservations		//numbers of reservations
+	 * @param 	int 	$product_id			//Product
+	 * @param 	string	$sendId				//ID
+	 * 
+	 * @url	POST firsteventstep
+	 * @access protected
+	 * @throws RestException 401 Not allowed
+	 * @throws RestException 404 Not found
+	 * @throws RestException 506 No available spaces
+	 * 
+	 */
+	public function firstEventStep(int $fk_event, int $reservations, int $product_id, string $sendId)
+	{
+		ApiBbusLog::eventLog("fk_event: {$fk_event}");
+		ApiBbusLog::eventLog("reservations: {$reservations}");
+		ApiBbusLog::eventLog("product_id: {$product_id}");
+		ApiBbusLog::eventLog("sendId: {$sendId}");
+		$eventHelper = new EventHelper;
+		if ($eventHelper->noEmptySpaces($fk_event, $reservations)) {
+			throw new RestException(506, 'No available spaces');
+		}
+
+		if (!DolibarrApiAccess::$user->rights->facture->creer) {
+			ApiBbusLog::eventLog("{$sendId} Insufficient rights");
+			throw new RestException(401, 'Insufficient rights');
+		}
+		/**
+		 * LOG SECTION
+		 */
+		ApiBbusLog::eventLog("{$sendId} === NEW INVOICE ===");
+		dol_syslog("{$sendId} === NEW INVOICE ===", LOG_INFO, 0);
+		ApiBbusLog::eventLog("{$sendId} REQUEST: {$sendId}");
+		dol_syslog("{$sendId} REQUEST: {$sendId}", LOG_INFO, 0);
+		ApiBbusLog::eventLog("{$sendId} User: {$this->user->firstname} {$this->user->lastname} (ID: {$this->user->id})");
+		dol_syslog("{$sendId} User: {$this->user->firstname} {$this->user->lastname} (ID: {$this->user->id})", LOG_INFO, 0);
+		ApiBbusLog::eventLog("{$sendId} " . json_encode([
+			'fk_event' => $fk_event,
+			'reservations' => $reservations,
+			'product_id' => $product_id,
+			'sendId' => $sendId,
+		]));
+
+		$apiInvoiceHelper = new ApiInvoiceHelper;
+		$createdPreOrderOBJ = [];
+
+		for ($i = 1; $i <= $reservations; $i++) {
+			dol_include_once('/comm/action/class/actioncomm.class.php');
+			dol_include_once('/custom/booking/class/preorder.class.php');
+			$apiInvoiceHelper->increaseParticipant($fk_event);
+
+			$lines = $apiInvoiceHelper->getProductLines($product_id);
+			foreach ($lines as $line) {
+				$preOrderObj = new PreOrder($this->db);
+				$preOrderObj->ref = $this->generateRandomString();
+				$preOrderObj->fk_event = $fk_event;
+				$preOrderObj->fk_product = $product_id;
+				$result = $preOrderObj->create($this->user);
+				if ($result > 0) {
+					$createdPreOrderOBJ[] = [
+						'id' => $preOrderObj->id,
+						'ref' => $preOrderObj->ref,
+					];
+				} else {
+					ApiBbusLog::eventLog(json_encode(['error' => $preOrderObj->errors]));
+					ApiBbusLog::eventLog("Unsaved event: " . $fk_event);
+					throw new RestException(401, 'Unsaved event: ' . $fk_event);
+				}
+			}
+		}
+		return $createdPreOrderOBJ;
+	}
+
+	/**
+	 * Validate and save invoice
+	 * {"cardPaymentLog": "","sendId": "Xune5nQb","payment": {"datepaye": 1720005853,"paymentid": 4,"accountid": 2,"closepaidinvoices": "yes"},"preorder": [23]}
+	 *
+	 * Return an array with details
+	 *
+	 * @return 	array|mixed data without useless information
+	 *
+	 * @param 	string	$sendId				sendID
+	 * @param  	array 	$payment			Invoice payment
+	 * @param  	array 	$preorder			preorder
+	 * @param  	array 	$invoice			Invoice
+	 * @param  	string 	$cardPaymentLog		Card payment log data
+	 * 
+	 * @url	POST validateandsaveinvoice
+	 * @access protected
+
+	 * @throws RestException 401 Not allowed
+	 * @throws RestException 404 Not found
+	 * @throws RestException 506 No available spaces
+	 * 
+	 */
+	public function validateandsaveinvoice(string $sendId, array $payment, array $preorder, array $invoice, string $cardPaymentLog = '')
+	{
+		global $user, $db;
+		$createdInvoiceData = [];
+		$apiInvoiceHelper = new ApiInvoiceHelper;
+		$bbusApi = new BBus();
+		foreach ($preorder as $order) {
+			$sql = "SELECT fk_product, fk_event  FROM llx_booking_preorder WHERE rowid = {$order}";
+			//print $sql . "\r\n";
+			$data = $db->query($sql);
+			if ($db->num_rows($data) > 0) {
+				while ($row = $db->fetch_object($data)) {
+					//print_r($row);
+					$lines = $apiInvoiceHelper->getProductLinesWithoutDiscount($row->fk_product);
+					$createdInvoiceArray = $bbusApi->invoice($invoice, $lines, $payment, $cardPaymentLog = '', $sendId = '');
+					$createdInvoiceData[] = $createdInvoiceArray;
+					$bookingHistory = $this->saveEventData((int)$row->fk_event, $createdInvoiceArray['invoice']['ref'], $createdInvoiceArray['invoice']['id']);
+					$this->updateBbticket($bookingHistory, $createdInvoiceArray['invoice']);
+					$this->deletePreorder($preorder);
+				}
+			}
+		}
+		return $createdInvoiceData;
+	}
+
+	/**
+	 * Get types of a bookable events
+	 *
+	 * Return an array with bookable events type list
+	 *
+	 * @return 	array|mixed data without useless information
+	 *
+	 * @url	GET types
+	 *
+	 * @throws RestException 401 Not allowed
+	 * @throws RestException 404 Not found
+	 */
+	public function types()
+	{
+		dol_include_once('/eventwizard/class/eventdetails.class.php');
+		$EventDetails = new EventDetails($this->db);
+		return $EventDetails->fields['type']['arrayofkeyval'];
+		if (!DolibarrApiAccess::$user->rights->booking->types->read) {
+			throw new RestException(401);
+		}
+
+		// dol_include_once('/booking/class/bookinglog.class.php');
+
+		// $result = $this->bookinglog->fetch($id);
+		// if (!$result) {
+		// throw new RestException(404, 'BookingLog not found');
+		// }
+
+		// if (!DolibarrApi::_checkAccessToResource('bookinglog', $this->bookinglog->id, 'booking_bookinglog')) {
+		// throw new RestException(401, 'Access to instance id='.$this->bookinglog->id.' of object not allowed for login '.DolibarrApiAccess::$user->login);
+		// }
+
+		// return $this->_cleanObjectDatas($this->bookinglog);
+	}
+
+	/**
+	 * Get bookable events
+	 *
+	 * Return an array with bookable events list
+	 *
+	 * @return 	array|mixed data without useless information
+	 * 
+	 * @param 	int 		$onlyBookable 
+	 * @param 	int 		$withDetails 
+	 * @param 	int 		$withDates 
+	 * @param 	int 		$withAviability
+	 * @url	GET events
+	 *
+	 * @throws RestException 401 Not allowed
+	 * @throws RestException 404 Not found
+	 */
+	public function events($onlyBookable = 1, $withDetails = 0, $withDates = 0, $withAviability = 0)
+	{
+		global $db, $conf;
+		// if (!DolibarrApiAccess::$user->rights->booking->events->read) {
+		// throw new RestException(401);
+		// }
+
+		$obj_ret = [];
+
+		// if (!DolibarrApiAccess::$user->rights->agenda->myactions->read) {
+		// throw new RestException(401, "Insufficient rights to read events");
+		// }
+
+		$sql = "SELECT DISTINCT ed.rowid as id";
+		if (!empty($conf->societe->enabled)) {
+			// if ((!DolibarrApiAccess::$user->rights->societe->client->voir && !$socid) || $search_sale > 0) {
+			// $sql .= ", sc.fk_soc, sc.fk_user"; // We need these fields in order to filter by sale (including the case where the user can only see his prospects)
+			// }
+		}
+		$sql .= " ,ed.label ";
+		$sql .= " ,eld.label as from"; //... ??
+		$sql .= " ,ela.label as to"; //...
+
+		$sql .= " FROM " . MAIN_DB_PREFIX . "actioncomm as t";
+		$sql .= " LEFT JOIN " . MAIN_DB_PREFIX . "eventwizard_eventdetails ed ON ed.rowid = t.fk_element";
+		$sql .= " LEFT JOIN " . MAIN_DB_PREFIX . "eventwizard_eventlocation eld ON eld.rowid = ed.fk_elventlocation_departure";
+		$sql .= " LEFT JOIN " . MAIN_DB_PREFIX . "eventwizard_eventlocation ela ON ela.rowid = ed.fk_elventlocation_arrival";
+		$sql .= " WHERE code = 'AC_EVENT' ";
+		$sql .= " AND t.elementtype = 'eventdetails@eventwizard'";
+		if ($onlyBookable) {
+			$sql .= " AND t.datep >  CURRENT_TIMESTAMP";
+		}
+		$result = $this->db->query($sql);
+
+		if ($result) {
+			$i = 0;
+			// $num = $this->db->num_rows($result);
+			// $min = min($num, ($limit <= 0 ? $num : $limit));
+			while ($event = $this->db->fetch_object($result)) {
+				if ($withDetails) {
+					$event->details = $this->details($event->id);
+				}
+				if ($withDates) {
+					//... $withAviability
+					$event->dates = $this->dates($event->id);
+				}
+				$obj_ret[] = $event;
+			}
+		} else {
+			throw new RestException(503, 'Error when retrieve Agenda Event list : ' . $this->db->lasterror());
+		}
+		if (!count($obj_ret)) {
+			throw new RestException(404, 'No Agenda Event found');
+		}
+		return $obj_ret;
+	}
+
+	/**
+	 * Get event dates
+	 *
+	 * Return an array with event dates list
+	 *
+	 * @return 	array|mixed data without useless information
+	 *
+	 * @param 	int 		$id 
+	 * @param 	int 		$onlyBookable 
+	 * @param 	string 		$json 
+	 * @url	GET dates
+	 *
+	 * @throws RestException 401 Not allowed
+	 * @throws RestException 404 Not found
+	 */
+	public function dates($id, $onlyBookable = 1, $json = null)
+	{
+		global $db, $conf;
+		// if (!DolibarrApiAccess::$user->rights->booking->events->read) {
+		// throw new RestException(401);
+		// }
+
+		$obj_ret = [];
+
+		// if (!DolibarrApiAccess::$user->rights->agenda->myactions->read) {
+		// throw new RestException(401, "Insufficient rights to read events");
+		// }
+
+		$sql = "SELECT t.id ";
+		if (!empty($conf->societe->enabled)) {
+			// if ((!DolibarrApiAccess::$user->rights->societe->client->voir && !$socid) || $search_sale > 0) {
+			// $sql .= ", sc.fk_soc, sc.fk_user"; // We need these fields in order to filter by sale (including the case where the user can only see his prospects)
+			// }
+		}
+		$sql .= " ,ed.label, t.note ";
+		$sql .= " ,t.datep as start, t.datep2 as end";
+		$sql .= " ,eld.label as from"; //... ??
+		$sql .= " ,ela.label as to"; //...
+
+		$sql .= " FROM " . MAIN_DB_PREFIX . "actioncomm as t";
+		// if (!empty($conf->societe->enabled)) {
+		// if ((!DolibarrApiAccess::$user->rights->societe->client->voir && !$socid) || $search_sale > 0) {
+		// $sql .= ", ".MAIN_DB_PREFIX."societe_commerciaux as sc"; // We need this table joined to the select in order to filter by sale
+		// }
+		// }
+		$sql .= " LEFT JOIN " . MAIN_DB_PREFIX . "eventwizard_eventdetails ed ON ed.rowid = t.fk_element";
+		$sql .= " LEFT JOIN " . MAIN_DB_PREFIX . "eventwizard_eventlocation eld ON eld.rowid = ed.fk_elventlocation_departure";
+		$sql .= " LEFT JOIN " . MAIN_DB_PREFIX . "eventwizard_eventlocation ela ON ela.rowid = ed.fk_elventlocation_arrival";
+		// $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."eventwizard_eventoption eo ON el.rowid = ed.fk_element";
+		// $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."eventwizard_eventproduct eo ON el.rowid = ed.fk_element";
+		// $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."eventwizard_ eo ON el.rowid = ed.fk_element";
+		// $sql .= ' WHERE t.entity IN ('.getEntity('agenda').')';
+		$sql .= " WHERE code = 'AC_EVENT' ";
+		$sql .= " AND t.fk_element = " . (int) $this->db->escape($id);
+		$sql .= " AND t.elementtype = 'eventdetails@eventwizard'";
+		$sql .= " AND t.datep >  CURRENT_TIMESTAMP";
+		// if (!empty($conf->societe->enabled)) {
+		// if ((!DolibarrApiAccess::$user->rights->societe->client->voir && !$socid) || $search_sale > 0) {
+		// $sql .= " AND t.fk_soc = sc.fk_soc";
+		// }
+		// }
+		// if ($user_ids) {
+		// $sql .= " AND t.fk_user_action IN (".$this->db->sanitize($user_ids).")";
+		// }
+		// if ($socid > 0) {
+		// $sql .= " AND t.fk_soc = ".((int) $socid);
+		// }
+		// Insert sale filter
+		// if ($search_sale > 0) {
+		// $sql .= " AND sc.fk_user = ".((int) $search_sale);
+		// }
+		// Add sql filters
+		// if ($sqlfilters) {
+		// $errormessage = '';
+		// if (!DolibarrApi::_checkFilters($sqlfilters, $errormessage)) {
+		// throw new RestException(503, 'Error when validating parameter sqlfilters -> '.$errormessage);
+		// }
+		// $regexstring = '\(([^:\'\(\)]+:[^:\'\(\)]+:[^\(\)]+)\)';
+		// $sql .= " AND (".preg_replace_callback('/'.$regexstring.'/', 'DolibarrApi::_forge_criteria_callback', $sqlfilters).")";
+		// }
+
+		// $sql .= $this->db->order($sortfield, $sortorder);
+		// if ($limit) {
+		// if ($page < 0) {
+		// $page = 0;
+		// }
+		// $offset = $limit * $page;
+
+		// $sql .= $this->db->plimit($limit + 1, $offset);
+		// }
+		$result = $this->db->query($sql);
+
+		if ($result) {
+			$i = 0;
+			$num = $this->db->num_rows($result);
+			// $min = min($num, ($limit <= 0 ? $num : $limit));
+			while ($i < $num) {
+				$obj_ret[] = $this->db->fetch_object($result);
+				$i++;
+			}
+		} else {
+			throw new RestException(503, 'Error when retrieve Agenda Event list : ' . $this->db->lasterror());
+		}
+		if (!count($obj_ret)) {
+			throw new RestException(404, 'No Agenda Event found');
+		}
+		return $obj_ret;
+	}
+
+	/**
+	 * Post booking (draft)
+	 *
+	 * Return an array with draft bookings list
+	 *
+	 * @return 	array|mixed data without useless information
+	 *
+	 * @param 	int 	$event
+	 * @param 	array 	$details 
+	 * @url	POST set
+	 *
+	 * @access protected
+	 * @throws RestException 401 Not allowed
+	 * @throws RestException 404 Not found
+	 */
+	public function set($event, $details)
+	{
+		if (!DolibarrApiAccess::$user->rights->booking->events->write) {
+			throw new RestException(401);
+		}
+	}
+
+	/**
+	 * Post booking validation
+	 *
+	 * Return an array with bookings list
+	 *
+	 * @return 	array|mixed data without useless information
+	 *
+	 * @param 	int 	$event
+	 * @param 	array 	$drafts 
+	 * @url	POST validate
+	 *
+	 * @access protected
+	 * @throws RestException 401 Not allowed
+	 * @throws RestException 404 Not found
+	 */
+	public function validate($event, $drafts)
+	{
+		if (!DolibarrApiAccess::$user->rights->booking->events->write) {
+			throw new RestException(401);
+		}
+	}
+
+	/**
+	 * Get bookings list
+	 *
+	 * Return an array with the user's bookings list
+	 *
+	 * @return 	array|mixed data without useless information
+	 *
+	 * @url	POST bookings
+	 *
+	 * @access protected
+	 * @throws RestException 401 Not allowed
+	 * @throws RestException 404 Not found
+	 */
+	public function bookings()
+	{
+		if (!DolibarrApiAccess::$user->rights->booking->events->write) {
+			throw new RestException(401);
+		}
+	}
+
+	/**
+	 * Get cron to clean booking draftInvoices
+	 *
+	 * Return an array with cleaned list
+	 *
+	 * @return 	array|mixed data without useless information
+	 *
+	 * @url	GET cron
+	 *
+	 * @access protected
+	 * @throws RestException 401 Not allowed
+	 * @throws RestException 404 Not found
+	 */
+	public function cron()
+	{
+		if (!DolibarrApiAccess::$user->rights->booking->events->write) {
+			throw new RestException(401);
+		}
+	}
+
+	/**
+	 * Get details of a bookable event
+	 *
+	 * Return an array with details
+	 *
+	 * @return 	array|mixed data without useless information
+	 *
+	 * @param 	int 	$id
+	 * @url	GET details
+	 *
+	 * @access protected
+	 * @throws RestException 401 Not allowed
+	 * @throws RestException 404 Not found
+	 */
+	public function details($id)
+	{
+		$details = [
+			'tmp' => [],
+			'product' => [],
+			'min' => 0,
+			'id_event' => $id,
+			// 'variants' => []
+		];
+		$variants = [];
+		dol_include_once('/eventwizard/class/eventdetails.class.php');
+		$EventDetails = new EventDetails($this->db);
+		if ($EventDetails->fetch($id)) {
+			$sql = "SELECT ep.rowid ,ep.fk_eventdetails, ep.fk_product, ep.type, ep.amount, ep.qty ";
+			$sql .= " , p.label, p.price "; //price	price_ttc	price_min	price_min_ttc
+			$sql .= " FROM " . MAIN_DB_PREFIX . "eventwizard_eventproduct ep ";
+			$sql .= " LEFT JOIN " . MAIN_DB_PREFIX . "product p ON p.rowid = ep.fk_product ";
+			// $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."product_attribute_combination ac ON ac.fk_product_parent = ep.fk_product ";
+			// $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."eventwizard_eventoption eo ON eo.rowid = ep.fk_eventoption ";
+			// $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."eventwizard_eventdetails ed ON ed.rowid = ep.fk_eventdetails ";
+
+			$sql .= " WHERE ep.fk_eventdetails = " . (int) $this->db->escape($id);
+			// return $sql;
+			$result = $this->db->query($sql);
+			if ($result) {
+				$variants_ids = [];
+				while ($d = $this->db->fetch_object($result)) {
+					$variants_ids[] = $d->fk_product;
+					// if(is_null($d->fk_product_child)){}
+					$d->variants = [];
+					// $d->minP = (is_null($d->amount))?(float)$d->price:(float)$d->amount;
+					$details['tmp']['' . $d->fk_product] = $d;
+				}
+
+				$sql2 = "SELECT p.rowid, p.label, p.price ";
+				$sql2 .= ", ac.fk_product_parent, ac.fk_product_child, ac.variation_price, ac.variation_price_percentage "; //	variation_price	variation_price_percentage	variation_weight	variation_ref_ext	entity
+				$sql2 .= "FROM " . MAIN_DB_PREFIX . "product_attribute_combination ac ";
+				$sql2 .= " LEFT JOIN " . MAIN_DB_PREFIX . "product p ON ac.fk_product_child = p.rowid ";
+				$sql2 .= " WHERE ac.fk_product_parent IN (" . implode(",", $variants_ids) . ") ";
+
+				$result2 = $this->db->query($sql2);
+				if ($result2) {
+					while ($v = $this->db->fetch_object($result2)) {
+						$d = $details['tmp']['' . $v->fk_product_parent];
+						$d->variants[] = $this->product2out($v);
+						if (!is_null($d->amount)) { //... - ??? %?
+							$d->minP = (float) $d->amount;
+						} elseif (!isset($d->minP)) {
+							$d->minP = $v->price;
+						} elseif ($d->minP > $v->price) {
+							$d->minP = $v->price;
+						}
+						$details['tmp']['' . $v->fk_product_parent] = $d;
+					}
+				}
+				foreach ($details['tmp'] as $k => $v) {
+					$p = $this->product2out($v);
+					$p["minP"] = (is_null($v->amount)) ? (!isset($d->minP)) ? (float) $v->price : (float) $v->minP : (float) $v->amount;
+					$p["variants"] = $v->variants;
+					$details['product'][] = $p;
+					if ($p["type"] == 1) {
+						$details['min'] += $p["minP"];
+					}
+				}
+				unset($details['tmp']);
+			} else {
+				throw new RestException(503, 'Error when retrieve Agenda Event list : ' . $this->db->lasterror());
+			}
+			// $EventDetails->getLinesArray();
+			// print_r($EventDetails->lines);
+			return $details;
+
+			//$variations
+			// $variations = 
+
+		}
+	}
+
+	protected function product2out($product)
+	{
+		return [
+			"id" => $product->fk_product,
+			"type" => $product->type, //1,2,3
+			"fixed_price" => $product->amount,
+			"max" => $product->qty,
+			"label" => $product->label,
+			"price" => $product->price,
+		];
+	}
+
+	/**
+	 * Get all products by type
+	 *
+	 * Return an array with details
+	 *
+	 * @return 	array|mixed data without useless information
+	 *
+	 * @param 	int 	$type_id
+	 * @param 	string 	$from_date
+	 * @param 	string 	$to_date
+	 * 
+	 * @url	POST getallavailableproducts
+	 *
+	 * @throws RestException 401 Not allowed
+	 * @throws RestException 404 Not found
+	 */
+	public function getAllAvailableProducts(int $type_id, string $from_date, string $to_date)
+	{
+		$date = new DateTime($to_date);
+		$date->modify('+1 day');
+		$to_date = $date->format('Y-m-d');
+		$TMPArray = [];
+		$productsArray = [];
+		$sql = "SELECT 
+		pr.rowid
+		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 ed.rowid = ac.fk_element
+		INNER JOIN llx_eventwizard_eventproduct as ep ON ep.fk_eventdetails = ed.rowid
+		INNER JOIN llx_product as pr ON pr.rowid = ep.fk_product
+		where ac.datep > '{$from_date} 00:00:00' AND ac.datep2 < '{$to_date} 00:00:00'
+		AND ac.code = 'AC_EVENT'
+		AND ed.type = {$type_id}
+		AND ace.max_num - COALESCE(ace.participants, 0) > 1
+		GROUP BY pr.rowid";
+		$result = $this->db->query($sql);
+		if ($this->db->num_rows($result) > 0) {
+			while ($row = $this->db->fetch_object($result)) {
+				$TMPArray[] = $row->rowid;
+			}
+			foreach ($TMPArray as $productItem) {
+				$ApiProductListHelper = new ApiProductListHelper();
+				$array = $ApiProductListHelper->list('t.ref', 'ASC', '', '', '', '', "(t.rowid:=:{$productItem})");
+				$productsArray[] = $array[0];
+			}
+		}
+
+		return $productsArray;
+	}
+
+	function generateRandomString($length = 10)
+	{
+		$characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
+		$charactersLength = strlen($characters);
+		$randomString = '';
+		for ($i = 0; $i < $length; $i++) {
+			$randomString .= $characters[rand(0, $charactersLength - 1)];
+		}
+
+		return $randomString;
+	}
+
+	/**
+	 * Save event data in Bookinghistory
+	 *
+	 * Return an array with details
+	 *
+	 * @return 	array|mixed data without useless information
+	 *
+	 * @param 	string 	$fk_event			//selected evet from llx_event
+	 * @param 	string 	$fk_facture			//facture rowid from llx_facture
+	 * @param 	string 	$fk_eventproduct	//eventproduct rowid from llx_eventwizard_eventproduct
+	 * @param 	string 	$ref
+	 * 
+	 * @url	POST saveeventdata
+	 * @access protected
+	 * @throws RestException 401 Not allowed
+	 * @throws RestException 404 Not found
+	 */
+	public function saveEventData(string $fk_event, string $ref, string $fk_facture = null, string $fk_eventproduct = null)
+	{
+		dol_include_once('/custom/booking/class/bookinghistory.class.php');
+		dol_include_once('/comm/action/class/actioncomm.class.php');
+		$actionCommObj = new ActionComm($this->db);
+		$sql = "SELECT fk_element, datep, datep2 FROM " . MAIN_DB_PREFIX . $actionCommObj->table_element . " WHERE id = {$fk_event}";
+		$result = $this->db->query($sql);
+		if ($this->db->num_rows($result) > 0) {
+			$row = $this->db->fetch_object($result);
+			$BookingHistory = new BookingHistory($this->db);
+			$BookingHistory->fk_event = (int)$fk_event;
+			$BookingHistory->fk_facture = (int)$fk_facture;
+			$BookingHistory->fk_event_detail = $row->fk_element;
+			$BookingHistory->fk_eventproduct = (int)$fk_eventproduct;
+			$BookingHistory->date_start = strtotime($row->datep);
+			$BookingHistory->date_end = strtotime($row->datep2);
+			$BookingHistory->invoice_number = $ref;
+			$result = $BookingHistory->create($this->user);
+			if ($result > 0) {
+				return $BookingHistory->id;
+			} else {
+				throw new RestException(401, 'Unsaved');
+			}
+		} else {
+			throw new RestException(401, 'No Event record');
+		}
+	}
+
+	public function updateBbticket($fk_booking_history, $invoice)
+	{
+		global $user;
+		$sql = "SELECT rowid FROM llx_bbus_bbticket WHERE fk_facture = {$invoice['id']}";
+		$data = $this->db->query($sql);
+		if ($this->db->num_rows($data) > 0) {
+			while ($row = $this->db->fetch_object($data)) {
+				$sql = "UPDATE llx_bbus_bbticket
+				SET booking_history_id = {$fk_booking_history}, invoice_number = '{$invoice['ref']}'
+				WHERE rowid = {$row->rowid}";
+				$this->db->query($sql);
+			}
+		}
+	}
+
+	public function deletePreorder($preorder)
+	{
+		foreach ($preorder as $item) {
+			$sql = "DELETE FROM llx_booking_preorder WHERE rowid = {$item}";
+			$this->db->query($sql);
+		}
+	}
+
+	public function eventErasuer()
+	{
+		global $user;
+		$limitDate = date("Y-m-d H:i:s", dol_now() - 1200);
+		$sql = "SELECT * FROM llx_booking_preorder WHERE date_creation < '{$limitDate}'";
+		//print $sql;exit;
+		$data = $this->db->query($sql);
+		if ($this->db->num_rows($data) > 0) {
+			while ($row = $this->db->fetch_object($data)) {
+				//print_r($row);
+				$actioncommObj = new ActionComm($this->db);
+				$resultActionComm = $actioncommObj->fetch($row->fk_event);
+				$actioncommObj->array_options['options_participants'] = $actioncommObj->array_options['options_participants'] - 1;
+				$actioncommObj->update($user);
+			}
+			//exit;
+			$sqlDelete = "DELETE FROM llx_booking_preorder WHERE date_creation < '{$limitDate}'";
+			$dataDelete = $this->db->query($sqlDelete);
+		}
+	}
+	/**
+	 * Increase Participants
+	 *
+	 * Return an array with details
+	 *
+	 * @return 	array|mixed data without useless information
+	 *
+	 * @param 	int 	$event_id			//rowid of evet from llx_event
+	 * 
+	 * @url	POST increaseparticipant
+	 *
+	 * @throws RestException 401 Not allowed
+	 * @throws RestException 404 Not found
+	 */
+	public function increaseParticipant(int $event_id)
+	{
+		dol_include_once('/comm/action/class/actioncomm.class.php');
+		global $user;
+		$actionComObj = new ActionComm($this->db);
+		$actionComObj->fetch($event_id);
+		$max_num = (int) $actionComObj->array_options['options_max_num'];
+		$buffer = (int) $actionComObj->array_options['options_buffer'];
+		$participants = (int) $actionComObj->array_options['options_participants'];
+		$increasedParticipants = $participants + 1;
+		if ($increasedParticipants > ($max_num + $buffer)) {
+			return 'full';
+		} elseif (($increasedParticipants > $max_num) && ($increasedParticipants <= ($max_num + $buffer))) {
+			$actionComObj->array_options['options_participants'] = $increasedParticipants;
+			$actionComObj->update($user);
+			return 'Buffer';
+		} else {
+			$actionComObj->array_options['options_participants'] = $increasedParticipants;
+			$actionComObj->update($user);
+			return 'OK';
+		}
+	}
+
+	/**
+	 * Reduce Participants
+	 *
+	 * Return an array with details
+	 *
+	 * @return 	array|mixed data without useless information
+	 *
+	 * @param 	int 	$event_id			//rowid of evet from llx_event
+	 * 
+	 * @url	POST reduceparticipant
+	 *
+	 * 
+	 * @throws RestException 401 Not allowed
+	 * @throws RestException 404 Not found
+	 */
+	public function reduceParticipant(int $event_id)
+	{
+		global $user;
+		dol_include_once('/comm/action/class/actioncomm.class.php');
+		$actionComObj = new ActionComm($this->db);
+		$actionComObj->fetch($event_id);
+		$participants = (int) $actionComObj->array_options['options_participants'];
+		$reducedParticipants = $participants - 1;
+		$actionComObj->array_options['options_participants'] = $reducedParticipants < 0 ? 0 : $reducedParticipants;
+		$actionComObj->update($user);
+		return 'OK';
+	}
+
+	/**
+	 * Create invoice
+	 * 
+	 * @param  array 	$invoice			Invoice data
+	 * @param  array 	$lines				Invoice lines
+	 * @param  array 	$payment			Invoice payment
+	 * @param  string 	$eventid			Event ID
+	 * @param  string 	$cardPaymentLog		Card payment log data
+	 * 
+	 * @access protected
+	 * @return array|mixed Data without useless information
+	 * 
+	 * @url POST /invoice
+	 */
+	public function invoice(array $invoice, array $lines, array $payment, string $cardPaymentLog = '', string $eventid = '', string $sendId = '')
+	{
+		if (empty($sendId)) {
+			$sendId = substr(md5(rand()), 0, 8);
+		}
+
+		/**
+		 * LOG SECTION
+		 */
+		ApiBbusLog::appLog("{$sendId} === NEW INVOICE ===");
+		dol_syslog("{$sendId} === NEW INVOICE ===", LOG_INFO, 0);
+		ApiBbusLog::appLog("{$sendId} REQUEST: {$sendId}");
+		dol_syslog("{$sendId} REQUEST: {$sendId}", LOG_INFO, 0);
+		ApiBbusLog::appLog("{$sendId} User: {$this->user->firstname} {$this->user->lastname} (ID: {$this->user->id})");
+		dol_syslog("{$sendId} User: {$this->user->firstname} {$this->user->lastname} (ID: {$this->user->id})", LOG_INFO, 0);
+		ApiBbusLog::appLog("{$sendId} " . json_encode([
+			'invoice' => $invoice,
+			'lines' => $lines,
+			'payment' => $payment,
+			'eventid' => $eventid,
+			'cardPaymentLog' => $cardPaymentLog
+		]));
+
+		/**
+		 * CHECK RIGHTS
+		 */
+		if (!DolibarrApiAccess::$user->rights->facture->creer) {
+			ApiBbusLog::appLog("{$sendId} Insufficient rights");
+			throw new RestException(401, 'Insufficient rights');
+		}
+
+
+		$apiInvoiceHelper = new ApiInvoiceHelper;
+		/**
+		 * handle invoice basic data
+		 */
+		$invoiceObj = $apiInvoiceHelper->createInvoice($invoice, $sendId);
+		/**
+		 * handle invoice line(s)
+		 */
+		$products = [];
+
+		//print $eventid;exit;
+
+		foreach ($lines as $line) {
+			$invoiceObj = $apiInvoiceHelper->addLineToInvoice($invoiceObj, $line, $sendId);
+			$this->increaseParticipant((int) $eventid);
+			$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->total_ttc;
+					$row['price'] = $line->multicurrency_total_ttc;
+					$row['total_tva'] = $line->total_tva;
+					//$row['total_tva'] = $line->multicurrency_total_tva;
+				}
+			}
+		}
+
+		return [
+			'sendId' => $sendId,
+			'invoice' => [
+				'id' => $invoiceObj->id,
+				'ref' => $invoiceObj->ref,
+				'total' => $invoiceObj->multicurrency_total_ttc
+			],
+			'products' => $products,
+		];
+	}
+
+	/**
+	 * Get all free spaces on a selected date
+	 *
+	 * Return an array with details
+	 *
+	 * @return 	array|mixed data without useless information
+	 *
+	 * @param 	string 	date_from
+	 * @param 	string 	date_to
+	 * @param 	int 	product_id
+	 * @param 	int 	participant_number
+	 * 
+	 * @url	POST localavailableplaces
+	 *
+	 * @throws RestException 401 Not allowed
+	 * @throws RestException 404 Not found
+	 */
+	public function localAvailablePlaces($date_from, $date_to, $product_id, $participant_number)
+	{
+		$array = [];
+		$date = new DateTime($date_to);
+		$date->modify('+1 day');
+		$date_to = $date->format('Y-m-d');
+		$sql = "SELECT 
+		ac.id, 
+		ac.datep, 
+		ace.max_num, 
+		ace.participants,
+		ace.buffer
+		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}
+		AND ac.datep > '{$date_from} 00:00:00' 
+		AND ac.datep2 < '{$date_to} 00:00:00'
+		ORDER BY ac.datep ASC";
+		$result = $this->db->query($sql);
+		while ($row = $this->db->fetch_object($result)) {
+			$max_num = $row->max_num;
+			$buffer = $row->buffer;
+			$participants = $row->participants;
+			$date = strtotime($row->datep);
+			$element['event_id'] = $row->id;
+			//$element['date'] = date("Y-m-d", $date);
+			//$element['time'] = date("H:i", $date);
+			$element['participants'] = is_null($participants) ? 0 : (int) $participants;
+			$element['max_num'] = $max_num;
+			$element['buffer'] = $buffer;
+			if ($max_num > $participants) {
+				if ($max_num + $buffer > $participants + $participant_number) {
+					$array[date("Y-m-d", $date)][date("H:i", $date)] = $element;
+				}
+			}
+		}
+		return $array;
+	}
+
+	/**
+	 * Get all free spaces on a selected date
+	 *
+	 * Return an array with details
+	 *
+	 * @return 	array|mixed data without useless information
+	 *
+	 * @param 	string 	sendId
+	 * @param 	int 	fk_event
+	 * @param 	int 	reservations
+	 * @param 	int 	product_id
+	 * 
+	 * @url	POST localcreatedpreorderobj
+	 * @access protected
+	 * @throws RestException 401 Not allowed
+	 * @throws RestException 404 Not found
+	 */
+	public function localcreatedpreorderobj($sendId, $fk_event, $reservations, $product_id)
+	{
+		$apiInvoiceHelper = new ApiInvoiceHelper;
+		$createdPreOrderOBJ = [];
+		for ($i = 1; $i <= $reservations; $i++) {
+			dol_include_once('/comm/action/class/actioncomm.class.php');
+			dol_include_once('/custom/booking/class/preorder.class.php');
+			$apiInvoiceHelper->increaseParticipant($fk_event);
+
+			$lines = $apiInvoiceHelper->getProductLines($product_id);
+			foreach ($lines as $line) {
+				$preOrderObj = new PreOrder($this->db);
+				$preOrderObj->ref = $this->generateRandomString();
+				$preOrderObj->fk_event = $fk_event;
+				$preOrderObj->fk_product = $product_id;
+				$result = $preOrderObj->create($this->user);
+				if ($result > 0) {
+					$createdPreOrderOBJ[] = [
+						'id' => $preOrderObj->id,
+						'ref' => $preOrderObj->ref,
+					];
+				} else {
+					ApiBbusLog::eventLog(json_encode(['error' => $preOrderObj->errors]));
+					ApiBbusLog::eventLog("Unsaved event: " . $fk_event);
+					throw new RestException(401, 'Unsaved event: ' . $fk_event);
+				}
+			}
+		}
+		return $createdPreOrderOBJ;
+	}
+
+	/**
+	 * Get all free spaces on a selected date
+	 *
+	 * Return an array with details
+	 *
+	 * @return 	array|mixed data without useless information
+	 *
+	 * @param 	int 	fk_event
+	 * @param 	int 	reservations
+	 * 
+	 * @url	POST nolocalemptyspaces
+	 *
+	 * @throws RestException 401 Not allowed
+	 * @throws RestException 404 Not found
+	 */
+	public function nolocalemptyspaces($fk_event, $reservations)
+	{
+		$sql = "SELECT ace.max_num, ace.buffer, ace.participants FROM llx_actioncomm as ac
+        INNER JOIN llx_actioncomm_extrafields as ace ON ace.fk_object = ac.id
+        WHERE ac.id = {$fk_event}";
+		$result = $this->db->query($sql);
+		if ($this->db->num_rows($result) == 0) {
+			return '{"result":1}';
+		}
+		while ($row = $this->db->fetch_object($result)) {
+			if ($row->participants >= $row->max_num) {
+				return '{"result":1}';
+			}
+			if ($row->participants + $reservations > $row->max_num + $row->buffer) {
+				return '{"result":1}';
+			}
+		}
+		return '{"result":0}';
+	}
+
+	/**
+	 * Validate and save invoice
+	 *
+	 * Return an array with details
+	 *
+	 * @return 	array|mixed data without useless information
+	 *
+	 * @param 	string	$sendId				sendID
+	 * @param  	array 	$payment			Invoice payment
+	 * @param  	array 	$preorder			preorder
+	 * @param  	array 	$invoice			Invoice
+	 * @param  	string 	$cardPaymentLog		Card payment log data
+	 * 
+	 * @url	POST localvalidateandsaveinvoice
+	 * @access protected
+
+	 * @throws RestException 401 Not allowed
+	 * @throws RestException 404 Not found
+	 * @throws RestException 506 No available spaces
+	 * 
+	 */
+	public function localValidateAndSaveInvoice($invoice, $preorder, $payment, $cardPaymentLog, $sendId)
+	{
+		global $user, $db;
+		$createdInvoiceData = [];
+		$apiInvoiceHelper = new ApiInvoiceHelper;
+		$bbusApi = new BBus();
+		foreach ($preorder as $order) {
+			$sql = "SELECT fk_product, fk_event  FROM llx_booking_preorder WHERE rowid = {$order}";
+			//print $sql . "\r\n";
+			$data = $db->query($sql);
+			if ($db->num_rows($data) > 0) {
+				while ($row = $db->fetch_object($data)) {
+					//print_r($row);
+					$lines = $apiInvoiceHelper->getProductLines($row->fk_product);
+					$createdInvoiceArray = $bbusApi->invoice($invoice, $lines, $payment, $cardPaymentLog = '', $sendId = '');
+					$createdInvoiceData[] = $createdInvoiceArray;
+					$bookingHistory = $this->saveEventData((int)$row->fk_event, $createdInvoiceArray['invoice']['id']);
+					$this->updateBbticket($bookingHistory, $createdInvoiceArray['invoice']);
+					$this->deletePreorder($preorder);
+				}
+			}
+		}
+		return $createdInvoiceData;
+	}
+
+	/**
+	 * Get back the product_id and event_id from llx_booking_preorder
+	 *
+	 * Return an array with details
+	 *
+	 * @return 	array|mixed data without useless information
+	 *
+	 * @param 	int		$rowid				preorder->rowid
+	 * 
+	 * @url	POST localpreorderarray
+	 * @access protected
+
+	 * @throws RestException 401 Not allowed
+	 * @throws RestException 404 Not found
+	 * @throws RestException 506 No available spaces
+	 * 
+	 */
+	public function localpreorderarray(int $rowid)
+	{
+		global $user, $db;
+		$result = [];
+		$sql = "SELECT fk_product, fk_event  FROM llx_booking_preorder WHERE rowid = {$rowid}";
+		$data = $db->query($sql);
+		if ($db->num_rows($data) > 0) {
+			while ($row = $db->fetch_object($data)) {
+				$result = $row;
+			}
+		}
+		return $result;
+	}
+
+	/**
+	 * Create BBticket record
+	 *
+	 * Return an array with details
+	 *
+	 * @return 	array|mixed data without useless information
+	 *
+	 * @param 	string		$product_id
+	 * @param 	string		$datec
+	 * @param 	string		$facture_id
+	 * 
+	 * @url	POST createbbticket
+	 * @access protected
+
+	 * @throws RestException 401 Not allowed
+	 * @throws RestException 404 Not found
+	 * @throws RestException 506 No available spaces
+	 * 
+	 */
+	public function createbbticket(string $product_id, string $datec, string $facture_id)
+	{
+		global $db, $conf;
+		$sql = "SELECT validperiod, occasions FROM " . $this->db->prefix() . "product_extrafields WHERE fk_object = " . $product_id;
+		$result = $db->query($sql);
+		while ($sqlDataResult = $db->fetch_array($result)) {
+			$validperiod = $sqlDataResult['validperiod'] ? $sqlDataResult['validperiod'] : 366;
+			$occasions = $sqlDataResult['occasions'];
+		}
+		$ticket = new BbTicket($db);
+		$ticket->fk_facture = null;
+		$ticket->bundle_id = $product_id;
+		$ticket->usable_occasions = $occasions;
+		$ticket->usage = '0';
+		$ticket->available_at = $this->getAvailableAtDate($datec, $validperiod);
+		$ticket->ticket_id = $product_id;
+		$ticket->fk_settlements_group_id = $conf->global->CURL_GROUP_ID;
+		$ticket->invoice_number = $facture_id;
+		if ($ticket->create($this->user) == -1) {
+			dol_syslog("Nem sikerult a ticketek mentese");
+		}
+		return true;
+	}
+
+	private function getAvailableAtDate($date, $validperiod)
+	{
+		$available_at = date('Y-m-d H:i:s', strtotime($date . ' +' . $validperiod . ' days'));
+		return $available_at;
+	}
+
+	#-------------------------------------------------
+	#	CURL
+	#-------------------------------------------------
+
+	/**
+	 * Update data in BBticket
+	 *
+	 * Return an array with details
+	 *
+	 * @return 	array|mixed data without useless information
+	 *
+	 * @param 	string 	$fk_booking_history			//selected evet from llx_event
+	 * @param 	array 	$invoice			//facture rowid from llx_facture
+	 * 
+	 * @url	POST curlUpdateBbticket
+	 * @throws RestException 401 Not allowed
+	 * @throws RestException 404 Not found
+	 */
+	public function curlUpdateBbticket($fk_booking_history, $invoice)
+	{
+		global $user;
+		$sql = "SELECT rowid FROM llx_bbus_bbticket WHERE invoice_number = '{$invoice['id']}'";
+		ApiBbusLog::appLog("curlUpdateBbticket SELECT: {$sql}");
+		$data = $this->db->query($sql);
+		if ($this->db->num_rows($data) > 0) {
+			while ($row = $this->db->fetch_object($data)) {
+				$sql = "UPDATE llx_bbus_bbticket
+				SET booking_history_id = {$fk_booking_history}, invoice_number = '{$invoice['ref']}'
+				WHERE rowid = {$row->rowid}";
+				ApiBbusLog::appLog("curlUpdateBbticket UPDATE: {$sql}");
+				$this->db->query($sql);
+			}
+		}
+	}
+
+	/**
+	 * delete preorderrecord
+	 *
+	 * Return an array with details
+	 *
+	 * @return 	array|mixed data without useless information
+	 *
+	 * @param 	string 	$preorder_id			//selected evet from llx_event
+	 * 
+	 * @url	POST curlDeletePreorder
+	 * @throws RestException 401 Not allowed
+	 * @throws RestException 404 Not found
+	 */
+	public function curlDeletePreorder($rowid)
+	{
+		$sql = "DELETE FROM llx_booking_preorder WHERE rowid = {$rowid}";
+		ApiBbusLog::appLog("{$sql}");
+		$this->db->query($sql);
+	}
+
+	/**
+	 * Create BBticket record
+	 *
+	 * Return an array with details
+	 *
+	 * @return 	array|mixed data without useless information
+	 *
+	 * @param 	string		$product_id
+	 * @param 	string		$datec
+	 * @param 	string		$ref
+	 * 
+	 * @url	POST createbbticketmultiprinting
+	 * @access protected
+
+	 * @throws RestException 401 Not allowed
+	 * @throws RestException 404 Not found
+	 * @throws RestException 506 No available spaces
+	 * 
+	 */
+	public function createbbticketmultiprinting(string $product_id, string $datec, string $ref)
+	{
+		global $db;
+		$sql = "SELECT validperiod, occasions FROM " . $this->db->prefix() . "product_extrafields WHERE fk_object = " . $product_id;
+		$result = $db->query($sql);
+		while ($sqlDataResult = $db->fetch_array($result)) {
+			$validperiod = $sqlDataResult['validperiod'] ? $sqlDataResult['validperiod'] : 366;
+			$occasions = $sqlDataResult['occasions'];
+		}
+		$curlGroup = 10000;
+		$ticket = new BbTicket($db);
+		$ticket->fk_facture = null;
+		$ticket->bundle_id = $product_id;
+		$ticket->usable_occasions = $occasions;
+		$ticket->usage = '0';
+		$ticket->available_at = $this->getAvailableAtDate($datec, $validperiod);
+		$ticket->ticket_id = $product_id;
+		$ticket->fk_settlements_group_id = $curlGroup;
+		$ticket->invoice_number = $ref;
+		if ($ticket->create($this->user) == -1) {
+			dol_syslog("Nem sikerult a ticketek mentese");
+		}
+		$array['id'] = $ticket->id;
+		$array['ticket_id'] = $ticket->ticket_id;
+		return $array;
+	}
+
+	#-------------------------------------------------
+	#	OLD functions
+	#-------------------------------------------------
+
+	/**
+	 * Validate and save invoice
+	 * {"facture_id":41968,"cardPaymentLog":"","sendId":"K1pfFPlT","payment":{"datepaye":1716388707,"paymentid":14,"accountid":4,"closepaidinvoices":"yes"}}
+	 *
+	 * Return an array with details
+	 *
+	 * @return 	array|mixed data without useless information
+	 *
+	 * @param  	int 	$facture_id			//facture_id
+	 * @param  	array 	$payment			Invoice payment
+	 * @param  	string 	$cardPaymentLog		Card payment log data
+	 * @param 	string	$sendId				//ID
+	 * 
+	 * @url	POST validateandsaveinvoiceold
+	 * @access protected
+
+	 * @throws RestException 401 Not allowed
+	 * @throws RestException 404 Not found
+	 * @throws RestException 506 No available spaces
+	 * 
+	 */
+	public function validateandsaveinvoiceOld(int $facture_id, array $payment, string $cardPaymentLog = '', string $sendId = '')
+	{
+		global $user;
+		ApiBbusLog::eventLog("{$sendId} === VALIDATE INVOICE ===");
+		dol_syslog("{$sendId} === VALIDATE INVOICE ===", LOG_INFO, 0);
+		ApiBbusLog::eventLog("{$sendId} REQUEST: {$sendId}");
+		dol_syslog("{$sendId} REQUEST: {$sendId}", LOG_INFO, 0);
+		ApiBbusLog::eventLog("{$sendId} User: {$this->user->firstname} {$this->user->lastname} (ID: {$this->user->id})");
+		dol_syslog("{$sendId} User: {$this->user->firstname} {$this->user->lastname} (ID: {$this->user->id})", LOG_INFO, 0);
+		ApiBbusLog::eventLog("{$sendId} " . json_encode([
+			'facture_id' => $facture_id,
+			'payement' => $payment,
+			'cardPayementLog' => $cardPaymentLog,
+			'sendId' => $sendId,
+		]));
+		$products = [];
+		$invoiceObj = new Facture($this->db);
+		$apiInvoiceHelper = new ApiInvoiceHelper;
+		$invoiceObj->fetch($facture_id);
+
+		foreach ($invoiceObj->lines as $line) {
+			$product = $apiInvoiceHelper->loadProductToResult(get_object_vars($line));
+			if (!empty($product)) {
+				$products[] = $product;
+			}
+		}
+
+		foreach ($products as &$row) {
+			foreach ($invoiceObj->lines as $line) {
+				if ($line->product_ref == $row['ref']) {
+					//$row['price'] = $line->total_ttc;
+					$row['price'] = $line->multicurrency_total_ttc;
+					$row['total_tva'] = $line->total_tva;
+					//$row['total_tva'] = $line->multicurrency_total_tva;
+				}
+			}
+		}
+
+		$invoiceObj = $apiInvoiceHelper->validateInvoiceFromPROV($invoiceObj, $sendId, $facture_id);
+		$apiInvoiceHelper->setPaymentFromPROV($invoiceObj, $payment, $sendId);
+		if (!empty($cardPaymentLog)) {
+			$invoiceObj = $apiInvoiceHelper->saveCardPaymentLog($invoiceObj, $cardPaymentLog, $sendId);
+		}
+
+		ApiBbusLog::eventLog("{$sendId} Invoice created. ID: {$invoiceObj->id} REF: {$invoiceObj->ref} REQ: {$sendId}");
+		dol_syslog("{$sendId} Invoice created. ID: {$invoiceObj->id} REF: {$invoiceObj->ref} REQ: {$sendId}", LOG_INFO, 0);
+		//$bbApiLock->delete($user);
+
+		ApiBbusLog::eventLog("{$sendId}####################################################################");
+		dol_syslog("{$sendId}####################################################################", LOG_INFO, 0);
+
+		return [
+			'sendId' => $sendId,
+			'invoice' => [
+				'id' => $invoiceObj->id,
+				'ref' => $invoiceObj->ref,
+				'total' => $invoiceObj->multicurrency_total_ttc
+			],
+			'products' => $products,
+		];
+	}
+
+	/**
+	 * First step of the eventhandling
+	 * {"invoice":{"array_options_app_facture":1,"array_options_customer_data_zip":6782,"multicurrency_code":"HUF","fk_multicurrency":3,"mode_reglement_id":14,"cond_reglement_id":14,"fk_account":4},"fk_event":82586,"reservations":1,"sendId":12121212,"product_id":155}
+	 *
+	 * Return an array with details
+	 *
+	 * @return 	array|mixed data without useless information
+	 *
+	 * @param  array 	$invoice			Invoice data
+	 * @param 	int 	$fk_event			//selected evet from llx_event
+	 * @param 	int 	$reservations		//numbers of reservations
+	 * @param 	int 	$product_id			//Product
+	 * @param 	string	$sendId				//ID
+	 * 
+	 * @url	POST firsteventstepold
+	 * @access protected
+	 * @throws RestException 401 Not allowed
+	 * @throws RestException 404 Not found
+	 * @throws RestException 506 No available spaces
+	 * 
+	 */
+	public function firstEventStepOld(array $invoice, int $fk_event, int $reservations, int $product_id, string $sendId)
+	{
+		$eventHelper = new EventHelper;
+		if ($eventHelper->noEmptySpaces($fk_event, $reservations)) {
+			throw new RestException(506, 'No available spaces');
+		}
+
+		if (!DolibarrApiAccess::$user->rights->facture->creer) {
+			ApiBbusLog::eventLog("{$sendId} Insufficient rights");
+			throw new RestException(401, 'Insufficient rights');
+		}
+		/**
+		 * LOG SECTION
+		 */
+		ApiBbusLog::eventLog("{$sendId} === NEW INVOICE ===");
+		dol_syslog("{$sendId} === NEW INVOICE ===", LOG_INFO, 0);
+		ApiBbusLog::eventLog("{$sendId} REQUEST: {$sendId}");
+		dol_syslog("{$sendId} REQUEST: {$sendId}", LOG_INFO, 0);
+		ApiBbusLog::eventLog("{$sendId} User: {$this->user->firstname} {$this->user->lastname} (ID: {$this->user->id})");
+		dol_syslog("{$sendId} User: {$this->user->firstname} {$this->user->lastname} (ID: {$this->user->id})", LOG_INFO, 0);
+		ApiBbusLog::eventLog("{$sendId} " . json_encode([
+			'invoice' => $invoice,
+			'fk_event' => $fk_event,
+			'reservations' => $reservations,
+			'product_id' => $product_id,
+			'sendId' => $sendId,
+		]));
+
+		$apiInvoiceHelper = new ApiInvoiceHelper;
+		$createdInvoicePROVs = [];
+
+		for ($i = 1; $i <= $reservations; $i++) {
+			dol_include_once('/comm/action/class/actioncomm.class.php');
+			$apiInvoiceHelper->increaseParticipant($fk_event);
+			$invoiceObj = $apiInvoiceHelper->createInvoicePROV($invoice, $sendId);
+			$createdInvoicePROVs[] = [
+				'id' => $invoiceObj->id,
+				'ref' => $invoiceObj->ref,
+			];
+			ApiBbusLog::eventLog("{$sendId} - Invoice PROV created - " . $invoiceObj->id . ' - ' . $invoiceObj->ref);
+			$lines = $apiInvoiceHelper->getProductLines($product_id);
+			foreach ($lines as $line) {
+				$invoiceLineObj = $apiInvoiceHelper->addLineToInvoice($invoiceObj, $line, $sendId);
+				$this->saveEventData($fk_event, $invoiceObj->id, $fk_eventproduct = 1);
+			}
+			$invoiceLineObj->fetch_lines();
+		}
+		print_r($createdInvoicePROVs);
+		exit;
+		return $createdInvoicePROVs;
+	}
+}

Certains fichiers n'ont pas été affichés car il y a eu trop de fichiers modifiés dans ce diff