Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added: Service products can now be assigned to a room type from room type edit page at back office #890

Merged
merged 10 commits into from
Mar 14, 2024
121 changes: 89 additions & 32 deletions admin/themes/default/template/controllers/products/serviceproduct.tpl
Original file line number Diff line number Diff line change
Expand Up @@ -3,77 +3,134 @@
<input type="hidden" name="submitted_tabs[]" value="ServiceProduct" />
<h3 class="tab"> <i class="icon-AdminAdmin"></i> {l s='Service Products'}</h3>

{if isset($service_products) && $service_products}
{if (isset($associated_service_products) && $associated_service_products) || (isset($unassociated_service_products) && $unassociated_service_products)}
<div class="from-group table-responsive-row clearfix">
<table class="table tableDnD hotel-roomtype-link-table">
<table class="table hotel-roomtype-link-table">
<thead>
<tr class="nodrag nodrop">
<th class="text-center">
<input type="checkbox" class="bulk-service-products-status">
</th>
<th class="col-sm-1">
<span>{l s='Id Product'}</span>
<span>{l s='ID'}</span>
</th>
<th class="col-sm-3">
<span>{l s='name'}</span>
<th class="col-sm-2">
<span>{l s='Name'}</span>
</th>
<th class="">
<span>{l s='Auto add to cart'}</span>
<th class="text-center">
<span>{l s='Auto Add to Cart'}</span>
</th>
<th>
<span>{l s='Position'}</span>
</th>
<th class="">
<th>
<span>{l s='Price'}</span>
</th>
<th class="">
<th>
<span>{l s='Tax'}</span>
</th>
<th class="text-right">
<span>{l s='Action'}</span>
</th>
</tr>
</thead>
<tbody>
{foreach from=$service_products key=key item=service_product}
<tr id='room_type_service_product_{$service_product.id_room_type_service_product|escape:'html':'UTF-8'}' position='{$service_product.position|escape:'html':'UTF-8'}' id_product='{$service_product.id_product|escape:'html':'UTF-8'}' id_element="{$product->id}" data-roomtype_url="{$link->getAdminLink('AdminProducts', true)|addslashes}">
<td class="col-sm-1">{$service_product.id_product|escape:'html':'UTF-8'} <a target="blank" href="{$link->getAdminLink('AdminNormalProducts')|escape:'html':'UTF-8'}&amp;id_product={$service_product.id_product|escape:'html':'UTF-8'}&amp;updateproduct"><i class="icon-external-link-sign"></i></a></td>
{foreach from=$associated_service_products item=service_product}
<tr id='room_type_service_product_{$service_product.id_product|escape:'html':'UTF-8'}' position="{$service_product.association_info.position|escape:'html':'UTF-8'}" id_product='{$service_product.id_product|escape:'html':'UTF-8'}' id_element="{$product->id}" data-roomtype_url="{$link->getAdminLink('AdminProducts', true)|addslashes}">
{assign var=inputs_prefix value="service_product_`$service_product.id_product`_"}
<input type="hidden" name="available_service_products[]" value="{$service_product.id_product}">

