* @copyright 2007-2017 PrestaShop SA * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) * International Registered Trademark & Property of PrestaShop SA */ /** * @property Tax $object */ class AdminTaxesControllerCore extends AdminController { protected $invalidCoreFields = array(); protected $invalidTierFields = array(); protected $invalidChildFields = array(); protected $invalidValidityFields = array(); public function __construct() { $this->bootstrap = true; $this->table = 'tax'; $this->className = 'Tax'; $this->lang = true; $this->addRowAction('edit'); $this->addRowAction('delete'); $this->bulk_actions = array( 'delete' => array( 'text' => $this->l('Delete selected'), 'confirm' => $this->l('Delete selected items?'), 'icon' => 'icon-trash' ) ); $this->fields_list = array( 'id_tax' => array('title' => $this->l('ID'), 'align' => 'center', 'class' => 'fixed-width-xs'), 'name' => array('title' => $this->l('Name'), 'width' => 'auto'), 'is_tourism_tax' => array( 'title' => $this->l('Tourism Tax'), 'align' => 'center', 'class' => 'fixed-width-sm', 'callback' => 'displayTourismTaxBadge', 'orderby' => false, 'type' => 'bool', ), 'rate' => array( 'title' => $this->l('Rate'), 'align' => 'center', 'class' => 'fixed-width-md', 'callback' => 'displayRate', 'orderby' => false, ), 'active' => array('title' => $this->l('Enabled'), 'width' => 25, 'align' => 'center', 'active' => 'status', 'type' => 'bool', 'orderby' => false, 'class' => 'fixed-width-sm', 'remove_onclick' => true) ); // Code For eco-tax working // $ecotax_desc = ''; // if (Configuration::get('PS_USE_ECOTAX')) { // $ecotax_desc = $this->l('If you disable the ecotax, the ecotax for all your products will be set to 0.'); // } $this->fields_options = array( 'general' => array( 'title' => $this->l('Tax options'), 'fields' => array( 'PS_TAX' => array( 'title' => $this->l('Enable tax'), 'desc' => $this->l('Select whether or not to include tax on purchases.'), 'cast' => 'intval', 'type' => 'bool'), 'PS_TAX_DISPLAY' => array( 'title' => $this->l('Display tax in the booking cart'), 'desc' => $this->l('Select whether or not to display tax on a distinct line in the cart.'), 'cast' => 'intval', 'type' => 'bool'), // 'PS_TAX_ADDRESS_TYPE' => array( // 'title' => $this->l('Based on'), // 'cast' => 'pSQL', // 'type' => 'select', // 'list' => array( // array( // 'name' => $this->l('Invoice address'), // 'id' => 'id_address_invoice' // ), // array( // 'name' => $this->l('Delivery address'), // 'id' => 'id_address_delivery') // ), // ), // 'identifier' => 'id' // ), // Code For eco-tax working // 'PS_USE_ECOTAX' => array( // 'title' => $this->l('Use ecotax'), // 'desc' => $ecotax_desc, // 'validation' => 'isBool', // 'cast' => 'intval', // 'type' => 'bool' // ), ), 'submit' => array('title' => $this->l('Save')) ), ); // Code For eco-tax working // if (Configuration::get('PS_USE_ECOTAX') || Tools::getValue('PS_USE_ECOTAX')) { // $this->fields_options['general']['fields']['PS_ECOTAX_TAX_RULES_GROUP_ID'] = array( // 'title' => $this->l('Ecotax'), // 'hint' => $this->l('Define the ecotax (e.g. French ecotax: 19.6%).'), // 'cast' => 'intval', // 'type' => 'select', // 'identifier' => 'id_tax_rules_group', // 'list' => TaxRulesGroup::getTaxRulesGroupsForOptions() // ); // } $this->fields_options['general']['fields']['QLO_USE_TOURISM_TAX'] = array( 'title' => $this->l('Use tourism tax'), 'hint' => $this->l('Enable tourism tax calculation for hotel room bookings.'), 'validation' => 'isBool', 'cast' => 'intval', 'type' => 'bool', ); if (Configuration::get('QLO_USE_TOURISM_TAX') || Tools::getValue('QLO_USE_TOURISM_TAX')) { $this->fields_options['general']['fields']['QLO_TOURISM_TAX_GROSSED_UP'] = array( 'title' => $this->l('Include tourism tax in displayed prices'), 'desc' => $this->l('When enabled, tourism tax is included in displayed prices. The applicable tourism tax is always shown as a separate line if applicable.'), 'validation' => 'isBool', 'cast' => 'intval', 'type' => 'bool', ); } parent::__construct(); $this->_where .= ' AND a.deleted = 0'; $this->_join .= ' LEFT JOIN `'._DB_PREFIX_.'tax_configuration` tourism_tax ON tourism_tax.`id_tax` = a.`id_tax`'; $extraSelect = 'IFNULL(tourism_tax.`calculation_type`, 0) AS `tourism_tax_calc_type`, IFNULL(tourism_tax.`tax_value`, 0) AS `tourism_tax_value`'; $this->_select = ($this->_select ? $this->_select . ', ' : '') . $extraSelect; } public function initPageHeaderToolbar() { if (empty($this->display) || $this->display == 'list') { $this->page_header_toolbar_btn['new_tax'] = array( 'href' => self::$currentIndex.'&addtax&token='.$this->token, 'desc' => $this->l('Add new tax', null, null, false), 'icon' => 'process-icon-new' ); } parent::initPageHeaderToolbar(); } /** * Display delete action link * * @param string|null $token * @param int $id * * @return string * @throws Exception * @throws SmartyException */ public function displayDeleteLink($token, $id) { if (!array_key_exists('Delete', self::$cache_lang)) { self::$cache_lang['Delete'] = $this->l('Delete'); } if (!array_key_exists('DeleteItem', self::$cache_lang)) { self::$cache_lang['DeleteItem'] = $this->l('Delete item #', __CLASS__, true, false); } if (TaxRule::isTaxInUse($id)) { $confirm = $this->l('This tax is currently in use as a tax rule. Are you sure you\'d like to continue?', null, true, false); } $this->context->smarty->assign(array( 'href' => self::$currentIndex.'&'.$this->identifier.'='.$id.'&delete'.$this->table.'&token='.($token != null ? $token : $this->token), 'confirm' => (isset($confirm) ? '\r'.$confirm : self::$cache_lang['DeleteItem'].$id.' ? '), 'action' => self::$cache_lang['Delete'], )); return $this->context->smarty->fetch('helpers/list/list_action_delete.tpl'); } /** * Fetch the template for action enable * * @param string $token * @param int $id * @param int $value state enabled or not * @param string $active status * @param int $id_category * @param int $id_product */ public function displayEnableLink($token, $id, $value, $active, $id_category = null, $id_product = null) { if ($value && TaxRule::isTaxInUse($id)) { $confirm = $this->l('This tax is currently in use as a tax rule. If you continue, this tax will be removed from the tax rule. Are you sure you\'d like to continue?', null, true, false); } $tpl_enable = $this->context->smarty->createTemplate('helpers/list/list_action_enable.tpl'); $tpl_enable->assign(array( 'enabled' => (bool)$value, 'url_enable' => self::$currentIndex.'&'.$this->identifier.'='.(int)$id.'&'.$active.$this->table. ((int)$id_category && (int)$id_product ? '&id_category='.(int)$id_category : '').'&token='.($token != null ? $token : $this->token), 'confirm' => isset($confirm) ? $confirm : null, )); return $tpl_enable->fetch(); } public function renderList() { $this->_new_list_header_design = true; return parent::renderList(); } public function renderForm() { $idTax = (int) Tools::getValue('id_' . $this->table); $subtype = null; $tiers = array(); $childRanges = array(); $validityRanges = array(); $contextCurrency = $this->context->currency; $currencySign = Tools::safeOutput(trim($contextCurrency->prefix . $contextCurrency->suffix)); $isAnySubmit = Tools::isSubmit('submitAdd' . $this->table) || Tools::isSubmit('submitAdd' . $this->table . 'AndStay'); if ($idTax && !$isAnySubmit) { $subtype = TaxConfiguration::getByTaxId($idTax); if ($subtype) { $_POST['tax_calc_type'] = $subtype->calculation_type; $_POST['is_per_night'] = $subtype->per_night; $_POST['is_per_person'] = $subtype->per_person; $_POST['tax_value'] = $subtype->tax_value; $_POST['is_tiered'] = $subtype->has_tiered_pricing; $_POST['has_child_rate'] = $subtype->apply_on_child; $_POST['has_child_age_range'] = $subtype->has_child_age_range; $_POST['child_calc_type'] = $subtype->child_calculation_type; $_POST['has_multiple_valid_ranges'] = $subtype->has_multiple_valid_ranges; $tiers = TaxPriceTier::getByTaxId($idTax); $childRanges = TaxChildRange::getByTaxId($idTax); $validityRanges = TaxValidityRange::getByTaxId($idTax); } } elseif ($isAnySubmit) { $postTierIds = (array) Tools::getValue('tier_id', array()); $postTierMins = (array) Tools::getValue('tier_min', array()); $postTierMaxs = (array) Tools::getValue('tier_max', array()); $postTierValues = (array) Tools::getValue('tier_value', array()); foreach ($postTierIds as $tierRowIndex => $tierId) { $tiers[] = array( 'id_tier' => (int) $tierId, 'min_amount' => isset($postTierMins[$tierRowIndex]) ? $postTierMins[$tierRowIndex] : '', 'max_amount' => isset($postTierMaxs[$tierRowIndex]) ? $postTierMaxs[$tierRowIndex] : '', 'tax_value' => isset($postTierValues[$tierRowIndex]) ? $postTierValues[$tierRowIndex] : '', ); } $postChildIds = (array) Tools::getValue('child_id', array()); $postChildMins = (array) Tools::getValue('child_min', array()); $postChildMaxs = (array) Tools::getValue('child_max', array()); $postChildValues = (array) Tools::getValue('child_value', array()); foreach ($postChildIds as $childRangeRowIndex => $childId) { $childRanges[] = array( 'id_child_range' => (int) $childId, 'min_age' => isset($postChildMins[$childRangeRowIndex]) ? $postChildMins[$childRangeRowIndex] : '', 'max_age' => isset($postChildMaxs[$childRangeRowIndex]) ? $postChildMaxs[$childRangeRowIndex] : '', 'tax_value' => isset($postChildValues[$childRangeRowIndex]) ? $postChildValues[$childRangeRowIndex] : '', ); } $postValidityIds = (array) Tools::getValue('validity_id', array()); $postValidityFroms = (array) Tools::getValue('validity_from', array()); $postValidityTos = (array) Tools::getValue('validity_to', array()); foreach ($postValidityIds as $validityRangeRowIndex => $rangeId) { $validityRanges[] = array( 'id_validity_range' => (int) $rangeId, 'valid_from' => isset($postValidityFroms[$validityRangeRowIndex]) ? $postValidityFroms[$validityRangeRowIndex] : '', 'valid_to' => isset($postValidityTos[$validityRangeRowIndex]) ? $postValidityTos[$validityRangeRowIndex] : '', ); } } $taxType = (int) Tools::getValue('tax_calc_type', 0); $baseTaxValue = Tools::getValue('tax_value', $subtype ? $subtype->tax_value : 0); $allDayKeys = TaxConfiguration::DAY_KEYS; if ($subtype && $subtype->special_days) { $defaultSpecialDays = json_decode($subtype->special_days, true) ?: $allDayKeys; } else { $defaultSpecialDays = $allDayKeys; } $specialDaysChecked = Tools::getValue('valid_days', $defaultSpecialDays); if (!is_array($specialDaysChecked)) { $specialDaysChecked = $allDayKeys; } $initialTypeSign = ($taxType == TaxConfiguration::CALCULATION_TYPE_PERCENTAGE) ? '%' : $currencySign; $taxValueInputHtml = '
' . $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', 'type' => 'submit', 'class' => 'btn btn-default pull-right', 'icon' => 'process-icon-save', ), ), ); 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)) { $existingTaxId = (int)(Tools::getValue('id_'.$this->table)); $isTourismTax = (int) Tools::getValue('is_tourism_tax'); /* Object update */ if (isset($existingTaxId) && !empty($existingTaxId)) { /** @var Tax $object */ $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 { Tools::redirectAdmin(self::$currentIndex.'&conf=4&token='.$this->token); } } } else { $this->errors[] = Tools::displayError('An error occurred while updating an object.').' '.$this->table.' '.Tools::displayError('(cannot load object)'); } } /* Object creation */ else { /** @var Tax $object */ $object = new $this->className(); $this->copyFromPost($object, $this->table); 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); } } } } else { $this->display = 'add'; } } else { parent::postProcess(); } } /** * 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'); if ($old_value != $value) { // Reset ecotax if ($value == 0) { Product::resetEcoTax(); } Configuration::updateValue('PS_USE_ECOTAX', (int)$value); } } }