* 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 . */ 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; } }