<td class="text-center">
<input type="checkbox" name="{$inputs_prefix}associated" class="is-associated" checked>
</td>
<td class="col-sm-1">
{$service_product.id_product|escape:'html':'UTF-8'}
<a target="blank" href="{$link->getAdminLink('AdminNormalProducts')|escape:'html':'UTF-8'}&amp;id_product={$service_product.id_product|escape:'html':'UTF-8'}&amp;updateproduct">
<i class="icon-external-link-sign"></i>
</a>
</td>
<td>{$service_product.name}</td>
<td><span {if $service_product.auto_add_to_cart}class="badge badge-success"{/if}>{if $service_product.auto_add_to_cart}{l s='Yes'}{else}{l s='No'}{/if}</span></td>
<td class="text-center">
<span {if $service_product.auto_add_to_cart}class="badge badge-success"{/if}>
{if $service_product.auto_add_to_cart}{l s='Yes'}{else}{l s='No'}{/if}
</span>
</td>
<td class="pointer dragHandle center positionImage">
<div class="dragGroup">
<div class="positions">
{$service_product.position + 1}
{$service_product.association_info.position + 1}
</div>
</div>
</td>
<td>
<span class="field-view service-product-price-text">{if isset($service_product.custom_price) && $service_product.custom_price}{displayPrice price=$service_product.custom_price currency=$currency->id}{else}{displayPrice price=$service_product.default_price currency=$currency->id}{/if}</span>
<div class="field-edit" style="display:none">
<div class="fixed-width-xl">
<div class="input-group">
<input type="text" value="{if isset($service_product.custom_price) && $service_product.custom_price}{$service_product.custom_price|escape:'html':'UTF-8'}{else}{$service_product.default_price|escape:'html':'UTF-8'}{/if}" class="service-product-price" data-id_product="{$service_product.id_product|escape:'html':'UTF-8'}">
<span class="input-group-addon">{$currency->prefix}{$currency->suffix}</span>
{assign var=price_value value=0}
{if isset($smarty.post["{$inputs_prefix}price"])}
{assign var=price_value value=$smarty.post["{$inputs_prefix}price"]}
{else}
{if isset($service_product.association_info.custom_price)}
{assign var=price_value value=$service_product.association_info.custom_price}
{elseif isset($service_product.association_info.default_price)}
{assign var=price_value value=$service_product.association_info.default_price}
{/if}
{/if}
<input type="text" name="{$inputs_prefix}price" value="{$price_value}" data-id_product="{$service_product.id_product}">
</div>
</div>
<div class="help-block">{l s='Default price: %s' sprintf={displayPrice price=$service_product.default_price currency=$currency->id}}
<div class="help-block">
{l s='Default price: %s' sprintf={displayPrice price=$service_product.association_info.default_price currency=$currency->id}}
</div>
</td>
<td>
<span class="field-view service_product_tax_text">{if isset($service_product.tax_rules_group_name) && $service_product.tax_rules_group_name}{$service_product.tax_rules_group_name}{else}{$service_product.default_tax_rules_group_name}{/if}</span>
<div class="field-edit" style="display:none">
<select class="service_product_id_tax_rules_group">
<div class="fixed-width-xl">
<select class="service_product_id_tax_rules_group" name="{$inputs_prefix}id_tax_rules_group">
<option value="0">{l s='No Tax'}</option>
{foreach from=$tax_rules_groups item=tax_rules_group}
<option value="{$tax_rules_group.id_tax_rules_group}" {if $service_product.id_tax_rules_group == $tax_rules_group.id_tax_rules_group}selected="selected"{/if} >
<option value="{$tax_rules_group.id_tax_rules_group}" {if $service_product.association_info.id_tax_rules_group == $tax_rules_group.id_tax_rules_group}selected="selected"{/if} >
{$tax_rules_group['name']|htmlentitiesUTF8}
</option>
{/foreach}
</select>
</div>
<div class="help-block">{l s='Default tax rule: %s' sprintf=$service_product.default_tax_rules_group_name}
<div class="help-block">{l s='Default tax rule: %s' sprintf=$service_product.association_info.default_tax_rules_group_name}</div>
</td>
<td class="text-right">
<a href="#" class="btn btn-default button-edit-price field-view"><i class="icon-pencil"></i></a>
<span class="field-edit" style="display:none">
<a href="#" class="btn btn-default btn-save" data-roomtype_url="{$link->getAdminLink('AdminProducts', true)|addslashes}" data-id_product="{$service_product.id_product|escape:'html':'UTF-8'}"><i class="icon-save"></i> {l s='save'}</a>
<a href="#" class="btn btn-default btn-cancel"><i class="icon-times"></i></a>
</span>
</tr>
{/foreach}

{foreach from=$unassociated_service_products item=service_product}
<tr class="nodrop nodrag">
{assign var=inputs_prefix value="service_product_`$service_product.id_product`_"}
<input type="hidden" name="available_service_products[]" value="{$service_product.id_product}">

