Fixed: initial commit

Co-authored-by: Name <sumit201@webkul.in>
This commit is contained in:
amit sharma
2026-07-16 17:04:53 +05:30
parent 5b4d65cbb8
commit 6f2d1e599e
17 changed files with 1477 additions and 0 deletions

View File

@@ -0,0 +1,18 @@
{*
* NOTICE OF LICENSE
*
* This source file is subject to the Open Software License version 3.0
* that is bundled with this package in the file LICENSE.md
* It is also available through the world-wide-web at this URL:
* https://opensource.org/license/osl-3-0-php
*
* @author Webkul IN
* @copyright Since 2010 Webkul
* @license https://opensource.org/license/osl-3-0-php Open Software License version 3.0
*}
{extends file="helpers/list/list_header.tpl"}
{block name="override_form_extra"}
{if isset($smarty.get.id_source_type)}
<input type="hidden" name="id_source_type" value="{$smarty.get.id_source_type|intval}" />
{/if}
{/block}

View File

@@ -0,0 +1,36 @@
{*
* NOTICE OF LICENSE
*
* This source file is subject to the Open Software License version 3.0
* that is bundled with this package in the file LICENSE.md
*
* @author Webkul IN
* @copyright Since 2010 Webkul
* @license https://opensource.org/license/osl-3-0-php Open Software License version 3.0
*}
<form action="{$current_index}&token={$token}" method="post">
<div class="modal-body">
<div class="form-group">
<label>{l s='Current Source'}</label>
<select name="merge_current_source" id="merge_current_source" class="form-control">
{foreach from=$sources item=source}
<option value="{$source.id_source}"{if $source.id_source == $id_current_source} selected="selected"{/if}>{$source.name}</option>
{/foreach}
</select>
</div>
<div class="form-group">
<label>{l s='Target Source'}</label>
<select name="merge_target_source" id="merge_target_source" class="form-control">
{foreach from=$sources item=source}
<option value="{$source.id_source}">{$source.name}</option>
{/foreach}
</select>
</div>
<p class="help-block">{l s='Every order currently attributed to Current Source will be reattributed to Target Source. Current Source itself is left as-is.'}</p>
<input type="hidden" name="id_source_type" value="{$id_source_type|intval}" />
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">{l s='Cancel'}</button>
<button type="submit" name="submitMergeSource" class="btn btn-primary">{l s='Update'}</button>
</div>
</form>

View File

@@ -32,5 +32,6 @@ class BoOrder extends PaymentModule
$this->validateOrderAmount = false;
// Default payment type for backoffice order should be PAY_AT_HOTEL
$this->payment_type = OrderPayment::PAYMENT_TYPE_PAY_AT_HOTEL;
$this->idBookingSource = Source::getIdByCode('WALKIN');
}
}

237
classes/BusinessSource.php Normal file
View File

