diff --git a/admin/ajax.php b/admin/ajax.php index 2506e809d..57e492364 100644 --- a/admin/ajax.php +++ b/admin/ajax.php @@ -127,4 +127,4 @@ if (Tools::isSubmit('getZones')) { if (Tools::isSubmit('getEmailHTML') && $email = Tools::getValue('email')) { $email_html = AdminTranslationsController::getEmailHTML($email); die($email_html); -} +} \ No newline at end of file diff --git a/admin/filemanager/js/jquery.contextMenu.js b/admin/filemanager/js/jquery.contextMenu.js index 103a58582..136efe9b7 100644 --- a/admin/filemanager/js/jquery.contextMenu.js +++ b/admin/filemanager/js/jquery.contextMenu.js @@ -125,7 +125,7 @@ var // currently active contextMenu trigger offset = {top: y, left: x}; } - // correct offset if viewport demands it + // correct offset if viewport it var bottom = $win.scrollTop() + $win.height(), right = $win.scrollLeft() + $win.width(), height = opt.$menu.height(), diff --git a/admin/themes/default/template/controllers/carts/helpers/view/view.tpl b/admin/themes/default/template/controllers/carts/helpers/view/view.tpl index b26103a19..c4cacfa00 100644 --- a/admin/themes/default/template/controllers/carts/helpers/view/view.tpl +++ b/admin/themes/default/template/controllers/carts/helpers/view/view.tpl @@ -107,92 +107,42 @@
- {$roomDemand['name']|escape:'html':'UTF-8'}
- {if isset($roomDemand['adv_option']) && $roomDemand['adv_option']}
- {$roomDemand['adv_option'][$demand['id_option']]['name']}
- {/if}
-
- {if isset($roomDemand['adv_option']) && $roomDemand['adv_option']} - {convertPrice price = $roomDemand['adv_option'][$demand['id_option']]['price_tax_excl']|escape:'html':'UTF-8'} - {else} - {convertPrice price = $roomDemand['price_tax_excl']|escape:'html':'UTF-8'} - {/if} -
-{if $nationality}{$nationality}{else}--{/if}
+| - | {l s='Name'} | -{l s='Options'} | -{l s='Unit Price (tax excl.)'} | -
|---|---|---|---|
| - - | -
- {$demand['name']|escape:'html':'UTF-8'} - |
- - {if isset($demand['adv_option']) && $demand['adv_option']} - - {else} - -- - - {/if} - | -- - {if isset($selected_adv_option) && isset($demand['adv_option'][$selected_adv_option]['price_tax_excl'])}{convertPrice price = $demand['adv_option'][$selected_adv_option]['price_tax_excl']|escape:'html':'UTF-8'}{else if isset($demand['adv_option']) && $demand['adv_option']}{convertPrice price = $demand['adv_option'][$demand['adv_option']|@key]['price_tax_excl']}{else}{convertPrice price = $demand['price_tax_excl']|escape:'html':'UTF-8'}{/if} - - {if $demand['price_calc_method'] == HotelRoomTypeGlobalDemand::WK_PRICE_CALC_METHOD_EACH_DAY} - {l s='/ night'} - {/if} - | -
@@ -80,6 +76,10 @@ {l s='Cancel'} + {*$toggle_button*}
| + + | ++ + | ++ + | +-- | +
|---|---|---|---|
| + + | ++ + | +
+
+
+
+
+ |
+ + + + + + | +
| + + | ++ + | ++ + | +-- | +
|---|---|---|---|
| + + | ++ + | +
+
+
+
+
+ |
+ + + + + + | +
| + | + | -- | +
|---|---|---|
|
+
+
+
+
+ |
+
+
+
+
+
+ |
+ + + + + + | +
' + . $this->l('Uncheck days when the tax should not apply within the date range.') + . '
', + 'form_group_class' => 'tourism-tax-field', + ), ), + 'submit' => array('title' => $this->l('Save')), 'buttons' => array( 'save-and-stay' => array( 'title' => $this->l('Save and stay'), - 'name' => 'submitAdd'.$this->table.'AndStay', + 'name' => 'submitAdd' . $this->table . 'AndStay', 'type' => 'submit', 'class' => 'btn btn-default pull-right', 'icon' => 'process-icon-save', @@ -248,25 +816,72 @@ class AdminTaxesControllerCore extends AdminController return parent::renderForm(); } + /** + * List column callback: display a Yes/No badge for is_tourism_tax. + * + * @param mixed $value 1 or 0 + * @param array $row + * @return string + */ + public function displayTourismTaxBadge($value, $row) + { + if ($value) { + return '' . $this->l('Yes') . ''; + } + return '' . $this->l('No') . ''; + } + + /** + * List column callback: display tax rate with the correct symbol. + * Tourism-fixed taxes show currency sign; tourism-percent and regular taxes show %. + * + * @param mixed $value ps_tax.rate + * @param array $row Full list row (includes tourism_tax_calc_type, tourism_tax_value from join) + * @return string + */ + public function displayRate($value, $row) + { + return TaxConfiguration::getFormattedRateForDisplay($value, $row, $this->context->currency); + } + public function postProcess() { if ($this->action == 'save') { + if ((int) Tools::getValue('is_tourism_tax')) { + $_POST['rate'] = '0'; + } /* Checking fields validity */ $this->validateRules(); + $this->validateTourismTaxFields(); if (!count($this->errors)) { - $id = (int)(Tools::getValue('id_'.$this->table)); + $existingTaxId = (int)(Tools::getValue('id_'.$this->table)); + $isTourismTax = (int) Tools::getValue('is_tourism_tax'); /* Object update */ - if (isset($id) && !empty($id)) { + if (isset($existingTaxId) && !empty($existingTaxId)) { /** @var Tax $object */ - $object = new $this->className($id); + $object = new $this->className($existingTaxId); if (Validate::isLoadedObject($object)) { + $wasTourismTax = (int) $object->is_tourism_tax; $this->copyFromPost($object, $this->table); $result = $object->update(false, false); if (!$result) { $this->errors[] = Tools::displayError('An error occurred while updating an object.').' '.$this->table.''; } elseif ($this->postImage($object->id)) { + if ($isTourismTax) { + self::saveTourismTaxSubtype($object->id); + } + if ($wasTourismTax && !$isTourismTax) { + $this->cleanTaxFromTourismTaxRulesGroups($object->id); + $tourismTax = TaxConfiguration::getByTaxId($object->id); + if ($tourismTax) { + $tourismTax->delete(); + } + } + if (!$wasTourismTax && $isTourismTax) { + $this->cleanTaxFromVatTaxRulesGroups($object->id); + } if (Tools::isSubmit('submitAdd'.$this->table.'AndStay')) { Tools::redirectAdmin(self::$currentIndex.'&update'.$this->table.'&id_'.$this->table.'='.$object->id.'&conf=4'.'&token='.$this->token); } else { @@ -286,12 +901,14 @@ class AdminTaxesControllerCore extends AdminController if (!$object->add()) { $this->errors[] = Tools::displayError('An error occurred while creating an object.').' '.$this->table.''; } elseif ($this->postImage($object->id)) { + if ($isTourismTax) { + self::saveTourismTaxSubtype($object->id); + } if (Tools::isSubmit('submitAdd'.$this->table.'AndStay')) { Tools::redirectAdmin(self::$currentIndex.'&update'.$this->table.'&id_'.$this->table.'='.$object->id.'&conf=3'.'&token='.$this->token); } else { Tools::redirectAdmin(self::$currentIndex.'&conf=3&token='.$this->token); } - Tools::redirectAdmin(self::$currentIndex.'&id_'.$this->table.'='.$object->id.'&conf=3'.'&token='.$this->token); } } } else { @@ -302,6 +919,317 @@ class AdminTaxesControllerCore extends AdminController } } + /** + * Validate tourism-tax-specific fields and append to $this->errors. + */ + protected function validateTourismTaxFields() + { + if (!(int) Tools::getValue('is_tourism_tax')) { + return; + } + + $taxValue = Tools::getValue('tax_value', ''); + if ($taxValue === '') { + $this->errors[] = $this->l('Tax value is required.'); + $this->invalidCoreFields['tax_value'] = true; + } else { + if (!is_numeric($taxValue)) { + $this->errors[] = $this->l('Tax value must be a valid number.'); + $this->invalidCoreFields['tax_value'] = true; + } elseif ((float) $taxValue < 0) { + $this->errors[] = $this->l('Tax value cannot be negative.'); + $this->invalidCoreFields['tax_value'] = true; + } + } + + if ((int) Tools::getValue('has_multiple_valid_ranges')) { + $submittedRangeFroms = Tools::getValue('validity_from', array()); + $submittedRangeTos = Tools::getValue('validity_to', array()); + $filledRanges = array(); + foreach ($submittedRangeFroms as $rowIndex => $fromRaw) { + $toRaw = isset($submittedRangeTos[$rowIndex]) ? $submittedRangeTos[$rowIndex] : ''; + $fromRaw = trim($fromRaw); + $toRaw = trim($toRaw); + if ($fromRaw === '0000-00-00') { $fromRaw = ''; } + if ($toRaw === '0000-00-00') { $toRaw = ''; } + $rowNum = (int) $rowIndex + 1; + if ($fromRaw === '' && $toRaw === '') { + continue; + } + if ($fromRaw !== '' && !Validate::isDate($fromRaw)) { + $this->errors[] = sprintf($this->l('Valid range #%d: "From" is not a valid date.'), $rowNum); + $this->invalidValidityFields[$rowIndex]['from'] = true; + } + if ($toRaw !== '' && !Validate::isDate($toRaw)) { + $this->errors[] = sprintf($this->l('Valid range #%d: "To" is not a valid date.'), $rowNum); + $this->invalidValidityFields[$rowIndex]['to'] = true; + } + if ($fromRaw !== '' && $toRaw !== '' && Validate::isDate($fromRaw) && Validate::isDate($toRaw) + && strtotime($toRaw) < strtotime($fromRaw) + ) { + $this->errors[] = sprintf($this->l('Valid range #%d: "To" must be on or after "From".'), $rowNum); + $this->invalidValidityFields[$rowIndex]['from'] = true; + $this->invalidValidityFields[$rowIndex]['to'] = true; + } + $filledRanges[] = array( + 'from' => ($fromRaw !== '' && Validate::isDate($fromRaw)) ? strtotime($fromRaw) : null, + 'to' => ($toRaw !== '' && Validate::isDate($toRaw)) ? strtotime($toRaw) : null, + 'rowNum' => $rowNum, + 'rowIndex' => $rowIndex, + ); + } + if (empty($filledRanges)) { + $this->errors[] = $this->l('Add at least one range or disable "Set valid date ranges".'); + } + $rangeCount = count($filledRanges); + for ($outerIdx = 0; $outerIdx < $rangeCount; $outerIdx++) { + for ($innerIdx = $outerIdx + 1; $innerIdx < $rangeCount; $innerIdx++) { + $outerRange = $filledRanges[$outerIdx]; + $innerRange = $filledRanges[$innerIdx]; + $outerMinEffective = ($outerRange['from'] === null) ? -PHP_INT_MAX : $outerRange['from']; + $outerMaxEffective = ($outerRange['to'] === null) ? PHP_INT_MAX : $outerRange['to']; + $innerMinEffective = ($innerRange['from'] === null) ? -PHP_INT_MAX : $innerRange['from']; + $innerMaxEffective = ($innerRange['to'] === null) ? PHP_INT_MAX : $innerRange['to']; + if ($outerMinEffective <= $innerMaxEffective && $outerMaxEffective >= $innerMinEffective) { + $this->errors[] = sprintf( + $this->l('Valid ranges #%d and #%d overlap. Each range must cover a distinct period.'), + $outerRange['rowNum'], + $innerRange['rowNum'] + ); + $this->invalidValidityFields[$outerRange['rowIndex']]['from'] = true; + $this->invalidValidityFields[$outerRange['rowIndex']]['to'] = true; + $this->invalidValidityFields[$innerRange['rowIndex']]['from'] = true; + $this->invalidValidityFields[$innerRange['rowIndex']]['to'] = true; + break 2; + } + } + } + } + + if ((int) Tools::getValue('has_child_rate') && (int) Tools::getValue('has_child_age_range')) { + $infantMaxAge = (int) Configuration::get('QLO_GLOBAL_MAX_INFANT_AGE'); + $childMaxAge = (int) Configuration::get('WK_GLOBAL_CHILD_MAX_AGE'); + $submittedBandMins = Tools::getValue('child_min', array()); + $submittedBandMaxs = Tools::getValue('child_max', array()); + $submittedBandValues = Tools::getValue('child_value', array()); + if (empty($submittedBandValues)) { + $this->errors[] = $this->l('Add at least one range or disable "Set child age range".'); + } + $filledBands = array(); + foreach ($submittedBandValues as $rowIndex => $taxValue) { + $bandMinRaw = isset($submittedBandMins[$rowIndex]) ? $submittedBandMins[$rowIndex] : ''; + $bandMaxRaw = isset($submittedBandMaxs[$rowIndex]) ? $submittedBandMaxs[$rowIndex] : ''; + $rowNum = (int) $rowIndex + 1; + if ($taxValue === '' || $taxValue === false) { + $this->errors[] = sprintf($this->l('Child range #%d: tax value is required.'), $rowNum); + $this->invalidChildFields[$rowIndex]['value'] = true; + continue; + } + $bandMin = ($bandMinRaw !== '') ? (int) $bandMinRaw : 0; + $bandMax = ($bandMaxRaw !== '') ? (int) $bandMaxRaw : 0; + if (!is_numeric($taxValue)) { + $this->errors[] = sprintf($this->l('Child range #%d: tax value must be a valid number.'), $rowNum); + $this->invalidChildFields[$rowIndex]['value'] = true; + } elseif ((float) $taxValue < 0) { + $this->errors[] = sprintf($this->l('Child range #%d: tax value cannot be negative.'), $rowNum); + $this->invalidChildFields[$rowIndex]['value'] = true; + } + if ($bandMax > 0 && $bandMin > $bandMax) { + $this->errors[] = sprintf($this->l('Child range #%d: min age cannot be greater than max age.'), $rowNum); + $this->invalidChildFields[$rowIndex]['min'] = true; + $this->invalidChildFields[$rowIndex]['max'] = true; + } + if ($bandMin > 0 && $bandMin < $infantMaxAge) { + $this->errors[] = sprintf($this->l('Child range #%d: min age cannot be below the infant age (%d).'), $rowNum, $infantMaxAge); + $this->invalidChildFields[$rowIndex]['min'] = true; + } + if ($bandMax > 0 && $bandMax >= $childMaxAge) { + $this->errors[] = sprintf($this->l('Child range #%d: max age cannot be %d or above (the general child age setting).'), $rowNum, $childMaxAge); + $this->invalidChildFields[$rowIndex]['max'] = true; + } + $filledBands[] = array('minAge' => $bandMin, 'maxAge' => $bandMax, 'rowNum' => $rowNum, 'rowIndex' => $rowIndex); + } + $bandCount = count($filledBands); + for ($outerIdx = 0; $outerIdx < $bandCount; $outerIdx++) { + for ($innerIdx = $outerIdx + 1; $innerIdx < $bandCount; $innerIdx++) { + $outerBand = $filledBands[$outerIdx]; + $innerBand = $filledBands[$innerIdx]; + $outerMaxEffective = ($outerBand['maxAge'] == 0) ? PHP_INT_MAX : $outerBand['maxAge']; + $innerMaxEffective = ($innerBand['maxAge'] == 0) ? PHP_INT_MAX : $innerBand['maxAge']; + if ($outerBand['minAge'] <= $innerMaxEffective && $outerMaxEffective >= $innerBand['minAge']) { + $this->errors[] = sprintf( + $this->l('Child age ranges #%d and #%d overlap. Each range must cover a distinct age range.'), + $outerBand['rowNum'], + $innerBand['rowNum'] + ); + $this->invalidChildFields[$outerBand['rowIndex']]['min'] = true; + $this->invalidChildFields[$outerBand['rowIndex']]['max'] = true; + $this->invalidChildFields[$innerBand['rowIndex']]['min'] = true; + $this->invalidChildFields[$innerBand['rowIndex']]['max'] = true; + break 2; + } + } + } + } + + if ((int) Tools::getValue('is_tiered')) { + $submittedTierMins = Tools::getValue('tier_min', array()); + $submittedTierMaxs = Tools::getValue('tier_max', array()); + $submittedTierValues = Tools::getValue('tier_value', array()); + if (empty($submittedTierValues)) { + $this->errors[] = $this->l('Add at least one range or disable "Tiered pricing".'); + } + $filledTiers = array(); + foreach ($submittedTierValues as $rowIndex => $taxValue) { + $tierMinRaw = isset($submittedTierMins[$rowIndex]) ? $submittedTierMins[$rowIndex] : ''; + $tierMaxRaw = isset($submittedTierMaxs[$rowIndex]) ? $submittedTierMaxs[$rowIndex] : ''; + $rowNum = (int) $rowIndex + 1; + if ($taxValue === '' || $taxValue === false) { + $this->errors[] = sprintf($this->l('Tier #%d: tax value is required.'), $rowNum); + $this->invalidTierFields[$rowIndex]['value'] = true; + continue; + } + $tierMin = ($tierMinRaw !== '') ? (float) $tierMinRaw : 0.0; + $tierMax = ($tierMaxRaw !== '') ? (float) $tierMaxRaw : 0.0; + if (!is_numeric($taxValue)) { + $this->errors[] = sprintf($this->l('Tier #%d: tax value must be a valid number.'), $rowNum); + $this->invalidTierFields[$rowIndex]['value'] = true; + } elseif ((float) $taxValue < 0) { + $this->errors[] = sprintf($this->l('Tier #%d: tax value cannot be negative.'), $rowNum); + $this->invalidTierFields[$rowIndex]['value'] = true; + } + if ($tierMax > 0 && $tierMin > $tierMax) { + $this->errors[] = sprintf($this->l('Tier #%d: min price cannot be greater than max price.'), $rowNum); + $this->invalidTierFields[$rowIndex]['min'] = true; + $this->invalidTierFields[$rowIndex]['max'] = true; + } + $filledTiers[] = array('minPrice' => $tierMin, 'maxPrice' => $tierMax, 'rowNum' => $rowNum, 'rowIndex' => $rowIndex); + } + $tierCount = count($filledTiers); + for ($outerIdx = 0; $outerIdx < $tierCount; $outerIdx++) { + for ($innerIdx = $outerIdx + 1; $innerIdx < $tierCount; $innerIdx++) { + $outerTier = $filledTiers[$outerIdx]; + $innerTier = $filledTiers[$innerIdx]; + $outerMaxEffective = ($outerTier['maxPrice'] == 0) ? PHP_FLOAT_MAX : $outerTier['maxPrice']; + $innerMaxEffective = ($innerTier['maxPrice'] == 0) ? PHP_FLOAT_MAX : $innerTier['maxPrice']; + if ($outerTier['minPrice'] < $innerMaxEffective && $outerMaxEffective > $innerTier['minPrice']) { + $this->errors[] = sprintf( + $this->l('Price ranges #%d and #%d overlap. Each range must cover a distinct price range.'), + $outerTier['rowNum'], + $innerTier['rowNum'] + ); + $this->invalidTierFields[$outerTier['rowIndex']]['min'] = true; + $this->invalidTierFields[$outerTier['rowIndex']]['max'] = true; + $this->invalidTierFields[$innerTier['rowIndex']]['min'] = true; + $this->invalidTierFields[$innerTier['rowIndex']]['max'] = true; + break 2; + } + } + } + } + } + + public function setMedia() + { + parent::setMedia(); + if ($this->display == 'edit' || $this->display == 'add') { + $this->addCSS(_MODULE_DIR_ . 'hotelreservationsystem/views/css/HotelReservationAdmin.css'); + $this->addJs(_MODULE_DIR_ . 'hotelreservationsystem/views/js/TourismTaxForm.js'); + } + } + + /** + * @param int $idTax + */ + protected static function saveTourismTaxSubtype($idTax) + { + $idTax = (int) $idTax; + $tourismTax = TaxConfiguration::getByTaxId($idTax); + $tourismTaxExists = (bool) $tourismTax; + if (!$tourismTax) { + $tourismTax = new TaxConfiguration(); + $tourismTax->id = $idTax; + } + $tourismTax->calculation_type = (int) Tools::getValue('tax_calc_type', 0); + $tourismTax->per_night = (int) Tools::getValue('is_per_night', 1); + $tourismTax->per_person = (int) Tools::getValue('is_per_person', 0); + $tourismTax->tax_value = (float) Tools::getValue('tax_value', 0); + $tourismTax->has_tiered_pricing = (int) Tools::getValue('is_tiered', 0); + $tourismTax->apply_on_child = (int) Tools::getValue('has_child_rate', 0); + $tourismTax->has_child_age_range = (int) Tools::getValue('has_child_age_range', 0); + $tourismTax->child_calculation_type = (int) Tools::getValue('child_calc_type', 0); + $tourismTax->has_multiple_valid_ranges = (int) Tools::getValue('has_multiple_valid_ranges', 0); + + $submittedDays = Tools::getValue('valid_days', array()); + if (!is_array($submittedDays)) { + $submittedDays = array(); + } + $submittedDays = array_values(array_intersect(TaxConfiguration::DAY_KEYS, $submittedDays)); + if (empty($submittedDays) || count($submittedDays) === 7) { + $tourismTax->special_days = null; + } else { + $tourismTax->special_days = json_encode($submittedDays); + } + + if ($tourismTaxExists) { + $tourismTax->update(); + } else { + $tourismTax->add(); + } + + TaxPriceTier::saveAll( + $idTax, + Tools::getValue('tier_min', array()), + Tools::getValue('tier_max', array()), + Tools::getValue('tier_value', array()) + ); + TaxChildRange::saveAll( + $idTax, + Tools::getValue('child_min', array()), + Tools::getValue('child_max', array()), + Tools::getValue('child_value', array()) + ); + TaxValidityRange::saveAll( + $idTax, + Tools::getValue('validity_from', array()), + Tools::getValue('validity_to', array()) + ); + } + + /** + * Remove this tax from all tourism tax rules groups when it is demoted from tourism to regular. + * Flashes a warning listing how many rule rows were deleted. + * + * @param int $idTax + */ + protected function cleanTaxFromTourismTaxRulesGroups($idTax) + { + $count = TaxConfiguration::cleanFromTourismTaxRulesGroups($idTax); + if ($count) { + $this->warnings[] = sprintf( + $this->l('This tax was removed from %d tourism tax rules group(s) because it is no longer marked as a tourism tax.'), + $count + ); + } + } + + /** + * Remove this tax from all standard (non-tourism) tax rules groups when it is promoted to a + * tourism tax. Flashes a warning listing how many rule rows were deleted. + * + * @param int $idTax + */ + protected function cleanTaxFromVatTaxRulesGroups($idTax) + { + $count = TaxConfiguration::cleanFromVatTaxRulesGroups($idTax); + if ($count) { + $this->warnings[] = sprintf( + $this->l('This tax was removed from %d standard tax rules group(s) because it is now marked as a tourism tax.'), + $count + ); + } + } + public function updateOptionPsUseEcotax($value) { $old_value = (int)Configuration::get('PS_USE_ECOTAX'); diff --git a/controllers/admin/AdminTranslationsController.php b/controllers/admin/AdminTranslationsController.php index e56831c50..b5c79be40 100644 --- a/controllers/admin/AdminTranslationsController.php +++ b/controllers/admin/AdminTranslationsController.php @@ -110,6 +110,23 @@ class AdminTranslationsControllerCore extends AdminController 'page_header_toolbar_title' => $this->page_header_toolbar_title, 'page_header_toolbar_btn' => $this->page_header_toolbar_btn)); } + public function setMedia() + { + parent::setMedia(); + + if (Tools::getValue('type') == 'mails') { + Media::addJsDef(array( + 'mailResetSuccessMsg' => $this->l('The template is reset to its original content.'), + 'mailResetErrorMsg' => $this->l('An error occurred while resetting the template.'), + 'mailResetTooltipCore' => $this->l('On reset, the template will be reset to the default mail template.'), + 'mailResetTooltipModule' => $this->l('On reset, the template will be reset using modules/{module}/mails/{iso}/'), + 'admin_translations_link' => $this->context->link->getAdminLink('AdminTranslations'), + 'EMAIL_TEMPLATE_TYPE_CORE' => Language::EMAIL_TEMPLATE_TYPE_CORE, + 'EMAIL_TEMPLATE_TYPE_MODULE' => Language::EMAIL_TEMPLATE_TYPE_MODULE, + )); + $this->addJS(_PS_JS_DIR_.'admin/translations.js'); + } + } /** * This function create vars by default and call the good method for generate form @@ -1429,6 +1446,9 @@ class AdminTranslationsControllerCore extends AdminController */ public function postProcess() { + if ($this->ajax) { + return parent::postProcess(); + } $this->getInformations(); /* PrestaShop demo mode */ @@ -1663,6 +1683,50 @@ class AdminTranslationsControllerCore extends AdminController } } + public function ajaxProcessResetMailTemplate() + { + if (empty($this->tabAccess['edit'])) { + die(json_encode(array('hasError' => true, 'error' => Tools::displayError('You do not have permission to edit this.')))); + } + + $iso_code = Tools::getValue('iso_code') ? Tools::getValue('iso_code') : null; + $theme = Tools::getValue('theme'); + $mail_template_name = Tools::getValue('mail_name'); + $template_type = (int)Tools::getValue('template_type'); + $module_name = Tools::getValue('module_name') ? Tools::getValue('module_name') : false; + + if (!Validate::isLanguageIsoCode($iso_code)) { + die(json_encode(array('hasError' => true, 'error' => Tools::displayError('Invalid iso code.')))); + } + + if (!Validate::isTplName($mail_template_name)) { + die(json_encode(array('hasError' => true, 'error' => Tools::displayError('Invalid mail template to reset.')))); + } + + if ($template_type === Language::EMAIL_TEMPLATE_TYPE_MODULE) { + if (!$module_name || !Validate::isModuleName($module_name)) { + die(json_encode(array('hasError' => true, 'error' => Tools::displayError('Invalid module name.')))); + } + } elseif ($template_type === Language::EMAIL_TEMPLATE_TYPE_CORE) { + $module_name = false; + } else { + die(json_encode(array('hasError' => true, 'error' => Tools::displayError('Invalid template type.')))); + } + + if ($theme) { + $themes_base_dir = realpath(_PS_ALL_THEMES_DIR_); + $theme_real_path = realpath(_PS_ALL_THEMES_DIR_.$theme); + if ($themes_base_dir === false + || $theme_real_path === false + || strncmp($theme_real_path, $themes_base_dir.DIRECTORY_SEPARATOR, strlen($themes_base_dir) + 1) !== 0 + ) { + die(json_encode(array('hasError' => true, 'error' => Tools::displayError('Invalid theme.')))); + } + } + + die(json_encode(Language::resetEmailTemplate($mail_template_name, $iso_code, $template_type, $module_name, $theme))); + } + /** * Include file $dir/$file and return the var $var declared in it. * This create the file if not exists @@ -2362,9 +2426,12 @@ class AdminTranslationsControllerCore extends AdminController $str_return .= '| {l s='Room Extra Demands Detail'} | -||
|---|---|---|
| {l s='Room Type'} | -{l s='Name'} | -{l s='Total'} {l s='(Tax excl.)'} |
-
|
-
- {$data_v['name']} - {$rm_v['data_form']|date_format:"%d-%m-%Y"} {l s='to'} {$rm_v['data_to']|date_format:"%d-%m-%Y"} - {l s='Room'} - {$roomCount} - - |
- {/if}
- - - {$demand['name']} - - | -- - {convertPrice price=$demand['total_price_tax_excl']} - - | -
| {l s='No room extra demands added.'} | -||
| {l s='Rooms Services Detail'} | -|||
|---|---|---|---|
| {l s='Room Type'} | -{l s='Name'} | -{l s='Qty'} | -{l s='Total'} | -
|
-
- {$data_v['name']} - {$rm_v['data_form']|date_format:"%d-%m-%Y"} {l s='to'} {$rm_v['data_to']|date_format:"%d-%m-%Y"} - {l s='Room'} - {$roomCount} - - |
- {/if}
- - - {$service['name']} - - | -- - {if $service['allow_multiple_quantity']} - {$service['quantity']} - {else} - {l s='--'} - {/if} - - | -- - {convertPrice price=$service['total_price_tax_excl']} - - | -
| {l s='No room services added.'} | -|||
| {l s='Extra Services Details'} | +|||
|---|---|---|---|
| {l s='Room Type'} | +{l s='Name'} | +{l s='Qty'} | +{l s='Total'} | +
|
+
+ {$data_v['name']} + {$rm_v['data_form']|date_format:"%d-%m-%Y"} {l s='to'} {$rm_v['data_to']|date_format:"%d-%m-%Y"} + {l s='Room'} - {$roomCount} + + |
+ {/if}
+ + + {$service['name']} + + | ++ + {if $service['allow_multiple_quantity']} + {$service['quantity']} + {else} + {l s='--'} + {/if} + + | ++ + {convertPrice price=$service['total_price_tax_excl']} + + | +
| {l s='No service requested'} | +|||
{l s='Total Revenue Per Available Room' mod='dashperformance'}
{l s='Gross Operating Profit Per Available Room' mod='dashperformance'}
| {l s='Image Id' mod='hotelreservationsystem'} | {l s='Image' mod='hotelreservationsystem'} | +{l s='Category' mod='hotelreservationsystem'} | {l s='Cover' mod='hotelreservationsystem'} | {l s='Action' mod='hotelreservationsystem'} | |
|---|---|---|---|---|---|
|
-
-
- {l s='No Image Found' mod='hotelreservationsystem'}
-
- |
- |||||
|
+
+
+ {l s='No Image Found' mod='hotelreservationsystem'}
+
+ |
+ |||||
{l s='Allowed image formats: .gif, .jpg, .jpeg and .png' mod='hotelreservationsystem'}
+{l s='If not selected, image will be uncategorized.' mod='hotelreservationsystem'} — {l s='Create image category' mod='hotelreservationsystem'}
+{l s='Are you sure you want to delete the selected image(s)? This cannot be undone.' mod='hotelreservationsystem'}
+{l s='If not selected, selected images will be uncategorized.' mod='hotelreservationsystem'}
+{l s='Switching to Video will delete all images except the one in the first position. This cannot be undone. Continue?' mod='hotelreservationsystem'}
+{l s='Delete selected images? This cannot be undone.' mod='hotelreservationsystem'}
+{l s='Leave \'Select status\' to keep the current status.' mod='hotelreservationsystem'}
+{l s='Leave empty to clear the title for all selected images.' mod='hotelreservationsystem'}
+{l s='Leave empty to clear the description for all selected images.' mod='hotelreservationsystem'}
+{l s='Leave empty to keep each image\'s current color unchanged.' mod='hotelreservationsystem'}
+{l s='Leave as 0 to keep the current size.' mod='hotelreservationsystem'}
+{l s='Leave \'Select font weight\' to keep the current weight.' mod='hotelreservationsystem'}
++ {l s='Formats: .jpg, .jpeg, .png, .webp, .gif' mod='hotelreservationsystem'} + — {l s='Recommended: 1920×600 px' mod='hotelreservationsystem'} + — {l s='Max:' mod='hotelreservationsystem'} {$maxImageUpload|escape:'html':'UTF-8'} +
+{l s='Short title shown as an input field on this image. Leave empty for no title.' mod='hotelreservationsystem'}
+{l s='Short text overlay shown on this image. Leave empty for no overlay.' mod='hotelreservationsystem'}
+{l s='Text color for the description overlay.' mod='hotelreservationsystem'}
+{l s='Default: 16px. Recommended: 12px–48px.' mod='hotelreservationsystem'}
+{l s='Welcome To' mod='hotelreservationsystem'}
-{$WK_HTL_TAG_LINE|escape:'htmlall':'UTF-8'}
+{if isset($wkHeaderMediaDescription) && $wkHeaderMediaDescription}{$wkHeaderMediaDescription|escape:'html':'UTF-8'}{/if}
{/block}| {l s='Room Additional Facilities Detail' pdf='true'} | -|||
|---|---|---|---|
| {l s='Room Type' pdf='true'} | -{l s='Name' pdf='true'} | -{l s='Tax rate(s)' pdf='true'} | -{l s='Total' pdf='true'} {l s='(Tax excl.)' pdf='true'} |
-
|
- {$roomDemand['room_type_name']} - {dateFormat date=$roomDemand['date_from']} {l s='to' pdf='true'} {dateFormat date=$roomDemand['date_to']} - {l s='Room' pdf='true'} - {$roomCount} - |
- {/if}
- - {$demand['name']} - | -- {$demand['extra_demands_tax_label']} - | -- {displayPrice currency=$order->id_currency price=$demand['total_price_tax_excl']} - | -
| {l s='Room Extra Services Detail' pdf='true'} | @@ -113,8 +68,8 @@
|---|
- {if isset($demands_price)}{convertPrice price=$demands_price}{else}{convertPrice price=0}{/if} - {if (isset($selected_demands) && $selected_demands) || (isset($selected_service_product) && $selected_service_product)} +
+ {if isset($service_product_price)}{convertPrice price=$service_product_price}{else}{convertPrice price=0}{/if}
+ {if isset($selected_service_product) && $selected_service_product}
{/if}
{l s='Selected facilities'} {l s='(Per room)'}
- -{displayPrice price=$demands_price_per_room}
{displayPrice price=$service_product_price_per_room}
{displayPrice price=$demands_price}
{displayPrice price=$service_product_price}