<td class="text-center">
<input type="checkbox" name="{$inputs_prefix}associated" class="is-associated" {if isset($smarty.post["{$inputs_prefix}associated"]) && in_array($smarty.post["{$inputs_prefix}associated"], array('on', 'true', '1'))}checked{/if}>
</td>
<td class="col-sm-1">{$service_product.id_product|escape:'html':'UTF-8'} <a target="blank" href="{$link->getAdminLink('AdminNormalProducts')|escape:'html':'UTF-8'}&amp;id_product={$service_product.id_product|escape:'html':'UTF-8'}&amp;updateproduct"><i class="icon-external-link-sign"></i></a></td>
<td>{$service_product.name}</td>
<td class="text-center"><span {if $service_product.auto_add_to_cart}class="badge badge-success"{/if}>{if $service_product.auto_add_to_cart}{l s='Yes'}{else}{l s='No'}{/if}</span></td>
<td>{l s='--'}</td>
<td>
<div class="fixed-width-xl">
<div class="input-group">
<span class="input-group-addon">{$currency->prefix}{$currency->suffix}</span>
<input type="text" name="{$inputs_prefix}price" data-id_product="{$service_product.id_product|escape:'html':'UTF-8'}" value="{if isset($smarty.post["{$inputs_prefix}price"]) && $smarty.post["{$inputs_prefix}price"]}{$smarty.post["{$inputs_prefix}price"]}{else}{$service_product.price}{/if}">
</div>
</div>
<div class="help-block">
{l s='Default price: %s' sprintf={displayPrice price=$service_product.price currency=$currency->id}}
</div>
</td>
<td>
<div class="fixed-width-xl">
<select class="service_product_id_tax_rules_group" name="{$inputs_prefix}id_tax_rules_group">
<option value="0">{l s='No Tax'}</option>
{foreach from=$tax_rules_groups item=tax_rules_group}
<option value="{$tax_rules_group.id_tax_rules_group}" {if isset($smarty.post["{$inputs_prefix}id_tax_rules_group"])}{if $tax_rules_group.id_tax_rules_group == $smarty.post["{$inputs_prefix}id_tax_rules_group"]}{/if}{elseif $tax_rules_group.id_tax_rules_group == $service_product.id_tax_rules_group}selected{/if}>
{$tax_rules_group['name']|htmlentitiesUTF8}
</option>
{/foreach}
</select>
</div>
<div class="help-block">{l s='Default tax rule: %s' sprintf=$service_product.tax_rules_group_name}</div>
</td>
</tr>
{/foreach}
Expand Down
32 changes: 17 additions & 15 deletions classes/Product.php
Original file line number Diff line number Diff line change
Expand Up @@ -1454,23 +1454,25 @@ public function getAvailableServiceProductsCategories($id_lang, $front = false,
return $result;
}