@@ -0,0 +1,237 @@
<?php
/**
* NOTICE OF LICENSE
*
* This source file is subject to the Open Software License version 3.0
* that is bundled with this package in the file LICENSE.md
* It is also available through the world-wide-web at this URL:
* https://opensource.org/license/osl-3-0-php
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to support@qloapps.com so we can send you a copy immediately.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade QloApps to newer
* versions in the future. If you wish to customize QloApps for your needs
* please refer to https://store.webkul.com/customisation-guidelines for more information.
*
* @author Webkul IN
* @copyright Since 2010 Webkul
* @license https://opensource.org/license/osl-3-0-php Open Software License version 3.0
*/
class BusinessSourceCore extends ObjectModel
{
public $name;
public $source_type_code;
public $position;
public $unremovable;
public $active;
public $deleted = 0;
public $date_add;
public $date_upd;
public static $definition = array(
'table' => 'business_source',
'primary' => 'id_source_type',
'multilang' => true,
'fields' => array(
'source_type_code' => array('type' => self::TYPE_STRING, 'validate' => 'isModuleName', 'required' => true, 'size' => 64),
'position' => array('type' => self::TYPE_INT, 'validate' => 'isUnsignedInt'),
'unremovable' => array('type' => self::TYPE_BOOL, 'validate' => 'isBool'),
'active' => array('type' => self::TYPE_BOOL, 'validate' => 'isBool'),
'deleted' => array('type' => self::TYPE_BOOL, 'validate' => 'isBool'),
'date_add' => array('type' => self::TYPE_DATE, 'validate' => 'isDate'),
'date_upd' => array('type' => self::TYPE_DATE, 'validate' => 'isDate'),
'name' => array('type' => self::TYPE_STRING, 'lang' => true, 'validate' => 'isGenericName', 'required' => true, 'size' => 64),
),
);
public function add($autodate = true, $nullValues = false)
{
if ($this->position <= 0) {
$this->position = BusinessSource::getHigherPosition() + 1;
}
return parent::add($autodate, $nullValues);
}
/**
* @return int Highest current position among non-deleted Business Sources, or -1 if none exist
*/
public static function getHigherPosition()
{
$position = Db::getInstance()->getValue(
'SELECT MAX(`position`) FROM `'._DB_PREFIX_.'business_source` WHERE `deleted` = 0'
);
return is_numeric($position) ? (int)$position : -1;
}
/**
* Move this Business Source up/down the list.
* @param bool $way Up (1) or Down (0)
* @param int $position
* @return bool
*/
public function updatePosition($way, $position)
{
if (!$res = Db::getInstance()->executeS('
SELECT `position`, `id_source_type`
FROM `'._DB_PREFIX_.'business_source`
WHERE `deleted` = 0
ORDER BY `position` ASC'
)) {
return false;
}
$moved_item = null;
foreach ($res as $row) {
if ((int)$row['id_source_type'] == (int)$this->id) {
$moved_item = $row;
}
}
if (!$moved_item) {
return false;
}
return (Db::getInstance()->execute('
UPDATE `'._DB_PREFIX_.'business_source`
SET `position` = `position` '.($way ? '- 1' : '+ 1').'
WHERE `deleted` = 0 AND `position`
'.($way
? '> '.(int)$moved_item['position'].' AND `position` <= '.(int)$position
: '< '.(int)$moved_item['position'].' AND `position` >= '.(int)$position)
) && Db::getInstance()->execute('
UPDATE `'._DB_PREFIX_.'business_source`
SET `position` = '.(int)$position.'
WHERE `id_source_type` = '.(int)$moved_item['id_source_type']));
}
/**
* Reorder Business Source positions into a contiguous 0..N-1 sequence. Call after a delete.
* @return bool
*/
public static function cleanPositions()
{
$return = true;
$result = Db::getInstance()->executeS('
SELECT `id_source_type`
FROM `'._DB_PREFIX_.'business_source`
WHERE `deleted` = 0
ORDER BY `position` ASC'
);
$i = 0;
foreach ($result as $row) {
$return = Db::getInstance()->execute('
UPDATE `'._DB_PREFIX_.'business_source`
SET `position` = '.(int)$i++.'
WHERE `id_source_type` = '.(int)$row['id_source_type']
) && $return;
}
return $return;
}
public static function codeExists($code, $idExclude = 0)
{
return (bool)Db::getInstance()->getValue(
'SELECT `id_source_type` FROM `'._DB_PREFIX_.'business_source`
WHERE `source_type_code` = \''.pSQL($code).'\' AND `id_source_type` != '.(int)$idExclude
);
}
public static function getUnremovableIds()
{
$rows = Db::getInstance()->executeS(
'SELECT `id_source_type` FROM `'._DB_PREFIX_.'business_source` WHERE `unremovable` = 1 AND `deleted` = 0'
);
return array_map('intval', array_column($rows, 'id_source_type'));
}
public static function getActiveList($idLang)
{
return Db::getInstance()->executeS('
SELECT bs.`id_source_type`, bsl.`name`
FROM `'._DB_PREFIX_.'business_source` bs
LEFT JOIN `'._DB_PREFIX_.'business_source_lang` bsl
ON (bsl.`id_source_type` = bs.`id_source_type` AND bsl.`id_lang` = '.(int)$idLang.')
WHERE bs.`active` = 1 AND bs.`deleted` = 0
ORDER BY bs.`position` ASC
');
}
public function isRemovable()
{
return !$this->unremovable;
}
/**
* @return bool True if any Booking Source under this Business Source — deleted or not —
* is referenced by an order. A soft-deleted Booking Source still referenced by a historical
* order must keep resolving to a Business Source name too, so this still blocks deletion.
*/
public function hasSourceUsedByOrder()
{
return (bool)Db::getInstance()->getValue(
'SELECT COUNT(*) FROM `'._DB_PREFIX_.'source` s
INNER JOIN `'._DB_PREFIX_.'orders` o ON o.`id_source` = s.`id_source`
WHERE s.`id_source_type` = '.(int)$this->id
);
}
/**
* @return int Total orders placed across every Booking Source under this Business Source —
* the denominator for each Booking Source's own percentage within this category's
* drill-down list (as opposed to a share of every order in the system).
*/
public function getOrderCount()
{
return (int)Db::getInstance()->getValue(
'SELECT COUNT(*) FROM `'._DB_PREFIX_.'source` s
INNER JOIN `'._DB_PREFIX_.'orders` o ON o.`id_source` = s.`id_source`
WHERE s.`id_source_type` = '.(int)$this->id
);
}
/**
* Deleting a Business Source deletes every Booking Source under it (each through its own
* delete() rule — soft-deleted if order-linked, hard-deleted otherwise). If any of them
* turns out to be order-linked, this Business Source is soft-deleted too, the same way, so
* historical orders keep resolving a category name; otherwise it hard-deletes for real.
*/
public function delete()
{
if (!$this->isRemovable()) {
return false;
}
$keepSoft = $this->hasSourceUsedByOrder();
$sources = Db::getInstance()->executeS(
'SELECT `id_source` FROM `'._DB_PREFIX_.'source` WHERE `id_source_type` = '.(int)$this->id.' AND `deleted` = 0'
);
foreach ($sources as $row) {
$objSource = new Source((int)$row['id_source']);
if (!$objSource->delete()) {
return false;
}
}
if ($keepSoft) {
$this->deleted = 1;
if (!$this->update()) {
return false;
}
} elseif (!parent::delete()) {
return false;
}
return BusinessSource::cleanPositions();
}
}

View File

@@ -352,6 +352,13 @@ abstract class PaymentModuleCore extends Module
$order->source = Configuration::get('PS_SHOP_DOMAIN');
}
// Booking Source (business categorization, e.g. Direct Website/Walk-in/OTA) —
if (isset($this->idBookingSource) && $this->idBookingSource) {
$order->id_source = (int)$this->idBookingSource;
} else {
$order->id_source = Source::getDefaultSourceId();
}
if (self::DEBUG_MODE) {
PrestaShopLogger::addLog('PaymentModule::validateOrder - Order is about to be added', 1, null, 'Cart', (int)$id_cart, true);
}

222
classes/Source.php Normal file
View File

@@ -0,0 +1,222 @@
<?php
/**
* NOTICE OF LICENSE
*
* This source file is subject to the Open Software License version 3.0
* that is bundled with this package in the file LICENSE.md
* It is also available through the world-wide-web at this URL:
* https://opensource.org/license/osl-3-0-php
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to support@qloapps.com so we can send you a copy immediately.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade QloApps to newer
* versions in the future. If you wish to customize QloApps for your needs
* please refer to https://store.webkul.com/customisation-guidelines for more information.
*
* @author Webkul IN
* @copyright Since 2010 Webkul
* @license https://opensource.org/license/osl-3-0-php Open Software License version 3.0
*/
class SourceCore extends ObjectModel
{
public $name;
public $id_source_type;
public $source_code;
public $position;
public $unremovable;
public $active;
public $deleted = 0;
public $date_add;
public $date_upd;
public static $definition = array(
'table' => 'source',
'primary' => 'id_source',
'multilang' => true,
'fields' => array(
'id_source_type' => array('type' => self::TYPE_INT, 'validate' => 'isUnsignedId', 'required' => true),
'source_code' => array('type' => self::TYPE_STRING, 'validate' => 'isModuleName', 'required' => true, 'size' => 64),
'position' => array('type' => self::TYPE_INT, 'validate' => 'isUnsignedInt'),
'unremovable' => array('type' => self::TYPE_BOOL, 'validate' => 'isBool'),
'active' => array('type' => self::TYPE_BOOL, 'validate' => 'isBool'),
'deleted' => array('type' => self::TYPE_BOOL, 'validate' => 'isBool'),
'date_add' => array('type' => self::TYPE_DATE, 'validate' => 'isDate'),
'date_upd' => array('type' => self::TYPE_DATE, 'validate' => 'isDate'),
'name' => array('type' => self::TYPE_STRING, 'lang' => true, 'validate' => 'isGenericName', 'required' => true, 'size' => 64),
),
);
public function add($autodate = true, $nullValues = false)
{
if ($this->position <= 0) {
$this->position = Source::getHigherPosition($this->id_source_type) + 1;
}
return parent::add($autodate, $nullValues);
}
public static function getHigherPosition($idSourceType)
{
$position = Db::getInstance()->getValue(
'SELECT MAX(`position`) FROM `'._DB_PREFIX_.'source`
WHERE `id_source_type` = '.(int)$idSourceType.' AND `deleted` = 0'
);
return is_numeric($position) ? (int)$position : -1;
}
public function updatePosition($way, $position)
{
if (!$res = Db::getInstance()->executeS('
SELECT `position`, `id_source`
FROM `'._DB_PREFIX_.'source`
WHERE `id_source_type` = '.(int)$this->id_source_type.' AND `deleted` = 0
ORDER BY `position` ASC'
)) {
return false;
}
$moved_item = null;
foreach ($res as $row) {
if ((int)$row['id_source'] == (int)$this->id) {
$moved_item = $row;
}
}
if (!$moved_item) {
return false;
}
return (Db::getInstance()->execute('
UPDATE `'._DB_PREFIX_.'source`
SET `position` = `position` '.($way ? '- 1' : '+ 1').'
WHERE `id_source_type` = '.(int)$this->id_source_type.' AND `deleted` = 0 AND `position`
'.($way
? '> '.(int)$moved_item['position'].' AND `position` <= '.(int)$position
: '< '.(int)$moved_item['position'].' AND `position` >= '.(int)$position)
) && Db::getInstance()->execute('
UPDATE `'._DB_PREFIX_.'source`
SET `position` = '.(int)$position.'
WHERE `id_source` = '.(int)$moved_item['id_source']));
}
public static function codeExists($code, $idExclude = 0)
{
return (bool)Db::getInstance()->getValue(
'SELECT `id_source` FROM `'._DB_PREFIX_.'source`
WHERE `source_code` = \''.pSQL($code).'\' AND `id_source` != '.(int)$idExclude
);
}
public static function getIdByCode($code)
{
return (int)Db::getInstance()->getValue(
'SELECT `id_source` FROM `'._DB_PREFIX_.'source`
WHERE `source_code` = \''.pSQL($code).'\' AND `deleted` = 0'
);
}
public static function getUnremovableIds()
{
$rows = Db::getInstance()->executeS(
'SELECT `id_source` FROM `'._DB_PREFIX_.'source` WHERE `unremovable` = 1 AND `deleted` = 0'
);
return array_map('intval', array_column($rows, 'id_source'));
}
public static function getActiveListForType($idSourceType, $idLang)
{
return Db::getInstance()->executeS('
SELECT a.`id_source`, al.`name`
FROM `'._DB_PREFIX_.'source` a
LEFT JOIN `'._DB_PREFIX_.'source_lang` al ON (al.`id_source` = a.`id_source` AND al.`id_lang` = '.(int)$idLang.')
WHERE a.`id_source_type` = '.(int)$idSourceType.' AND a.`deleted` = 0 AND a.`active` = 1
ORDER BY a.`position` ASC
');
}
public static function getSourcesUsedInOrders($idLang)
{
return Db::getInstance()->executeS('
SELECT DISTINCT o.`id_source`, sl.`name`
FROM `'._DB_PREFIX_.'orders` o
INNER JOIN `'._DB_PREFIX_.'source` s ON (s.`id_source` = o.`id_source`)
LEFT JOIN `'._DB_PREFIX_.'source_lang` sl ON (sl.`id_source` = s.`id_source` AND sl.`id_lang` = '.(int)$idLang.')
');
}
public static function cleanPositions($idSourceType)
{
$return = true;
$result = Db::getInstance()->executeS('
SELECT `id_source`
FROM `'._DB_PREFIX_.'source`
WHERE `id_source_type` = '.(int)$idSourceType.' AND `deleted` = 0
ORDER BY `position` ASC'
);
$i = 0;
foreach ($result as $row) {
$return = Db::getInstance()->execute('
UPDATE `'._DB_PREFIX_.'source`
SET `position` = '.(int)$i++.'
WHERE `id_source` = '.(int)$row['id_source']
) && $return;
}
return $return;
}
public function isRemovable()
{
return !$this->unremovable;
}
public function isUsedByOrder()
{
return (bool)Db::getInstance()->getValue(
'SELECT COUNT(*) FROM `'._DB_PREFIX_.'orders` WHERE `id_source` = '.(int)$this->id
);
}
public function mergeOrdersInto($idTargetSource)
{
return (bool)Db::getInstance()->execute(
'UPDATE `'._DB_PREFIX_.'orders` SET `id_source` = '.(int)$idTargetSource.' WHERE `id_source` = '.(int)$this->id
);
}
public static function getTotalOrderCount()
{
return (int)Db::getInstance()->getValue('SELECT COUNT(*) FROM `'._DB_PREFIX_.'orders`');
}
public function delete()
{
if (!$this->isRemovable()) {
return false;
}
if ($this->isUsedByOrder()) {
$this->deleted = 1;
if (!$this->update()) {
return false;
}
} elseif (!parent::delete()) {
return false;
}
return Source::cleanPositions($this->id_source_type);
}
public static function getDefaultSourceId()
{
return (int)Configuration::get('PS_DEFAULT_BOOKING_SOURCE');
}
}

View File

@@ -33,6 +33,7 @@ class AdminOrdersControllerCore extends AdminController
protected $statuses_array = array();
protected $all_order_sources = array();
protected $bookingSourcesArray = array();
protected $hotelsArray = array();
protected $roomTypesArray = array();
protected $roomsArray = array();
@@ -74,6 +75,10 @@ class AdminOrdersControllerCore extends AdminController
hbd.`id_room` AS id_room_information,
(SELECT COUNT(spod.`id_service_product_order_detail`) FROM `'._DB_PREFIX_.'service_product_order_detail` spod WHERE spod.`id_order` = a.`id_order` AND spod.`id_htl_booking_detail`=0) as num_products';
$this->_select .= ',
(SELECT sl.`name` FROM `'._DB_PREFIX_.'source` s LEFT JOIN `'._DB_PREFIX_.'source_lang` sl ON (sl.`id_source` = s.`id_source` AND sl.`id_lang` = '.(int)$this->context->language->id.') WHERE s.`id_source` = a.`id_source`) AS `booking_source_name`,
(SELECT s.`source_code` FROM `'._DB_PREFIX_.'source` s WHERE s.`id_source` = a.`id_source`) AS `booking_source_code`';
$this->_join = '
LEFT JOIN `'._DB_PREFIX_.'customer` c ON (c.`id_customer` = a.`id_customer`)
LEFT JOIN `'._DB_PREFIX_.'currency` cu ON (cu.`id_currency` = a.`id_currency`)
@@ -113,6 +118,9 @@ class AdminOrdersControllerCore extends AdminController
foreach ($all_order_sources as $source) {
$this->all_order_sources[$source['source']] = $source['source'];
}
foreach (Source::getSourcesUsedInOrders((int)$this->context->language->id) as $bookingSource) {
$this->bookingSourcesArray[$bookingSource['id_source']] = $bookingSource['name'];
}
$hotelsArray = HotelBranchInformation::getProfileAccessedHotels($this->context->employee->id_profile, 1);
foreach ($hotelsArray as $hotel) {
@@ -272,6 +280,16 @@ class AdminOrdersControllerCore extends AdminController
'optional' => true,
'visible_default' => true
),
'booking_source_name' => array(
'title' => $this->l('Booking Source'),
'type' => 'select',
'filter_key' => 'a!id_source',
'list' => $this->bookingSourcesArray,
'orderby' => false,
'callback' => 'formatBookingSource',
'optional' => true,
'visible_default' => true
),
'osname' => array(
'title' => $this->l('Status'),
'type' => 'select',
@@ -359,6 +377,26 @@ class AdminOrdersControllerCore extends AdminController
return Tools::displayPrice($echo, (int)$idCurrency);
}
/**
* fields_list callback for the Booking Source column — shows the Booking Source name and,
* only for the built-in "Direct Website" source, a link to the storefront alongside it.
*/
public static function formatBookingSource($echo, $row)
{
if (!$echo) {
return '--';
}
$html = Tools::safeOutput($echo);
if (isset($row['booking_source_code']) && $row['booking_source_code'] === 'DIRECT_WEBSITE') {
$title = Translate::getAdminTranslation('Visit website', 'AdminOrders', true);
$html .= ' <a href="'.Context::getContext()->link->getBaseLink().'" target="_blank" title="'.$title.'"><i class="icon-external-link"></i></a>';
}
return $html;
}
public function initPageHeaderToolbar()
{
if (empty($this->display)) {

View File

@@ -0,0 +1,709 @@
<?php
/**
* NOTICE OF LICENSE
*
* This source file is subject to the Open Software License version 3.0
* that is bundled with this package in the file LICENSE.md
* It is also available through the world-wide-web at this URL:
* https://opensource.org/license/osl-3-0-php
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to support@qloapps.com so we can send you a copy immediately.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade QloApps to newer
* versions in the future. If you wish to customize QloApps for your needs
* please refer to https://store.webkul.com/customisation-guidelines for more information.
*
* @author Webkul IN
* @copyright Since 2010 Webkul
* @license https://opensource.org/license/osl-3-0-php Open Software License version 3.0
*/
class AdminSourcesControllerCore extends AdminController
{
protected $position_identifier = 'id_source_type';
/** @var int Total order count, cached once per list render for the Orders % column */
protected $ordersTotal = 0;
public function __construct()
{
$this->bootstrap = true;
$this->table = 'business_source';
$this->className = 'BusinessSource';
$this->identifier = 'id_source_type';
$this->list_id = 'business_source';
$this->lang = true;
$this->deleted = false;
$this->_defaultOrderBy = 'position';
$this->_defaultOrderWay = 'ASC';
$this->context = Context::getContext();
$this->bulk_actions = array(
'delete' => array(
'text' => $this->l('Delete selected'),
'icon' => 'icon-trash',
'confirm' => $this->l('Delete selected items?')
)
);
parent::__construct();
}
public function setMedia()
{
parent::setMedia();
$this->addJS(_PS_JS_DIR_.'admin/sources.js');
}
public function init()
{
if (Tools::isSubmit('viewbusiness_source')
|| Tools::isSubmit('submitFiltersource')
|| Tools::isSubmit('submitResetsource')
|| Tools::getValue('sourceOrderby')
|| Tools::getValue('sourceOrderway')
) {
$this->list_id = 'source';
}
$idSourceType = (int) Tools::getValue('id_source_type');
if ($idSourceType && Tools::getValue('viewbusiness_source')) {
self::$currentIndex .= '&id_source_type=' . $idSourceType . '&viewbusiness_source';
$this->className = 'Source';
}
if (Tools::isSubmit('addsource') || Tools::isSubmit('addbusiness_source')) {
$this->display = 'add';
}
if (Tools::isSubmit('updatesource') || Tools::isSubmit('updatebusiness_source')) {
$this->display = 'edit';
}
if (Tools::isSubmit('submitAddsource') || Tools::isSubmit('submitAddsourceAndStay')) {
$this->display = Tools::getValue('id_source') ? 'edit' : 'add';
}
if (Tools::isSubmit('submitAddbusiness_source') || Tools::isSubmit('submitAddbusiness_sourceAndStay')) {
$this->display = Tools::getValue('id_source_type') ? 'edit' : 'add';
}
return parent::init();
}
/**
* @see AdminController::initPageHeaderToolbar()
*/
public function initPageHeaderToolbar()
{
if (empty($this->display)) {
$this->page_header_toolbar_btn['new_business_source'] = array(
'href' => self::$currentIndex.'&addbusiness_source&token='.$this->token,
'desc' => $this->l('Add new Business Source', null, null, false),
'icon' => 'process-icon-new'
);
} elseif ($this->display == 'view') {
$idSourceType = (int)Tools::getValue('id_source_type');
if ($idSourceType) {
$this->page_header_toolbar_btn['new_source'] = array(
'href' => self::$currentIndex.'&addsource&id_source_type='.$idSourceType.'&token='.$this->token,
'desc' => $this->l('Add new Booking Source', null, null, false),
'icon' => 'process-icon-new'
);
$this->page_header_toolbar_btn['back_to_business'] = array(
'href' => self::$currentIndex.'&token='.$this->token,
'desc' => $this->l('Back To Business Source', null, null, false),
'icon' => 'process-icon-back'
);
}
}
unset($this->toolbar_btn['back']);
parent::initPageHeaderToolbar();
}
protected function initBusinessSourcesList()
{
$this->fields_list = array(
'id_source_type' => array(
'title' => $this->l('ID'),
'align' => 'text-center',
'class' => 'fixed-width-xs'
),
'name' => array(
'title' => $this->l('Name'),
'width' => 'auto',
'filter_key' => 'b!name'
),
'source_type_code' => array(
'title' => $this->l('Code'),
'align' => 'text-center'
),
'position' => array(
'title' => $this->l('Position'),
'filter_key' => 'a!position',
'align' => 'text-center',
'class' => 'fixed-width-xs',
'position' => 'position'
),
'orders_count' => array(
'title' => $this->l('Orders'),
'align' => 'text-center',
'orderby' => false,
'search' => false,
'callback' => 'formatOrdersPercentage',
),
'active' => array(
'title' => $this->l('Enabled'),
'active' => 'status',
'type' => 'bool',
'align' => 'text-center',
'class' => 'fixed-width-xs',
'orderby' => false
),
);
}
protected function initSourcesList()
{
$this->fields_list = array(
'id_source' => array(
'title' => $this->l('ID'),
'align' => 'text-center',
'class' => 'fixed-width-xs'
),
'name' => array(
'title' => $this->l('Name'),
'width' => 'auto',
'filter_key' => 'b!name'
),
'source_type_name' => array(
'title' => $this->l('Business Source'),
'orderby' => false,
'search' => false,
),
'source_code' => array(
'title' => $this->l('Code'),
'align' => 'text-center'
),
'position' => array(
'title' => $this->l('Position'),
'filter_key' => 'a!position',
'align' => 'text-center',
'class' => 'fixed-width-xs',
'position' => 'position'
),
'orders_count' => array(
'title' => $this->l('Orders'),
'align' => 'text-center',
'orderby' => false,
'search' => false,
'callback' => 'formatOrdersPercentage',
),
'active' => array(
'title' => $this->l('Enabled'),
'active' => 'status',
'type' => 'bool',
'align' => 'text-center',
'class' => 'fixed-width-xs',
'orderby' => false
),
);
}
public function renderList()
{
$this->addRowAction('view');
$this->addRowAction('edit');
$this->addRowAction('delete');
$this->addRowActionSkipList('delete', BusinessSource::getUnremovableIds());
$this->_where = 'AND a.`deleted` = 0';
$this->_select = '(SELECT COUNT(*) FROM `'._DB_PREFIX_.'orders` o
INNER JOIN `'._DB_PREFIX_.'source` s ON s.`id_source` = o.`id_source`
WHERE s.`id_source_type` = a.`id_source_type`) AS `orders_count`';
$this->ordersTotal = Source::getTotalOrderCount();
$this->initBusinessSourcesList();
$this->toolbar_title = $this->l('Business Source');
return parent::renderList();
}
public function renderView()
{
$idSourceType = (int)Tools::getValue('id_source_type');
$objBusinessSource = new BusinessSource($idSourceType, (int)$this->context->language->id);
if (!Validate::isLoadedObject($objBusinessSource)) {
return;
}
$this->addRowAction('edit');
$this->addRowAction('merge');
$this->addRowAction('delete');
$this->addRowActionSkipList('delete', Source::getUnremovableIds());
$this->table = 'source';
$this->className = 'Source';
$this->identifier = 'id_source';
$this->list_id = 'source';
$this->_select = 'bsl.`name` AS `source_type_name`,
(SELECT COUNT(*) FROM `'._DB_PREFIX_.'orders` o WHERE o.`id_source` = a.`id_source`) AS `orders_count`';
$this->ordersTotal = $objBusinessSource->getOrderCount();
$this->_join = 'LEFT JOIN `'._DB_PREFIX_.'business_source` bs ON (bs.`id_source_type` = a.`id_source_type`)';
$this->_join .= 'LEFT JOIN `'._DB_PREFIX_.'business_source_lang` bsl ON (bsl.`id_source_type` = bs.`id_source_type` AND bsl.`id_lang` = '.(int)$this->context->language->id.')';
$this->_where = 'AND a.`deleted` = 0 AND a.`id_source_type` = '.(int)$objBusinessSource->id;
$this->initSourcesList();
$this->toolbar_title = sprintf($this->l('Booking Source - %s'),$objBusinessSource->name);
$this->processFilter();
return parent::renderList();
}
public function renderForm()
{
if (Tools::isSubmit('updatesource')
|| Tools::isSubmit('addsource')
|| Tools::isSubmit('submitAddsource')
|| Tools::isSubmit('submitAddsourceAndStay')
) {
return $this->renderSourceForm();
}
return $this->renderBusinessSourceForm();
}
protected function renderBusinessSourceForm()
{
if (!($objBusinessSource = $this->loadObject(true))) {
return;
}
$this->fields_form = array(
'legend' => array(
'title' => $this->l('Business Source'),
'icon' => 'icon-tags'
),
'input' => array(
array(
'type' => 'text',
'label' => $this->l('Name'),
'name' => 'name',
'lang' => true,
'required' => true,
'hint' => $this->l('Invalid characters:').' &lt;&gt;;=#{}'
),
array(
'type' => 'text',
'label' => $this->l('Code'),
'name' => 'source_type_code',
'required' => true,
'hint' => $this->l('A short unique machine code, e.g. "OTA". Letters, numbers, underscores and hyphens only.')
),
array(
'type' => 'switch',
'label' => $this->l('Enabled'),
'name' => 'active',
'required' => false,
'class' => 't',
'is_bool' => true,
'values' => array(
array('id' => 'active_on', 'value' => 1, 'label' => $this->l('Enabled')),
array('id' => 'active_off', 'value' => 0, 'label' => $this->l('Disabled')),
)
),
),
'submit' => array(
'title' => $this->l('Save'),
'name' => 'submitAddbusiness_source'
),
'buttons' => array(
'save-and-stay' => array(
'title' => $this->l('Save and stay'),
'name' => 'submitAddbusiness_sourceAndStay',
'type' => 'submit',
'class' => 'btn btn-default pull-right',
'icon' => 'process-icon-save',
),
),
);
return parent::renderForm();
}
protected function renderSourceForm()
{
$this->table = 'source';
$this->className = 'Source';
$this->identifier = 'id_source';
$this->object = null;
if (!($objSource = $this->loadObject(true))) {
return;
}
$businessSources = BusinessSource::getActiveList((int)$this->context->language->id);
$this->fields_form = array(
'legend' => array(
'title' => $this->l('Booking Source'),
'icon' => 'icon-tags'
),
'input' => array(
array(
'type' => 'text',
'label' => $this->l('Name'),
'name' => 'name',
'lang' => true,
'required' => true,
'hint' => $this->l('Invalid characters:').' &lt;&gt;;=#{}'
),
array(
'type' => 'select',
'label' => $this->l('Business Source'),
'name' => 'id_source_type',
'required' => true,
'options' => array(
'query' => $businessSources,
'id' => 'id_source_type',
'name' => 'name',
),
),
array(
'type' => 'text',
'label' => $this->l('Source Code'),
'name' => 'source_code',
'required' => true,
'hint' => $this->l('A short unique machine code, e.g. "BOOKING_COM". Letters, numbers, underscores and hyphens only.')
),
array(
'type' => 'switch',
'label' => $this->l('Enabled'),
'name' => 'active',
'required' => false,
'class' => 't',
'is_bool' => true,
'values' => array(
array('id' => 'active_on', 'value' => 1, 'label' => $this->l('Enabled')),
array('id' => 'active_off', 'value' => 0, 'label' => $this->l('Disabled')),
)
),
),
'submit' => array(
'title' => $this->l('Save'),
'name' => 'submitAddsource'
),
'buttons' => array(
'save-and-stay' => array(
'title' => $this->l('Save and stay'),
'name' => 'submitAddsourceAndStay',
'type' => 'submit',
'class' => 'btn btn-default pull-right',
'icon' => 'process-icon-save',
),
),
);
return parent::renderForm();
}
public function postProcess()
{
if (Tools::isSubmit('submitAddsource') || Tools::isSubmit('submitAddsourceAndStay')) {
return $this->postProcessSource();
} elseif (Tools::isSubmit('submitMergeSource')) {
return $this->postProcessMergeSource();
} elseif (Tools::isSubmit('deletesource')) {
$objSource = new Source((int)Tools::getValue('id_source'));
if (!$objSource->isRemovable()) {
$this->errors[] = $this->l('For security reasons, you cannot delete a built-in Booking Source.');
} elseif (!$objSource->delete()) {
$this->errors[] = Tools::displayError('An error occurred while deleting the Booking Source.');
} else {
Tools::redirectAdmin(self::$currentIndex.'&viewbusiness_source&id_source_type='.(int)$objSource->id_source_type.'&conf=1&token='.$this->token);
}
} else if(Tools::isSubmit('submitBulkenableSelectionsource')){
$idSourceType = (int)Tools::getValue('id_source_type');
$this->className = 'Source';
$this->table = 'source';
$this->boxes = Tools::getValue('sourceBox');
parent::processBulkEnableSelection();
$this->redirect_after = self::$currentIndex.'&viewbusiness_source&id_source_type='.(int)$idSourceType.'&token='.$this->token;
} else if(Tools::isSubmit('submitBulkdisableSelectionsource')){
$idSourceType = (int)Tools::getValue('id_source_type');
$this->className = 'Source';
$this->table = 'source';
$this->boxes = Tools::getValue('sourceBox');
parent::processBulkDisableSelection();
$this->redirect_after = self::$currentIndex.'&viewbusiness_source&id_source_type='.(int)$idSourceType.'&token='.$this->token;
} elseif (Tools::isSubmit('submitBulkdeletesource')) {
$idSourceType = 0;
foreach (Tools::getValue('sourceBox') as $selection) {
$objSource = new Source((int)$selection);
$idSourceType = $objSource->id_source_type;
if (!$objSource->isRemovable()) {
$this->errors[] = $this->l('For security reasons, you cannot delete a built-in Booking Source.');
break;
}
}
if (!count($this->errors)) {
$this->className = 'Source';
$this->table = 'source';
$this->boxes = Tools::getValue('sourceBox');
parent::processBulkDelete();
$this->redirect_after = self::$currentIndex.'&viewbusiness_source&id_source_type='.(int)$idSourceType.'&conf=1&token='.$this->token;
}
} elseif (Tools::isSubmit('submitAddbusiness_source') || Tools::isSubmit('submitAddbusiness_sourceAndStay')) {
return $this->postProcessBusinessSource();
} elseif (Tools::isSubmit('delete'.$this->table)) {
$objBusinessSource = new BusinessSource((int)Tools::getValue('id_source_type'));
if (!$objBusinessSource->isRemovable()) {
$this->errors[] = $this->l('For security reasons, you cannot delete a built-in Business Source.');
} else {
return parent::postProcess();
}
} elseif (Tools::isSubmit('submitBulkdelete'.$this->table)) {
foreach (Tools::getValue($this->table.'Box') as $selection) {
$objBusinessSource = new BusinessSource((int)$selection);
if (!$objBusinessSource->isRemovable()) {
$this->errors[] = $this->l('For security reasons, you cannot delete a built-in Business Source.');
break;
}
}
if (!count($this->errors)) {
return parent::postProcess();
}
} else {
return parent::postProcess();
}
}
protected function postProcessSource()
{
$idSource = (int)Tools::getValue('id_source');
$idSourceType = (int)Tools::getValue('id_source_type');
$sourceCode = trim(Tools::getValue('source_code'));
$defaultLangId = Configuration::get('PS_LANG_DEFAULT');
$objDefaultLanguage = Language::getLanguage((int) $defaultLangId);
$languages = Language::getLanguages(false);
if (!trim(Tools::getValue('name_'.$defaultLangId))) {
$this->errors[] = $this->l('Name is required at least in ').
$objDefaultLanguage['name'];
} else {
foreach ($languages as $lang) {
if (trim(Tools::getValue('name_'.$lang['id_lang']))) {
if (!Validate::isGenericName(Tools::getValue('name_'.$lang['id_lang']))) {
$this->errors[] = $this->l('Invalid name in ').$lang['name'];
}
}
}
}
$objBusinessSource = new BusinessSource($idSourceType);
if (!Validate::isLoadedObject($objBusinessSource) || $objBusinessSource->deleted) {
$this->errors[] = $this->l('Please select a valid Business Source.');
}
if (!$sourceCode || !Validate::isModuleName($sourceCode)) {
$this->errors[] = $this->l('Source Code is invalid. Only letters, numbers, underscores and hyphens are allowed.');
} elseif (Source::codeExists($sourceCode, $idSource)) {
$this->errors[] = $this->l('This Source Code is already used by another Booking Source.');
}
if (count($this->errors)) {
$this->display = $idSource ? 'edit' : 'add';
return false;
}
$objSource = new Source($idSource);
$objSource->id_source_type = $idSourceType;
$objSource->source_code = $sourceCode;
$objSource->active = (int)Tools::getValue('active');
$objSource->name = array();
foreach (Language::getIDs(false) as $idLang) {
$objSource->name[$idLang] = Tools::getValue('name_'.$idLang);
}
if (!$objSource->save()) {
$this->errors[] = Tools::displayError('An error occurred while saving the Booking Source.');
$this->display = $idSource ? 'edit' : 'add';
return false;
}
if (Tools::isSubmit('submitAddsourceAndStay')) {
Tools::redirectAdmin(self::$currentIndex.'&updatesource&id_source='.$objSource->id.'&conf='.($idSource ? 4 : 3).'&token='.$this->token);
}
Tools::redirectAdmin(self::$currentIndex.'&viewbusiness_source&id_source_type='.$idSourceType.'&conf='.($idSource ? 4 : 3).'&token='.$this->token);
}
protected function postProcessMergeSource()
{
$idSourceType = (int)Tools::getValue('id_source_type');
$idCurrentSource = (int)Tools::getValue('merge_current_source');
$idTargetSource = (int)Tools::getValue('merge_target_source');
$objCurrent = new Source($idCurrentSource);
$objTarget = new Source($idTargetSource);
if (!Validate::isLoadedObject($objCurrent) || !Validate::isLoadedObject($objTarget)
|| (int)$objCurrent->id_source_type !== $idSourceType || (int)$objTarget->id_source_type !== $idSourceType
) {
$this->errors[] = $this->l('Please select valid Current and Target Booking Sources.');
} elseif ($idCurrentSource === $idTargetSource) {
$this->errors[] = $this->l('Current and Target Booking Source cannot be the same.');
} else {
$objCurrent->mergeOrdersInto($idTargetSource);
}
if (!count($this->errors)) {
Tools::redirectAdmin(self::$currentIndex.'&viewbusiness_source&id_source_type='.$idSourceType.'&conf=4&token='.$this->token);
}
}
protected function postProcessBusinessSource()
{
$idSourceType = (int)Tools::getValue('id_source_type');
$sourceTypeCode = trim(Tools::getValue('source_type_code'));
$defaultLangId = Configuration::get('PS_LANG_DEFAULT');
$objDefaultLanguage = Language::getLanguage((int) $defaultLangId);
$languages = Language::getLanguages(false);
if (!trim(Tools::getValue('name_'.$defaultLangId))) {
$this->errors[] = $this->l('Name is required at least in ').
$objDefaultLanguage['name'];
} else {
foreach ($languages as $lang) {
if (trim(Tools::getValue('name_'.$lang['id_lang']))) {
if (!Validate::isGenericName(Tools::getValue('name_'.$lang['id_lang']))) {
$this->errors[] = $this->l('Invalid name in ').$lang['name'];
}
}
}
}
if (!$sourceTypeCode || !Validate::isModuleName($sourceTypeCode)) {
$this->errors[] = $this->l('Code is invalid. Only letters, numbers, underscores and hyphens are allowed.');
} elseif (BusinessSource::codeExists($sourceTypeCode, $idSourceType)) {
$this->errors[] = $this->l('This Code is already used by another Business Source.');
}
if (count($this->errors)) {
$this->display = $idSourceType ? 'edit' : 'add';
return false;
}
return parent::postProcess();
}
public function formatOrdersPercentage($count, $row)
{
$percentage = $this->ordersTotal ? round(((int)$count / $this->ordersTotal) * 100, 1) : 0;
return $percentage.'%';
}
public function displayMergeLink($token, $id, $name = null)
{
$idSourceType = (int) Tools::getValue('id_source_type');
return '<a href="#"
class="merge-source-btn"
title="' . $this->l('Merge') . '"
data-id-source="' . (int) $id . '"
data-id-source-type="' . $idSourceType . '"
data-ajax-url="' . self::$currentIndex . '&token=' . ($token ?: $this->token) . '">
<i class="icon-random"></i> ' . $this->l('Merge') . '
</a>';
}
public function ajaxProcessInitMergeSourceModal()
{
$response = array('hasError' => 1);
if ($this->tabAccess['edit'] === 1) {
$idSourceType = (int)Tools::getValue('id_source_type');
$idSource = (int)Tools::getValue('id_source');
$objSource = new Source($idSource);
if (Validate::isLoadedObject($objSource) && (int)$objSource->id_source_type === $idSourceType) {
$this->context->smarty->assign(array(
'sources' => Source::getActiveListForType($idSourceType, (int)$this->context->language->id),
'id_current_source' => $idSource,
'id_source_type' => $idSourceType,
'current_index' => self::$currentIndex,
'token' => $this->token,
));
$this->context->smarty->assign(array(
'modal_id' => 'merge_source_modal',
'modal_class' => 'modal-md',
'modal_title' => $this->l('Merge Booking Source'),
'modal_content' => $this->context->smarty->fetch('controllers/sources/modals/_merge_source_form.tpl'),
));
$response['hasError'] = 0;
$response['modalHtml'] = $this->context->smarty->fetch('modal.tpl');
}
}
die(Tools::jsonEncode($response));
}
protected function filterToField($key, $filter)
{
if ($this->table == 'source') {
$this->initSourcesList();
} else {
$this->initBusinessSourcesList();
}
return parent::filterToField($key, $filter);
}
public function ajaxProcessUpdatePositions()
{
if ($this->tabAccess['edit'] !== 1) {
die(json_encode(array('hasError' => true, 'errors' => $this->l('You do not have permission to edit this.'))));
}
$way = (int)Tools::getValue('way');
$id = (int)Tools::getValue('id');
if ($positions = Tools::getValue('source')) {
$className = 'Source';
} elseif ($positions = Tools::getValue('source_type')) {
$className = 'BusinessSource';
} else {
die(json_encode(array('hasError' => true, 'errors' => 'Unknown table for position update.')));
}
foreach ($positions as $position => $value) {
$pos = explode('_', $value);
if (isset($pos[2]) && (int)$pos[2] === $id) {
if ($object = new $className((int)$pos[2])) {
if (isset($position) && $object->updatePosition($way, $position)) {
echo 'ok position '.(int)$position.' for '.$className.' '.$id;
} else {
echo '{"hasError" : true, "errors" : "Can not update tab '.(int)$id.' to position '.(int)$position.' "}';
}
} else {
echo json_encode(array(
'hasError' => true,
'errors' => 'Can not update '.$className.' '.$id.' to position '.(int)$position,
));
}
break;
}
}
}
}

View File

@@ -1174,6 +1174,7 @@ CREATE TABLE `PREFIX_orders` (
`invoice_date` datetime NOT NULL,
`delivery_date` datetime NOT NULL,
`source` varchar(255) DEFAULT NULL,
`id_source` int(10) unsigned DEFAULT NULL,
`valid` int(1) unsigned NOT NULL DEFAULT '0',
`is_advance_payment` tinyint(1) NOT NULL DEFAULT '0',
`advance_paid_amount` decimal(20,6) NOT NULL DEFAULT '0.00',
@@ -1193,6 +1194,7 @@ CREATE TABLE `PREFIX_orders` (
KEY `id_shop_group` (`id_shop_group`),
KEY (`current_state`),
KEY `id_shop` (`id_shop`),
KEY `id_source` (`id_source`),
INDEX `date_add`(`date_add`)
) ENGINE=ENGINE_TYPE DEFAULT CHARSET=utf8 COLLATION;
@@ -1879,6 +1881,48 @@ CREATE TABLE `PREFIX_search_word` (
UNIQUE KEY `id_lang` (`id_lang`,`id_shop`, `word`)
) ENGINE=ENGINE_TYPE DEFAULT CHARSET=utf8 COLLATION;
CREATE TABLE `PREFIX_business_source` (
`id_source_type` int(10) unsigned NOT NULL auto_increment,
`source_type_code` varchar(64) NOT NULL,
`position` int(10) unsigned NOT NULL DEFAULT '0',
`unremovable` tinyint(1) UNSIGNED NOT NULL DEFAULT '0',
`active` tinyint(1) UNSIGNED NOT NULL DEFAULT '1',
`deleted` tinyint(1) UNSIGNED NOT NULL DEFAULT '0',
`date_add` datetime NOT NULL,
`date_upd` datetime NOT NULL,
PRIMARY KEY (`id_source_type`),
UNIQUE KEY `source_type_code` (`source_type_code`)
) ENGINE=ENGINE_TYPE DEFAULT CHARSET=utf8 COLLATION;
CREATE TABLE `PREFIX_business_source_lang` (
`id_source_type` int(10) unsigned NOT NULL,
`id_lang` int(10) unsigned NOT NULL,
`name` varchar(64) NOT NULL,
PRIMARY KEY (`id_source_type`,`id_lang`)
) ENGINE=ENGINE_TYPE DEFAULT CHARSET=utf8 COLLATION;
CREATE TABLE `PREFIX_source` (
`id_source` int(10) unsigned NOT NULL auto_increment,
`id_source_type` int(10) unsigned NOT NULL,
`source_code` varchar(64) NOT NULL,
`position` int(10) unsigned NOT NULL DEFAULT '0',
`unremovable` tinyint(1) UNSIGNED NOT NULL DEFAULT '0',
`active` tinyint(1) UNSIGNED NOT NULL DEFAULT '1',
`deleted` tinyint(1) UNSIGNED NOT NULL DEFAULT '0',
`date_add` datetime NOT NULL,
`date_upd` datetime NOT NULL,
PRIMARY KEY (`id_source`),
UNIQUE KEY `source_code` (`source_code`),
KEY `id_source_type` (`id_source_type`)
) ENGINE=ENGINE_TYPE DEFAULT CHARSET=utf8 COLLATION;
CREATE TABLE `PREFIX_source_lang` (
`id_source` int(10) unsigned NOT NULL,
`id_lang` int(10) unsigned NOT NULL,
`name` varchar(64) NOT NULL,
PRIMARY KEY (`id_source`,`id_lang`)
) ENGINE=ENGINE_TYPE DEFAULT CHARSET=utf8 COLLATION;
CREATE TABLE `PREFIX_specific_price` (
`id_specific_price` INT UNSIGNED NOT NULL AUTO_INCREMENT,
`id_specific_price_rule` INT(11) UNSIGNED NOT NULL,

View File

@@ -0,0 +1,21 @@
<?xml version="1.0" encoding="UTF-8"?>
<entity_business_source>
<fields id="name" class="BusinessSource">
<field name="source_type_code"/>
<field name="position"/>
<field name="unremovable"/>
<field name="active"/>
</fields>
<entities>
<business_source id="Direct" source_type_code="DIRECT" position="1" unremovable="1" active="1">
</business_source>
<business_source id="OTA" source_type_code="OTA" position="2" unremovable="1" active="1">
</business_source>
<business_source id="Corporate" source_type_code="CORPORATE" position="3" unremovable="1" active="1">
</business_source>
<business_source id="Travel_Agent" source_type_code="TRAVEL_AGENT" position="4" unremovable="1" active="1">
</business_source>
<business_source id="Group" source_type_code="GROUP" position="5" unremovable="1" active="1">
</business_source>
</entities>
</entity_business_source>

View File

@@ -0,0 +1,34 @@
<?xml version="1.0" encoding="UTF-8"?>
<entity_source>
<fields id="name" class="Source">
<field name="id_source_type" relation="business_source"/>
<field name="source_code"/>
<field name="position"/>
<field name="unremovable"/>
<field name="active"/>
</fields>
<entities>
<source id="Direct_Website" id_source_type="Direct" source_code="DIRECT_WEBSITE" position="1" unremovable="1" active="1">
</source>
<source id="Walk_in" id_source_type="Direct" source_code="WALKIN" position="2" unremovable="1" active="1">
</source>
<source id="Phone" id_source_type="Direct" source_code="PHONE" position="3" unremovable="0" active="1">
</source>
<source id="Email" id_source_type="Direct" source_code="EMAIL" position="4" unremovable="0" active="1">
</source>
<source id="Social_Media" id_source_type="Direct" source_code="SOCIAL_MEDIA" position="0" unremovable="1" active="1">
</source>
<source id="WhatsApp" id_source_type="Direct" source_code="WHATSAPP" position="6" unremovable="0" active="1">
</source>
<source id="Booking_com" id_source_type="OTA" source_code="BOOKING_COM" position="7" unremovable="0" active="1">
</source>
<source id="Expedia" id_source_type="OTA" source_code="EXPEDIA" position="8" unremovable="0" active="1">
</source>
<source id="GoMMT" id_source_type="OTA" source_code="GOMMT" position="9" unremovable="0" active="1">
</source>
<source id="Agoda" id_source_type="OTA" source_code="AGODA" position="10" unremovable="0" active="1">
</source>
<source id="Airbnb" id_source_type="OTA" source_code="AIRBNB" position="11" unremovable="0" active="1">
</source>
</entities>
</entity_source>

View File

@@ -117,6 +117,9 @@
<tab id="Statuses" id_parent="Orders" active="1" hide_host_mode="0">
<class_name>AdminStatuses</class_name>
</tab>
<tab id="Sources" id_parent="Orders" active="1" hide_host_mode="0">
<class_name>AdminSources</class_name>
</tab>
<tab id="Order_Messages" id_parent="Orders" active="1" hide_host_mode="0">
<class_name>AdminOrderMessage</class_name>
</tab>

View File

@@ -0,0 +1,18 @@
<?xml version="1.0"?>
<entity_business_source>
<business_source id="Direct">
<name>Direct</name>
</business_source>
<business_source id="OTA">
<name>OTA</name>
</business_source>
<business_source id="Corporate">
<name>Corporate</name>
</business_source>
<business_source id="Travel_Agent">
<name>Travel Agent</name>
</business_source>
<business_source id="Group">
<name>Group</name>
</business_source>
</entity_business_source>

View File

@@ -0,0 +1,36 @@
<?xml version="1.0"?>
<entity_source>
<source id="Direct_Website">
<name>Direct Website</name>
</source>
<source id="Walk_in">
<name>Walk-in</name>
</source>
<source id="Phone">
<name>Phone</name>
</source>
<source id="Email">
<name>Email</name>
</source>
<source id="Social_Media">
<name>Social Media</name>
</source>
<source id="WhatsApp">
<name>WhatsApp</name>
</source>
<source id="Booking_com">
<name>Booking.com</name>
</source>
<source id="Expedia">
<name>Expedia</name>
</source>
<source id="GoMMT">
<name>GoMMT (GoIbibo/MakeMyTrip)</name>
</source>
<source id="Agoda">
<name>Agoda</name>
</source>
<source id="Airbnb">
<name>Airbnb</name>
</source>
</entity_source>

View File

@@ -37,6 +37,7 @@
<tab id="Delivery_Slips" name="Delivery Slips"/>
<tab id="Credit_Slips" name="Credit Slips"/>
<tab id="Statuses" name="Statuses"/>
<tab id="Sources" name="Business Sources"/>
<tab id="Order_Messages" name="Order Messages"/>
<tab id="Customers_1" name="Customers"/>
<tab id="Addresses" name="Addresses"/>

View File

@@ -537,6 +537,14 @@ class InstallModelInstall extends InstallAbstractModel
Configuration::updateGlobalValue('PS_OS_OUTOFSTOCK_PAID', (int)Configuration::get('PS_OS_OUTOFSTOCK'));
}
// Set the default Booking Source (Direct Website)
$id_default_source = (int)Db::getInstance()->getValue(
'SELECT `id_source` FROM '._DB_PREFIX_.'source WHERE `source_code` = \'DIRECT_WEBSITE\''
);
if ($id_default_source) {
Configuration::updateGlobalValue('PS_DEFAULT_BOOKING_SOURCE', $id_default_source);
}
// Set logo configuration
if (file_exists(_PS_IMG_DIR_.'logo.png')) {
list($width, $height) = getimagesize(_PS_IMG_DIR_.'logo.png');

44
js/admin/sources.js Normal file
View File

@@ -0,0 +1,44 @@
/**
* NOTICE OF LICENSE
*
* This source file is subject to the Open Software License version 3.0
* that is bundled with this package in the file LICENSE.md
* It is also available through the world-wide-web at this URL:
* https://opensource.org/license/osl-3-0-php
*
* @author Webkul IN
* @copyright Since 2010 Webkul
* @license https://opensource.org/license/osl-3-0-php Open Software License version 3.0
*/
$(document).on('click', '.merge-source-btn', function (e) {
e.preventDefault();
var $btn = $(this);
$('.loading_overlay').show();
$.ajax({
type: 'POST',
url: $btn.data('ajax-url'),
dataType: 'JSON',
cache: false,
data: {
ajax: true,
action: 'InitMergeSourceModal',
id_source: $btn.data('id-source'),
id_source_type: $btn.data('id-source-type')
},
success: function (result) {
if (!result.hasError && result.modalHtml) {
$('#merge_source_modal').remove();
$('#footer').next('.bootstrap').append(result.modalHtml);
$('#merge_source_modal').modal('show');
} else {
showErrorMessage(result.error || 'Could not open the merge form.');
}
},
complete: function () {
$('.loading_overlay').hide();
}
});
});