public function getServiceProducts($idLang, $front = false, $context = false)
public function getServiceProducts($active = null, $serviceProductType = null, $idLang = null, $orderBy = 'pl.name', $orderWay = 'ASC')
{
if (!$context) {
$context = Context::getContext();
if (!$idLang) {
$idLang = Context::getContext()->language->id;
}
$sql = 'SELECT p.*, product_shop.*, pl.*, image_shop.`id_image` id_image, il.`legend` as legend
FROM `'._DB_PREFIX_.'product` p
'.Shop::addSqlAssociation('product', 'p').'
LEFT JOIN `'._DB_PREFIX_.'product_lang` pl ON (p.`id_product` = pl.`id_product` '.Shop::addSqlRestrictionOnLang('pl').')
LEFT JOIN `'._DB_PREFIX_.'image_shop` image_shop
ON (image_shop.`id_product` = p.`id_product` AND image_shop.cover=1 AND image_shop.id_shop='.(int)$context->shop->id.')
LEFT JOIN `'._DB_PREFIX_.'image_lang` il
ON (image_shop.`id_image` = il.`id_image`
AND il.`id_lang` = '.(int)$idLang.')';
$sql .= 'WHERE pl.`id_lang` = '.(int)$idLang.' AND p.`booking_product` = 0
AND p.`service_product_type` = '.Product::SERVICE_PRODUCT_WITHOUT_ROOMTYPE.'
ORDER BY pl.`name`';

$sql = 'SELECT p.*, pl.*, i.`id_image`, il.`legend` AS legend
FROM `'._DB_PREFIX_.'product` p
LEFT JOIN `'._DB_PREFIX_.'product_lang` pl ON (pl.`id_product` = p.`id_product` AND pl.`id_lang` = '.(int) $idLang.')
LEFT JOIN `'._DB_PREFIX_.'image` i ON (i.`id_product` = p.`id_product` AND i.`cover` = 1)
LEFT JOIN `'._DB_PREFIX_.'image_lang` il ON (il.`id_image` = i.`id_image` AND il.`id_lang` = '.(int) $idLang.')
WHERE p.`booking_product` = 0'.
(!is_null($active) ? ' AND p.`active` = '.(int) $active : '').
($serviceProductType ? ' AND p.`service_product_type` = '.(int) $serviceProductType : '');

if (Validate::isOrderBy($orderBy) && Validate::isOrderBy($orderWay)) {
$sql .= ' ORDER BY '.$orderBy.' '.$orderWay;
}

return Db::getInstance(_PS_USE_SQL_SLAVE_)->executeS($sql);
}

Expand Down
47 changes: 41 additions & 6 deletions controllers/admin/AdminNormalProductsController.php
Original file line number Diff line number Diff line change
Expand Up @@ -2791,18 +2791,53 @@ public function getPreviewUrl(Product $product)
public function updateLinkedHotelsAndRooms($product)
{
if (Validate::isLoadedObject($product)) {
RoomTypeServiceProduct::deleteRoomProductLink($product->id);

$objRoomTypeServiceProduct = new RoomTypeServiceProduct();
$associatedRoomTypes = $objRoomTypeServiceProduct->getAssociatedHotelsAndRoomType($product->id)['room_types'];
if (Product::SERVICE_PRODUCT_WITH_ROOMTYPE == $product->service_product_type) {
$objRoomTypeServiceProduct = new RoomTypeServiceProduct();
// add product link for room types
if ($selectedRoomTypes = Tools::getValue('roomTypeBox')) {
$selectedRoomTypes = Tools::getValue('roomTypeBox');

// Generate list of new associations
$newRoomTypes = array();
foreach ($selectedRoomTypes as $selectedRoomType) {
if (!in_array($selectedRoomType, $associatedRoomTypes)) {
$newRoomTypes[] = $selectedRoomType;
}
}

// Generate list of associations to remove
$removedRoomTypes = array();
foreach ($associatedRoomTypes as $associatedRoomType) {
if (!in_array($associatedRoomType, $selectedRoomTypes)) {
$removedRoomTypes[] = $associatedRoomType;
}
}

// Remove associations
foreach ($removedRoomTypes as $removedRoomType) {
RoomTypeServiceProduct::deleteRoomProductLink(
$product->id,
RoomTypeServiceProduct::WK_ELEMENT_TYPE_ROOM_TYPE,
$removedRoomType
);
}

// Save new associations
if ($newRoomTypes) {
$objRoomTypeServiceProduct->addRoomProductLink(
$product->id,
$selectedRoomTypes,
$newRoomTypes,
RoomTypeServiceProduct::WK_ELEMENT_TYPE_ROOM_TYPE
);
}
} else {
// Remove associations
foreach ($associatedRoomTypes as $associatedRoomType) {
RoomTypeServiceProduct::deleteRoomProductLink(
$product->id,
RoomTypeServiceProduct::WK_ELEMENT_TYPE_ROOM_TYPE,
$associatedRoomType
);
}
}
}
}
Expand Down
Loading