<?xml version="1.0" encoding="utf-8"?>
<modification>
    <name>Options Combinations</name>
    <code>option_to_product_ocmod</code>
    <version>1.5.9</version>
    <author>DevmanExtensions</author>
	<link>https://www.devmanextensions.com</link>

		<file error="skip" path="admin/model/catalog/product.php">
			<operation error="skip" info="Add _constructor method to load OptionToProduct model and more">
				<search trim="true"><![CDATA[class ModelCatalogProduct extends Model {]]></search>
				<add position="after"><![CDATA[
					public function __construct($registry) {
						parent::__construct($registry);
						$loader = new Loader($registry);
						$loader->model('extension/module/option_to_product');
					}
				]]></add>
			</operation>

			<operation error="skip" info="">
				<search trim="true"><![CDATA[od.language_id = '" . (int)$this->config->get('config_language_id') . "'");]]></search>
				<add position="replace"><![CDATA[od.language_id = '" . (int)$this->config->get('config_language_id') . "' ORDER BY o.sort_order");]]></add>
			</operation>

			<operation error="skip" info="Check in function add/edit product options combinations">
				<search trim="true"><![CDATA[if (isset($data['product_option'])) {]]></search>
				<add position="before"><![CDATA[$this->model_extension_module_option_to_product->checkOptionsCombinationsEditAddProduct($product_id, $data);]]></add>
			</operation>

			<operation error="skip" info="Add option to product in copy function">
				<search trim="true"><![CDATA[$this->addProduct($data);]]></search>
				<add position="before"><![CDATA[
					$data = $this->model_extension_module_option_to_product->extend_model_catalog_product_copyProduct($product_id, $data);
				]]></add>
			</operation>

			<operation error="skip" info="Remove data from option to product in deleteproduct function">
				<search trim="true"><![CDATA[public function deleteProduct($product_id) {]]></search>
				<add position="after"><![CDATA[
					$this->model_extension_module_option_to_product->extend_model_catalog_product_deleteProduct($product_id);
				]]></add>
			</operation>
		</file>

		<file error="skip" path="admin/controller/catalog/product.php">
			<operation error="skip" info="Add _constructor method to load OptionToProduct model and more">
				<search trim="true"><![CDATA[class ControllerCatalogProduct extends Controller {]]></search>
				<add position="after"><![CDATA[
					public function __construct($registry) {
						parent::__construct($registry);
						$loader = new Loader($registry);
						$loader->model('extension/module/option_to_product');

						if(array_key_exists('action', $this->request->get)) {
							if($this->request->get['action'] == 'getSwapOptionValues') {
								$product_id = $this->request->get['product_id'];
								$option_id = $this->request->get['option_id'];
								$html = $this->model_extension_module_option_to_product->getSwapOptionValuesHtml($product_id, $option_id);
								echo $html; die;
							} else if($this->request->get['action'] == 'getOtpChildValues') {
								$product_id = $this->request->get['product_id'];
								$child_option_id = $this->request->get['child_option_id'];
								$parent_option_value_id = $this->request->get['parent_option_value_id'];
								$html = $this->model_extension_module_option_to_product->getOtpChildValues($product_id, $child_option_id, $parent_option_value_id);
								echo $html; die;
							} else if($this->request->get['action'] == 'getOtpGrandchildValues') {
								$product_id = $this->request->get['product_id'];
								$grandchild_option_id = $this->request->get['grandchild_option_id'];
								$parent_option_value_id = $this->request->get['parent_option_value_id'];
								$child_option_value_id = $this->request->get['child_option_value_id'];
								$html = $this->model_extension_module_option_to_product->getOtpChildValues($product_id, $child_option_value_id, $parent_option_value_id);
								echo $html; die;
							} else if($this->request->get['action'] == 'getOtp') {
								$product_id = $this->request->get['product_id'];
								$grandchild_option_value_id = $this->request->get['grandchild_option_value_id'];
								$parent_option_value_id = $this->request->get['parent_option_value_id'];
								$child_option_value_id = $this->request->get['child_option_value_id'];
								$html = $this->model_extension_module_option_to_product->getOtp($product_id, $parent_option_value_id, $child_option_value_id, $grandchild_option_value_id);
								echo $html; die;
							}
						}
					}
				]]></add>
			</operation>

			<operation error="skip" info="">
				<search trim="true"><![CDATA[protected function getList() {]]></search>
				<add position="after"><![CDATA[
					if ($this->config->get('config_otp_status'))
						$data['otp_categories'] = $this->model_extension_module_option_to_product->getOtpCategories();
				]]></add>
			</operation>

			<operation error="skip" info="">
				<search trim="true"><![CDATA[protected function getForm() {]]></search>
				<add position="after"><![CDATA[
					$data = $this->model_extension_module_option_to_product->extend_controller_catalog_product_getForm();
				]]></add>
			</operation>

			<operation error="skip" info="">
				<search trim="true"><![CDATA[protected function validateForm() {]]></search>
				<add position="after"><![CDATA[
					$otp_error = $this->model_extension_module_option_to_product->extend_controller_catalog_product_validateForm();
					if(!empty($otp_error))
					    $this->error['warning'] = $otp_error;
				]]></add>
			</operation>

			<operation error="skip" info="">
				<search trim="true"><![CDATA[$json[] = array(]]></search>
				<add position="replace"><![CDATA[
					$otpcheck = $this->model_extension_module_option_to_product->checkOtp($result['product_id']);
					$otp_option_data = $otpcheck ? $this->model_extension_module_option_to_product->getOtpOrderOptions($result['product_id']) : false;
					$json[] = array(
						'otpcheck' => $otpcheck,
						'otpoption' => $otp_option_data,
				]]></add>
			</operation>

			<operation error="skip" info="">
				<search trim="true"><![CDATA[$data['products'][] = array(]]></search>
				<add position="before"><![CDATA[
					$starting_from = $this->model_extension_module_option_to_product->getStartingFrom($result['product_id']);

					$normal_price = version_compare(VERSION, '3', '>=') ? $this->currency->format($result['price'], $this->config->get('config_currency')) : $result['price'];

					if($starting_from)
						$starting_from_formatted = 'From '.version_compare(VERSION, '3', '>=') ? $this->currency->format($starting_from, $this->config->get('config_currency')) : $starting_from;
					else
						$starting_from_formatted = $normal_price;
				]]></add>
			</operation>
			<operation error="skip" info="">
				<search trim="true"><![CDATA['quantity'   => $result['quantity'],]]></search>
				<add position="after"><![CDATA['price' => $starting_from_formatted,]]></add>
			</operation>

			<operation error="skip" info="">
				<search trim="true"><![CDATA[$this->load->model('design/layout');]]></search>
				<add position="after"><![CDATA[$data = $this->model_extension_module_option_to_product->extend_controller_catalog_product_getForm_end($data);]]></add>
			</operation>
		</file>

		<file error="skip" path="admin/view/template/catalog/product_form.twig">
			<operation error="skip">
				<search trim="true"><![CDATA[<div class="tab-pane" id="tab-option">]]></search>
				<add position="after"><![CDATA[{{ extend_tab_option_html }}]]></add>
			</operation>
		</file>
		<file error="skip" path="admin/view/template/catalog/product_form.tpl">
			<operation error="skip">
				<search trim="true"><![CDATA[<div class="tab-pane" id="tab-option">]]></search>
				<add position="after"><![CDATA[<?= $extend_tab_option_html ?>]]></add>
			</operation>
		</file>

		<file error="skip" path="admin/view/template/catalog/product_form.twig">
			<operation error="skip">
				<search trim="true"><![CDATA[<div class="tab-pane" id="tab-image">]]></search>
				<add position="after"><![CDATA[{{ extend_tab_image_html }}]]></add>
			</operation>
		</file>
		<file error="skip" path="admin/view/template/catalog/product_form.tpl">
			<operation error="skip">
				<search trim="true"><![CDATA[<div class="tab-pane" id="tab-image">]]></search>
				<add position="after"><![CDATA[<?= $extend_tab_image_html ?>]]></add>
			</operation>
		</file>

		<file error="skip" path="admin/view/template/catalog/product_form.twig">
			<operation error="skip">
				<search trim="true"><![CDATA[{{ footer }}]]></search>
				<add position="before"><![CDATA[{{ script_footer }}]]></add>
			</operation>
		</file>
		<file error="skip" path="admin/view/template/catalog/product_form.tpl">
			<operation error="skip">
				<search trim="true"><![CDATA[<?php echo $footer; ?>]]></search>
				<add position="before"><![CDATA[<?= $script_footer; ?>]]></add>
			</operation>
		</file>

		<file error="skip" path="admin/model/sale/order.php">
			<operation error="skip">
				<search trim="true"><![CDATA[$query = $this->db->query("SELECT * FROM " . DB_PREFIX . "order_option WHERE order_id = '" . (int)$order_id . "' AND order_product_id = '" . (int)$order_product_id . "'");]]></search>
				<add position="replace"><![CDATA[$query = $this->db->query("SELECT * FROM " . DB_PREFIX . "order_option WHERE order_id = '" . (int)$order_id . "' AND order_product_id = '" . (int)$order_product_id . "' ORDER BY order_option_id");]]></add>
			</operation>
		</file>

		<file error="skip" path="admin/controller/sale/order.php">
			<operation error="skip">
				<search trim="true"><![CDATA[public function getForm() {]]></search>
				<add position="after"><![CDATA[
						$this->load->model('extension/module/option_to_product');
						$data['script_footer'] = $this->model_extension_module_option_to_product->getScriptCodeOrderFormFooter();
				]]></add>
			</operation>
			<operation error="skip">
				<search trim="true"><![CDATA['product_id' => $product['product_id'],]]></search>
				<add position="replace"><![CDATA[
						'product_id' => $product['product_id'],
						'otp_id'     => $product['otp_id'],
				]]></add>
			</operation>
		</file>

		<file error="skip" path="admin/view/template/sale/order_form.twig">
			<operation error="skip">
				<search trim="true"><![CDATA[<div id="content">]]></search>
				<add position="after"><![CDATA[
					<script type="text/javascript">
						$(document).ready(function() {
						  $.ajaxSetup({ cache: false });
						});
					</script>
				]]></add>
			</operation>
			<operation error="skip">
				<search trim="true"><![CDATA[<input type="hidden" name="product[{{ product_row }}][product_id]" value="{{ order_product.product_id }}" />]]></search>
				<add position="after"><![CDATA[<input type="hidden" name="product[{{ product_row }}][otp_id]" value="{{ order_product.otp_id }}" />]]></add>
			</operation>
			<operation error="skip">
				<search trim="true"><![CDATA[html += '  <input type="hidden" name="product[' + i + '][product_id]" value="' + product['product_id'] + '" />';]]></search>
				<add position="after"><![CDATA[html += '  <input type="hidden" name="product[' + i + '][otp_id]" value="' + product['otp_id'] + '" />';]]></add>
			</operation>
			<operation error="skip">
				<search trim="true"><![CDATA[#tab-product input[name^=\'option\'][type=\'hidden\'],]]></search>
				<add position="replace"><![CDATA[#tab-product input[name^=\'otp_id\'][type=\'hidden\'], #tab-product input[name^=\'option\'][type=\'hidden\'],]]></add>
			</operation>
			<operation error="skip">
				<search trim="true"><![CDATA[option.type == 'image']]></search>
				<add position="replace"><![CDATA[option.type == 'image' or option.type == 'list']]></add>
			</operation>
			<operation error="skip">
				<search trim="true"><![CDATA[price: item['price']]]></search>
				<add position="replace"><![CDATA[
					price: item['price'],
					otpcheck: item['otpcheck'],
					otpoption: item['otpoption']
				]]></add>
			</operation>
			<operation error="skip">
				<search trim="true"><![CDATA[if (item['option'] != '') {]]></search>
				<add position="replace"><![CDATA[
					otphtml = '';
					if (item['otpcheck'] == true) {
						otphtml += '<input type="hidden" product="' + item['value'] + '" id="otp" name="otp_id" value="">';
						for (otpcount = 0; otpcount < item['otpoption'].length; otpcount++) {
							option = item['otpoption'][otpcount];
							otphtml += '<div class="form-group' + (option['required'] ? ' required' : '') + '">';
							otphtml += '  <label class="col-sm-2 control-label" for="input-option' + option['option_id'] + '">' + option['name'] + '</label>';
							otphtml += '<div class="col-sm-10">';
							otphtml += '<select name="option[' + option['option_id'] + ']" id="input-option' + option['option_id'] + '" class="otp_select_' + otpcount + ' otp-option form-control" option="' + option['option_id'] + '">';
							otphtml += '<option value="">{{ text_select }}</option>';
							for (j = 0; j < option['option_value'].length; j++) {
								option_value = option['option_value'][j];
								otphtml += '<option value="' + option_value['option_value_id'] + '">' + option_value['name'];
								otphtml += '</option>';
							}
							otphtml += '</select>';
							otphtml += '</div>';
							otphtml += '</div>';
						}
					}
					if (item['option'] != '' || item['otpcheck'] == true) {
				]]></add>
			</operation>
			<operation error="skip">
				<search trim="true"><![CDATA[html += '  <legend>{{ entry_option }}</legend>';]]></search>
				<add position="after"><![CDATA[html += otphtml;]]></add>
			</operation>
			<operation error="skip">
				<search trim="true"><![CDATA[if (option['type'] == 'select' || option['type'] == 'radio']]></search>
				<add position="replace"><![CDATA[if (option['type'] == 'select' || option['type'] == 'list' || option['type'] == 'radio']]></add>
			</operation>
			<operation error="skip">
				<search trim="true"><![CDATA[{{ footer }}]]></search>
				<add position="before"><![CDATA[{{ script_footer }}]]></add>
			</operation>
		</file>
		<file error="skip" path="admin/view/template/sale/order_form.tpl">
			<operation error="skip">
				<search trim="true"><![CDATA[<input type="hidden" name="product[<?php echo $product_row; ?>][product_id]" value="<?php echo $order_product['product_id']; ?>" />]]></search>
				<add position="after"><![CDATA[
					<input type="hidden" name="product[<?php echo $product_row; ?>][otp_id]" value="<?php echo $order_product['otp_id']; ?>" />
				]]></add>
			</operation>
			<operation error="skip">
				<search trim="true"><![CDATA[html += '  <input type="hidden" name="product[' + i + '][product_id]" value="' + product['product_id'] + '" />';]]></search>
				<add position="after"><![CDATA[html += '  <input type="hidden" name="product[' + i + '][otp_id]" value="' + product['otp_id'] + '" />';]]></add>
			</operation>
			<operation error="skip">
				<search trim="true"><![CDATA[#tab-product input[name^=\'option\'][type=\'hidden\'],]]></search>
				<add position="replace"><![CDATA[#tab-product input[name^=\'otp_id\'][type=\'hidden\'], #tab-product input[name^=\'option\'][type=\'hidden\'],]]></add>
			</operation>
			<operation error="skip">
				<search trim="true"><![CDATA[$option['type'] == 'image')]]></search>
				<add position="replace"><![CDATA[$option['type'] == 'image' || $option['type'] == 'list')]]></add>
			</operation>
			<operation error="skip">
				<search trim="true"><![CDATA[price: item['price']]]></search>
				<add position="replace"><![CDATA[
					price: item['price'],
					otpcheck: item['otpcheck'],
					otpoption: item['otpoption']
				]]></add>
			</operation>
			<operation error="skip">
				<search trim="true"><![CDATA[if (item['option'] != '') {]]></search>
				<add position="replace"><![CDATA[
					otphtml = '';
					if (item['otpcheck'] == true) {
						otphtml += '<input type="hidden" product="' + item['value'] + '" id="otp" name="otp_id" value="">';
						for (otpcount = 0; otpcount < item['otpoption'].length; otpcount++) {
							option = item['otpoption'][otpcount];
							otphtml += '<div class="form-group' + (option['required'] ? ' required' : '') + '">';
							otphtml += '  <label class="col-sm-2 control-label" for="input-option' + option['option_id'] + '">' + option['name'] + '</label>';
							otphtml += '<div class="col-sm-10">';
							otphtml += '<select name="option[' + option['option_id'] + ']" id="input-option' + option['option_id'] + '" class="otp_select_' + otpcount + ' otp-option form-control" option="' + option['option_id'] + '">';
							otphtml += '<option value=""><?php echo $text_select; ?></option>';
							for (j = 0; j < option['option_value'].length; j++) {
								option_value = option['option_value'][j];
								otphtml += '<option value="' + option_value['option_value_id'] + '">' + option_value['name'];
								otphtml += '</option>';
							}
							otphtml += '</select>';
							otphtml += '</div>';
							otphtml += '</div>';
						}
					}
					if (item['option'] != '' || item['otpcheck'] == true) {
				]]></add>
			</operation>
			<operation error="skip">
				<search trim="true"><![CDATA[html += '  <legend><?php echo $entry_option; ?></legend>';]]></search>
				<add position="after"><![CDATA[html += otphtml;]]></add>
			</operation>
			<operation error="skip">
				<search trim="true"><![CDATA[<?php echo $footer; ?>]]></search>
				<add position="before"><![CDATA[<?= $script_footer ?>]]></add>
			</operation>
			<operation error="skip">
				<search trim="true"><![CDATA[if (option['type'] == 'select' || option['type'] == 'radio']]></search>
				<add position="replace"><![CDATA[if (option['type'] == 'select' || option['type'] == 'list' || option['type'] == 'radio']]></add>
			</operation>
		</file>

		<file error="skip" path="admin/controller/catalog/option.php">
			<operation error="skip">
				<search trim="true"><![CDATA[$option['type'] == 'select']]></search>
				<add position="replace"><![CDATA[$option['type'] == 'select' || $option['type'] == 'list']]></add>
			</operation>
			<operation error="skip">
				<search trim="true"><![CDATA[$type = $this->language->get('text_choose');]]></search>
				<add position="replace"><![CDATA[$type = $option['type'] == 'list' ? 'List' : $type;]]></add>
			</operation>
		</file>

		<file error="skip" path="admin/view/template/catalog/option_list.twig">
			<operation error="skip">
				<search trim="true"><![CDATA[<td class="text-left">{% if sort == 'od.name' %}]]></search>
				<add position="before"><![CDATA[<td class="text-right">ID</td>]]></add>
			</operation>
			<operation error="skip">
				<search trim="true"><![CDATA[<td class="text-left">{{ option.name }}</td>]]></search>
				<add position="before"><![CDATA[<td class="text-left">{{ option.option_id }}</td>]]></add>
			</operation>
		</file>
		<file error="skip" path="admin/view/template/catalog/option_list.tpl">
			<operation error="skip">
				<search trim="true"><![CDATA[<td class="text-left"><?php if ($sort == 'od.name') { ?>]]></search>
				<add position="before"><![CDATA[<td class="text-right">ID</td>]]></add>
			</operation>
			<operation error="skip">
				<search trim="true"><![CDATA[<td class="text-left"><?php echo $option['name']; ?></td>]]></search>
				<add position="before"><![CDATA[<td class="text-right"><?php echo $option['option_id']; ?></td>]]></add>
			</operation>
		</file>

		<file error="skip" path="admin/view/template/catalog/option_form.twig">
			<operation error="skip">
				<search trim="true"><![CDATA[{% if type == 'radio' %}]]></search>
				<add position="before"><![CDATA[<option value="list" {% if type == 'list' %}selected="selected"{% endif %}>List</option>]]></add>
			</operation>
			<operation error="skip">
				<search trim="true"><![CDATA[this.value == 'select']]></search>
				<add position="replace"><![CDATA[this.value == 'select' || this.value == 'list']]></add>
			</operation>
			<operation error="skip">
				<search trim="true"><![CDATA[<td class="text-left required">{{ entry_option_value }}</td>]]></search>
				<add position="before"><![CDATA[<td class="text-right">ID</td>]]></add>
			</operation>
			<operation error="skip">
				<search trim="true"><![CDATA[<tr id="option-value-row{{ option_value_row }}">]]></search>
				<add position="after"><![CDATA[<td class="text-right">{{ option_value.option_value_id }}</td>]]></add>
			</operation>
			<operation error="skip">
				<search trim="true"><![CDATA[<td colspan="3"></td>]]></search>
				<add position="replace"><![CDATA[<td colspan="4"></td>]]></add>
			</operation>
			<operation error="skip">
				<search trim="true"><![CDATA[<tr id="option-value-row' + option_value_row + '">]]></search>
				<add position="replace"><![CDATA[<tr id="option-value-row' + option_value_row + '"><td></td>]]></add>
			</operation>
		</file>
		<file error="skip" path="admin/view/template/catalog/option_form.tpl">
			<operation error="skip">
				<search trim="true"><![CDATA[<?php if ($type == 'radio') { ?>]]></search>
				<add position="before"><![CDATA[<option value="list" <?= $type == 'list' ? 'selected="selected"' : '' ?>>List</option>]]></add>
			</operation>
			<operation error="skip">
				<search trim="true"><![CDATA[this.value == 'select']]></search>
				<add position="replace"><![CDATA[this.value == 'select' || this.value == 'list']]></add>
			</operation>
			<operation error="skip">
				<search trim="true"><![CDATA[<td class="text-left required"><?php echo $entry_option_value; ?></td>]]></search>
				<add position="before"><![CDATA[<td class="text-right">ID</td>]]></add>
			</operation>
			<operation error="skip">
				<search trim="true"><![CDATA[<tr id="option-value-row<?php echo $option_value_row; ?>">]]></search>
				<add position="after"><![CDATA[<td class="text-right"><?php echo $option_value['option_value_id']; ?></td>]]></add>
			</operation>
			<operation error="skip">
				<search trim="true"><![CDATA[<td colspan="3"></td>]]></search>
				<add position="replace"><![CDATA[<td colspan="4"></td>]]></add>
			</operation>
			<operation error="skip">
				<search trim="true"><![CDATA[<tr id="option-value-row' + option_value_row + '">]]></search>
				<add position="replace"><![CDATA[<tr id="option-value-row' + option_value_row + '"><td></td>]]></add>
			</operation>
		</file>

		<file error="skip" path="catalog/controller/api/cart.php">
			<operation error="skip">
				<search trim="true"><![CDATA[$product_options = $this->model_catalog_product->getProductOptions($this->request->post['product_id']);]]></search>
				<add position="before"><![CDATA[
					$this->load->model('extension/module/option_to_product');
					$otp_options = $this->model_extension_module_option_to_product->getOtpOptions($this->request->post['product_id']);
					if (!empty($otp_options)) {
						foreach ($otp_options as $otp_option) {
							if ($otp_option['required'] == 1 && empty($option[$otp_option['option_id']])) {
								$json['error']['option'][$otp_option['option_id']] = sprintf($this->language->get('error_required'), $otp_option['name']);
							}
						}
					}
				]]></add>
			</operation>
			<operation error="skip">
				<search trim="true"><![CDATA[$this->cart->add($product['product_id'], $product['quantity'], $option);]]></search>
				<add position="replace"><![CDATA[
					$otp_id = 0;
					if (isset($product['otp_id'])) {
						$otp_id = $product['otp_id'];
					}
					$this->cart->add($product['product_id'], $product['quantity'], $option, 0, $otp_id);
				]]></add>
			</operation>
			<operation error="skip">
				<search trim="true"><![CDATA[$this->cart->add($this->request->post['product_id'], $quantity, $option);]]></search>
				<add position="replace"><![CDATA[
					$otp_id = 0;
					if (isset($this->request->post['otp_id'])) {
						$otp_id = $this->request->post['otp_id'];
					}
					$this->cart->add($this->request->post['product_id'], $quantity, $option, 0, $otp_id);
				]]></add>
			</operation>
			<operation error="skip">
				<search trim="true"><![CDATA[$json['products'][] = array(]]></search>
				<add position="after"><![CDATA['otp_id' => $product['otp_id'],]]></add>
			</operation>
		</file>

		<file error="skip" path="catalog/controller/api/order.php">
			<operation error="skip">
				<search trim="true"><![CDATA[$order_data['products'][] = array(]]></search>
				<add position="after"><![CDATA['otp_id' => $product['otp_id'],]]></add>
			</operation>
		</file>

		<file error="skip" path="catalog/model/catalog/product.php">
			<operation error="skip" info="Add _constructor method to load OptionToProduct model and more">
				<search trim="true"><![CDATA[class ModelCatalogProduct extends Model {]]></search>
				<add position="after"><![CDATA[
					public function __construct($registry) {
						parent::__construct($registry);
						$loader = new Loader($registry);
						$loader->model('extension/module/option_to_product');
					}
				]]></add>
			</operation>
			<operation error="skip">
				<search trim="true" index="0"><![CDATA[if ($query->num_rows) {]]></search>
				<add position="after"><![CDATA[$starting_from = $this->model_extension_module_option_to_product->getStartingFrom($product_id, $query->row['price'], $query->row['special']);]]></add>
			</operation>
			<operation error="skip">
				<search trim="true"><![CDATA[=> ($query->row['discount'] ? $query->row['discount'] : $query->row['price']),]]></search>
				<add position="replace"><![CDATA[
					=> ($query->row['discount'] && !$starting_from ? $query->row['discount'] : $query->row['price']),
					'starting_from' => $starting_from,
				]]></add>
			</operation>
			<operation error="skip">
				<search trim="true"><![CDATA[$sql .= " LEFT JOIN " . DB_PREFIX . "product_description pd ON (p.product_id = pd.product_id)]]></search>
				<add position="replace"><![CDATA[$sql .= " LEFT JOIN " . DB_PREFIX . "product_description pd ON (p.product_id = pd.product_id) LEFT JOIN " . DB_PREFIX . "otp_data otp ON (p.product_id = otp.product_id)]]></add>
			</operation>
			<operation error="skip">
				<search trim="true"><![CDATA[$sql .= " OR LCASE(p.model) = '" . $this->db->escape(utf8_strtolower($data['filter_name'])) . "'";]]></search>
				<add position="after"><![CDATA[$sql .= " OR LCASE(otp.model) = '" . $this->db->escape(utf8_strtolower($data['filter_name'])) . "'";]]></add>
			</operation>
		</file>
		<file error="skip" path="catalog/controller/product/product.php">
			<operation error="skip" info="Add _constructor method to load OptionToProduct model and more">
				<search trim="true"><![CDATA[class ControllerProductProduct extends Controller {]]></search>
				<add position="after"><![CDATA[
					public function __construct($registry) {
						parent::__construct($registry);
						$loader = new Loader($registry);

						$loader->model('extension/module/option_to_product');

						if(array_key_exists('action', $this->request->get)) {
							if($this->request->get['action'] == 'getOtpChildValues') {
								$this->model_extension_module_option_to_product->getOtpChildValuesHtml();
							} else if($this->request->get['action'] == 'getOtpGrandchildValues') {
								$this->model_extension_module_option_to_product->getOtpGrandchildValuesHtml();
							} else if($this->request->get['action'] == 'getOtp') {
								$this->model_extension_module_option_to_product->getOtpHtml();
							} else if($this->request->get['action'] == 'getSwapImages') {
								$this->model_extension_module_option_to_product->getSwapImagesHtml();
							} else if($this->request->get['action'] == 'getOptCombsImages') {
								$this->model_extension_module_option_to_product->getOptCombsImagesHtml();
							}
						}
					}
				]]></add>
			</operation>
			<operation error="skip">
				<search trim="true"><![CDATA[if ($product_info) {]]></search>
				<add position="after"><![CDATA[
					$data['otp_options'] = $this->model_extension_module_option_to_product->getOtpOptions($this->request->get['product_id']);
				]]></add>
			</operation>
			<operation error="skip">
				<search trim="true"><![CDATA[public function index() {]]></search>
				<add position="after"><![CDATA[
					$data['text_starting_from'] = $this->config->get('config_otp_text_starting_from_'.$this->config->get('config_language_id'));
					$data['text_unavailable'] = $this->config->get('config_otp_text_unavailable_'.$this->config->get('config_language_id'));
				]]></add>
			</operation>
			<operation error="skip">
				<search trim="true"><![CDATA[if ($product_info) {]]></search>
				<add position="after"><![CDATA[
					$data['swapcheck'] = $this->model_extension_module_option_to_product->checkSwap($this->request->get['product_id']);
					$data['config_otp_extra'] = $this->config->get('config_otp_extra');
					$data['config_otp_dimensions'] = $this->config->get('config_otp_dimensions');
					$data['config_otp_list_width'] = $this->config->get('config_otp_list_width');
					$data['config_otp_list_height'] = $this->config->get('config_otp_list_height');
					$data['config_otp_list_radius'] = $this->config->get('config_otp_list_radius');
				]]></add>
			</operation>
			<operation error="skip">
				<search trim="true"><![CDATA[$data['options'] = array();]]></search>
				<add position="after"><![CDATA[
					if ($product_info['starting_from']) {
						$data['starting_from'] = $this->config->get('config_otp_text_starting_from_'.$this->config->get('config_language_id')) . ' ' . $this->currency->format($this->tax->calculate($product_info['starting_from'], $product_info['tax_class_id'], $this->config->get('config_tax')), $this->session->data['currency']);
						if ($this->config->get('config_tax')) {
							$data['tax'] = $this->currency->format($product_info['starting_from'], $this->session->data['currency']);
						} else {
							$data['tax'] = false;
						}
					}
					else {
						$data['starting_from'] = false;
					}
					$data['raw_price'] = $product_info['price'];
					$data['raw_special'] = $product_info['special'];
				]]></add>
			</operation>
			<operation error="skip">
				<search trim="true"><![CDATA[$results = $this->model_catalog_product->getProductImages($this->request->get['product_id']);]]></search>
				<add position="after"><![CDATA[
					if(!empty($data['otp_options'])) {
						$swap_images = $this->model_extension_module_option_to_product->addOtpImages($data, $results, $product_info);
						$data = $swap_images['data'];
						$results = $swap_images['results'];
					}
				]]></add>
			</operation>
			<operation error="skip">
				<search trim="true"><![CDATA[$discounts = $this->model_catalog_product->getProductDiscounts($this->request->get['product_id']);]]></search>
				<add position="before"><![CDATA[
					if(!empty($data['otp_options'])) {
						foreach ($results as $key => $result) {
							$data['images'][$key]['otp_thumb'] = $this->model_extension_module_option_to_product->_resize_image($result['image'], 'image_thumb');
							$data['images'][$key]['title'] = $product_info['name'].(isset($result['name'])?' :: '.$result['name']:'');
						}
					}
				]]></add>
			</operation>

			<operation error="skip">
				<search trim="true"><![CDATA[$data['products'][] = array(]]></search>
				<add position="before"><![CDATA[
					$otp_bullets = '';
					if ($this->config->get('config_otp_bullet')) {
						$bullets = $this->model_extension_module_option_to_product->getSwapBullets($result['product_id']);
						if (!empty($bullets)) {
							$otp_bullets = $this->model_extension_module_option_to_product->getBulletsHtmlCode($bullets);
						}
					}
				]]></add>
			</operation>

			<operation error="skip">
				<search trim="true"><![CDATA[$data['products'][] = array(]]></search>
				<add position="after"><![CDATA[
					'starting_from' => ($result['starting_from'] ? $this->config->get('config_otp_text_starting_from_'.$this->config->get('config_language_id')) . ' ' . $this->currency->format($this->tax->calculate($result['starting_from'], $result['tax_class_id'], $this->config->get('config_tax')), $this->session->data['currency']):''),
					'otp_bullets' => $otp_bullets,
				]]></add>
			</operation>

			<operation error="skip">
				<search trim="true" index="0"><![CDATA[$data['header'] = $this->load->controller('common/header');]]></search>
				<add position="after"><![CDATA[
					$data['html_option_combinations'] = $this->model_extension_module_option_to_product->getHtmlProductViewOptionCombinations($data);
					$data['script_footer'] = $this->model_extension_module_option_to_product->getScriptProductViewFooter($data);
				]]></add>
			</operation>
		</file>


		<file error="skip" path="catalog/controller/checkout/cart.php">
			<operation error="skip">
				<search trim="true"><![CDATA[$product_info = $this->model_catalog_product->getProduct($product_id);]]></search>
				<add position="after"><![CDATA[
					if(array_key_exists('otp', $this->request->post) && !empty($this->request->post['otp'])) {
						$ot_image = $this->db->query('SELECT image_1 FROM '.DB_PREFIX.'otp_data WHERE otp_id = '.$this->request->post['otp']);
						if($ot_image->num_rows == 1 && !empty($ot_image->row['image_1']))
							$product_info['image'] = $ot_image->row['image_1'];
        			}
				]]></add>
			</operation>

			<operation error="skip" info="Add _constructor method to load OptionToProduct model and more">
				<search trim="true"><![CDATA[class ControllerCheckoutCart extends Controller {]]></search>
				<add position="after"><![CDATA[
					public function __construct($registry) {
						parent::__construct($registry);
						$loader = new Loader($registry);
						$loader->model('extension/module/option_to_product');
					}
				]]></add>
			</operation>
			<operation error="skip">
				<search trim="true"><![CDATA[if (isset($this->request->post['option'])) {]]></search>
				<add position="before"><![CDATA[
					$otp = isset($this->request->post['otp']) ? $this->request->post['otp'] : 0;
					$swap = isset($this->request->post['swap']) ? $this->request->post['swap'] : 0;
				]]></add>
			</operation>
			<operation error="skip">
				<search trim="true"><![CDATA[$this->cart->add($this->request->post['product_id'], $quantity, $option, $recurring_id);]]></search>
				<add position="replace"><![CDATA[$this->cart->add($this->request->post['product_id'], $quantity, $option, $recurring_id, $otp, $swap);]]></add>
			</operation>
			<operation error="skip">
				<search trim="true"><![CDATA[$product_options = $this->model_catalog_product->getProductOptions($this->request->post['product_id']);]]></search>
				<add position="before"><![CDATA[
					$otp_options = $this->model_extension_module_option_to_product->getOtpOptions($this->request->post['product_id']);
					if (!empty($otp_options)) {
						foreach ($otp_options as $otp_option) {
							if ($otp_option['required'] == 1 && empty($option[$otp_option['option_id']])) {
								$json['error']['option'][$otp_option['option_id']] = sprintf($this->language->get('error_required'), $otp_option['name']);
							}
						}
					}
				]]></add>
			</operation>
		</file>
		<file error="skip" path="system/library/cart/cart.php|system/library/cart.php">
			<operation error="skip">
				<search trim="true"><![CDATA[class Cart {]]></search>
				<add position="before"><![CDATA[require_once DIR_SYSTEM . 'library/otp.php';]]></add>
			</operation>
			<operation error="skip">
				<search trim="true"><![CDATA[$this->weight = $registry->get('weight');]]></search>
				<add position="after"><![CDATA[$this->otp = new \Otp($registry);]]></add>
			</operation>
			<operation error="skip">
				<search trim="true"><![CDATA[$this->add($cart['product_id'], $cart['quantity'], json_decode($cart['option']), $cart['recurring_id']);]]></search>
				<add position="replace"><![CDATA[$this->add($cart['product_id'], $cart['quantity'], json_decode($cart['option']), $cart['recurring_id'], $cart['otp_id'], $cart['swap_id']);]]></add>
			</operation>
			<operation error="skip">
				<search trim="true"><![CDATA[public function add($product_id, $quantity = 1, $option = array(), $recurring_id = 0) {]]></search>
				<add position="replace"><![CDATA[public function add($product_id, $quantity = 1, $option = array(), $recurring_id = 0, $otp_id = 0, $swap_id = 0) {]]></add>
			</operation>
			<operation error="skip">
				<search trim="true"><![CDATA[date_added = NOW()");]]></search>
				<add position="replace"><![CDATA[date_added = NOW(), `otp_id` = '" . $otp_id . "', `swap_id` = '" . $swap_id . "'");]]></add>
			</operation>
			<operation error="skip">
				<search trim="true"><![CDATA[$option_data = array();]]></search>
				<add position="replace"><![CDATA[ ]]></add>
			</operation>
			<operation error="skip">
				<search trim="true"><![CDATA[$option_query->row['type'] == 'select']]></search>
				<add position="replace"><![CDATA[$option_query->row['type'] == 'select' || $option_query->row['type'] == 'list']]></add>
			</operation>
			<operation error="skip">
				<search trim="true"><![CDATA[if ($product_query->num_rows && ($cart['quantity'] > 0)) {]]></search>
				<add position="before"><![CDATA[
					$option_data = array();
					$otp_data = array();
					if ($cart['otp_id']) {
						$otpcount = 0;
						$otp_options = array();
						$otp_check_query = $this->db->query("SELECT * FROM " . DB_PREFIX . "otp_option_value WHERE `id` = '" . $cart['otp_id'] . "' LIMIT 1");
						if ($otp_check_query->num_rows) {
							$otp_options = array(
								'parent' => $otp_check_query->row['parent_option_id'],
								'child' => $otp_check_query->row['child_option_id'],
								'grandchild' => $otp_check_query->row['grandchild_option_id']
							);
							foreach (json_decode($cart['option']) as $otp_option_id => $otp_option_value_id) {
								if (in_array($otp_option_id, $otp_options)) {
									$otpcount++;
									$otp_option_query = $this->db->query("SELECT o.type, od.name FROM `" . DB_PREFIX . "option` o LEFT JOIN `" . DB_PREFIX . "option_description` od ON (o.option_id = od.option_id) WHERE o.option_id = '" . $otp_option_id . "' AND od.language_id = '" . $this->config->get('config_language_id') . "'");
									if ($otp_option_id == $otp_options['parent']) {
										$otp_option_value_query = $this->db->query("SELECT ovd.name, otpd.model, otpd.quantity, otpd.subtract, otpd.price_prefix, otpd.price, otpd.special, otpd.special_from, otpd.special_to, otpd.points, otpd.weight_prefix, otpd.weight FROM " . DB_PREFIX . "otp_option_value otp INNER JOIN " . DB_PREFIX . "otp_data otpd ON otp.id = otpd.otp_id LEFT JOIN " . DB_PREFIX . "option_value_description ovd ON (otp.parent_option_value_id = ovd.option_value_id) WHERE otp.id = '" . $cart['otp_id'] . "' AND ovd.language_id = '" . $this->config->get('config_language_id') . "'");
										$otp_option_value_query->row = $this->otp->process_prices_specials_by_customer_groups($otp_option_value_query->row);
										if ($otp_option_value_query->row['subtract'] == 1 && (!$otp_option_value_query->row['quantity'] || ($otp_option_value_query->row['quantity'] < $cart['quantity']))) {
											$stock = false;
										}
										$option_data[] = array(
											'product_option_id'       => $otp_option_id,
											'product_option_value_id' => $otp_option_value_id,
											'option_id'               => $otp_option_id,
											'option_value_id'         => $otp_option_value_id,
											'name'                    => $otp_option_query->row['name'],
											'value'                   => $otp_option_value_query->row['name'],
											'type'                    => $otp_option_query->row['type']
										);
										$otp_data['otp_id'] = $cart['otp_id'];
										$otp_data['model'] = $otp_option_value_query->row['model'];
										$otp_data['price_prefix'] = $otp_option_value_query->row['price_prefix'];
										$otp_data['price'] = $otp_option_value_query->row['price'];
										$otp_data['special'] = $otp_option_value_query->row['special'];
										$otp_data['special_from'] = $otp_option_value_query->row['special_from'];
										$otp_data['special_to'] = $otp_option_value_query->row['special_to'];
										$otp_data['points'] = $otp_option_value_query->row['points'];
										$otp_data['weight_prefix'] = $otp_option_value_query->row['weight_prefix'];
										$otp_data['weight'] = $otp_option_value_query->row['weight'];
									}
									elseif ($otp_option_id == $otp_options['child']) {
										$otp_option_value_query = $this->db->query("SELECT ovd.name, otpd.quantity, otpd.subtract FROM " . DB_PREFIX . "otp_option_value otp INNER JOIN " . DB_PREFIX . "otp_data otpd ON otp.id = otpd.otp_id LEFT JOIN " . DB_PREFIX . "option_value_description ovd ON (otp.child_option_value_id = ovd.option_value_id) WHERE otp.id = '" . $cart['otp_id'] . "' AND ovd.language_id = '" . $this->config->get('config_language_id') . "'");
										if ($otp_option_value_query->row['subtract'] && (!$otp_option_value_query->row['quantity'] || ($otp_option_value_query->row['quantity'] < $cart['quantity']))) {
											$stock = false;
										}
										$option_data[] = array(
											'product_option_id'       => $otp_option_id,
											'product_option_value_id' => $otp_option_value_id,
											'option_id'               => $otp_option_id,
											'option_value_id'         => $otp_option_value_id,
											'name'                    => $otp_option_query->row['name'],
											'value'                   => $otp_option_value_query->row['name'],
											'type'                    => $otp_option_query->row['type']
										);
									}
									elseif ($otp_option_id == $otp_options['grandchild']) {
										$otp_option_value_query = $this->db->query("SELECT ovd.name, otpd.quantity, otpd.subtract FROM " . DB_PREFIX . "otp_option_value otp INNER JOIN " . DB_PREFIX . "otp_data otpd ON otp.id = otpd.otp_id LEFT JOIN " . DB_PREFIX . "option_value_description ovd ON (otp.grandchild_option_value_id = ovd.option_value_id) WHERE otp.id = '" . $cart['otp_id'] . "' AND ovd.language_id = '" . $this->config->get('config_language_id') . "'");
										if ($otp_option_value_query->row['subtract'] && (!$otp_option_value_query->row['quantity'] || ($otp_option_value_query->row['quantity'] < $cart['quantity']))) {
											$stock = false;
										}
										$option_data[] = array(
											'product_option_id'       => $otp_option_id,
											'product_option_value_id' => $otp_option_value_id,
											'option_id'               => $otp_option_id,
											'option_value_id'         => $otp_option_value_id,
											'name'                    => $otp_option_query->row['name'],
											'value'                   => $otp_option_value_query->row['name'],
											'type'                    => $otp_option_query->row['type']
										);
									}
								}
							}
						}
						else {
							$this->remove($cart['cart_id']);
						}
					}
				]]></add>
			</operation>
			<operation error="skip">
				<search trim="true"><![CDATA[$product_data[] = array(]]></search>
				<add position="replace"><![CDATA[
					$final_reward = $reward;
					if ($cart['otp_id'] == 0) {
						$final_model = $product_query->row['model'];
						$final_price = $price + $option_price;
						$final_total = ($price + $option_price) * $cart['quantity'];
						$final_reward = $reward;
						$final_weight = ($product_query->row['weight'] + $option_weight) * $cart['quantity'];
					}
					else {
						if ($otp_data['model'] != '') {
							$final_model = $otp_data['model'];
						}
						else {
							$final_model = $product_query->row['model'];
						}

						if ($otp_data['points'] != '' && $otp_data['points'] > 0) {
							$final_reward = $otp_data['points'];
						}

						if ($product_discount_query->num_rows) {
							$final_price = $product_discount_query->row['price'] + $option_price;
							$final_total = ($product_discount_query->row['price'] + $option_price) * $cart['quantity'];
						}
						else {
							if ($this->config->get('config_otp_special') && $otp_data['special'] > 0) {
								$final_price = $otp_data['special'] + $option_price;
								$final_total = ($otp_data['special'] + $option_price) * $cart['quantity'];
							}
							elseif ($this->config->get('config_otp_price') && $otp_data['price'] > 0) {
								if ($otp_data['price_prefix'] == "=") {
									$final_price = $otp_data['price'] + $option_price;
									$final_total = ($otp_data['price'] + $option_price) * $cart['quantity'];
								}
								elseif ($otp_data['price_prefix'] == "+") {
									$final_price = $price + $otp_data['price'] + $option_price;
									$final_total = ($price + $otp_data['price'] + $option_price) * $cart['quantity'];
								}
								else {
									$final_price = $price - $otp_data['price'] + $option_price;
									$final_total = ($price - $otp_data['price'] + $option_price) * $cart['quantity'];
								}
							}
							else {
								$final_price = $price + $option_price;
								$final_total = ($price + $option_price) * $cart['quantity'];
							}
						}
						if ($this->config->get('config_otp_weight') && $otp_data['weight'] > 0) {
							if ($otp_data['weight_prefix'] == "=") {
								$final_weight = ($otp_data['weight'] + $option_weight) * $cart['quantity'];
							}
							elseif ($otp_data['weight_prefix'] == "+") {
								$final_weight = ($product_query->row['weight'] + $otp_data['weight'] + $option_weight) * $cart['quantity'];
							}
							else {
								$final_weight = ($product_query->row['weight'] - $otp_data['weight'] + $option_weight) * $cart['quantity'];
							}
						}
						else {
							$final_weight = ($product_query->row['weight'] + $option_weight) * $cart['quantity'];
						}
					}
					$final_image = '';
					if($cart['otp_id']) {
                        $result = $this->db->query("SELECT image_1 FROM " . DB_PREFIX . "otp_data WHERE `otp_id` = '" . $cart['otp_id'] . "'");
                        $final_image = !empty($result->row['image_1']) ? $result->row['image_1'] : '';
                    }

					if (empty($final_image) && $cart['swap_id'] == 0) {
				        $final_image = $product_query->row['image'];
					}
					else if(empty($final_image)) {
						$otp_swap_query = $this->db->query("SELECT * FROM " . DB_PREFIX . "otp_image WHERE `id` = '" . $cart['swap_id'] . "'");
						if ($otp_swap_query->num_rows) {
							$final_image = $otp_swap_query->row['image'];
						}
						else {
							$final_image = $product_query->row['image'];
						}
					}


					$product_data[] = array(
						'otp_id' => $cart['otp_id'],
						'swap_id' => $cart['swap_id'],
				]]></add>
			</operation>
			<operation error="skip">
				<search trim="true"><![CDATA[$product_query->row['model'],]]></search>
				<add position="replace"><![CDATA[$final_model,]]></add>
			</operation>
			<operation error="skip">
				<search trim="true"><![CDATA[$product_query->row['image'],]]></search>
				<add position="replace"><![CDATA[$final_image,]]></add>
			</operation>
			<operation error="skip">
				<search trim="true"><![CDATA[($price + $option_price),]]></search>
				<add position="replace"><![CDATA[$final_price,]]></add>
			</operation>
			<operation error="skip">
				<search trim="true"><![CDATA['reward'          => $reward * $cart['quantity'],]]></search>
				<add position="replace"><![CDATA['reward'          => $final_reward * $cart['quantity'],]]></add>
			</operation>
			<operation error="skip">
				<search trim="true"><![CDATA[($price + $option_price) * $cart['quantity'],]]></search>
				<add position="replace"><![CDATA[$final_total,]]></add>
			</operation>
			<operation error="skip">
				<search trim="true"><![CDATA[($product_query->row['weight'] + $option_weight) * $cart['quantity'],]]></search>
				<add position="replace"><![CDATA[$final_weight,]]></add>
			</operation>
		</file>

		<file error="skip" path="catalog/model/checkout/order.php">
			<operation error="skip">
				<search trim="true"><![CDATA[reward = '" . (int)$product['reward'] . "']]></search>
				<add position="replace"><![CDATA[reward = '" . (int)$product['reward'] . "', otp_id = '" . (int)$product['otp_id'] . "']]></add>
			</operation>
			<operation error="skip">
				<search trim="true"><![CDATA[$this->db->query("UPDATE " . DB_PREFIX . "product SET quantity = (quantity -]]></search>
				<add position="replace"><![CDATA[
					$this->db->query("UPDATE `" . DB_PREFIX . "otp_data` SET `quantity` = (quantity - " . (int)$order_product['quantity'] . ") WHERE `otp_id` = '" . (int)$order_product['otp_id'] . "' AND subtract = '1' LIMIT 1");
					$this->db->query("UPDATE " . DB_PREFIX . "product SET quantity = (quantity -
				]]></add>
			</operation>
			<operation error="skip">
				<search trim="true"><![CDATA[$this->db->query("UPDATE `" . DB_PREFIX . "product` SET quantity = (quantity +]]></search>
				<add position="replace"><![CDATA[
					$this->db->query("UPDATE `" . DB_PREFIX . "otp_data` SET `quantity` = (quantity + " . (int)$product['quantity'] . ") WHERE `otp_id` = '" . (int)$product['otp_id'] . "' AND subtract = '1' LIMIT 1");
					$this->db->query("UPDATE `" . DB_PREFIX . "product` SET quantity = (quantity +
				]]></add>
			</operation>
		</file>
		<file error="skip" path="catalog/controller/checkout/confirm.php">
			<operation error="skip">
				<search trim="true"><![CDATA['product_id' => $product['product_id'],]]></search>
				<add position="replace"><![CDATA[
					'otp_id' => $product['otp_id'],
					'product_id' => $product['product_id'],
				]]></add>
			</operation>
		</file>

		<file error="skip" path="catalog/controller/common/header.php">
			<operation error="skip">
				<search trim="true"><![CDATA[$data['cart'] = $this->load->controller('common/cart');]]></search>
				<add position="after"><![CDATA[
					$this->load->model('extension/module/option_to_product');
					$data['config_otp_bullet'] = $this->config->get('config_otp_bullet');
					$data['config_otp_bullet_radius'] = $this->config->get('config_otp_bullet_radius');
					$data['opt_head_html_js_code'] = $this->model_extension_module_option_to_product->getScriptCssHeaderView($data);
				]]></add>
			</operation>
		</file>
		<file error="skip" path="catalog/view/theme/*/template/common/header.tpl">
			<operation error="skip">
				<search trim="true"><![CDATA[</head>]]></search>
				<add position="before"><![CDATA[<?= $opt_head_html_js_code ?>]]></add>
			</operation>
		</file>
		<file error="skip" path="catalog/view/theme/*/template/common/header.twig">
			<operation error="skip">
				<search trim="true"><![CDATA[</head>]]></search>
				<add position="before"><![CDATA[{{ opt_head_html_js_code }}]]></add>
			</operation>
		</file>

		<file error="skip" path="catalog/controller/product/category.php|catalog/controller/product/manufacturer.php|catalog/controller/product/search.php|catalog/controller/product/special.php">
			<operation error="skip" info="Add _constructor method to load OptionToProduct model and more">
				<search trim="true"><![CDATA[extends Controller {]]></search>
				<add position="replace"><![CDATA[extends Controller {
					public function __construct($registry) {
						parent::__construct($registry);
						$loader = new Loader($registry);
						$loader->model('extension/module/option_to_product');

						$this->text_starting_from = $this->config->get('config_otp_text_starting_from_'.$this->config->get('config_language_id'));
						$this->text_unavailable = $this->config->get('config_otp_text_unavailable_'.$this->config->get('config_language_id'));
					}
				]]></add>
			</operation>
			<operation error="skip">
				<search trim="true"><![CDATA[$data['products'][] = array(]]></search>
				<add position="before"><![CDATA[
				$otp_bullets = '';
				if ($this->config->get('config_otp_bullet')) {
					$bullets = $this->model_extension_module_option_to_product->getSwapBullets($result['product_id']);
					if (!empty($bullets)) {
						$otp_bullets = $this->model_extension_module_option_to_product->getBulletsHtmlCode($bullets);
					}
				}
				]]></add>
			</operation>
			<operation error="skip">
				<search trim="true"><![CDATA[$data['products'][] = array(]]></search>
				<add position="after"><![CDATA[
					'starting_from' => ($result['starting_from'] ? $this->text_starting_from . ' ' . $this->currency->format($this->tax->calculate($result['starting_from'], $result['tax_class_id'], $this->config->get('config_tax')), $this->session->data['currency']):''),
					'otp_bullets' => $otp_bullets,
				]]></add>
			</operation>
			<operation error="skip">
				<search trim="true"><![CDATA[$tax = false;]]></search>
				<add position="before" offset="1"><![CDATA[
					if(version_compare(VERSION, '2.2', '>='))
						$this->currency->format($result['starting_from']?$result['starting_from']:((float)$result['special'] ? $result['special'] : $result['price']), $this->session->data['currency']);
					else
						$this->currency->format($result['starting_from']?$result['starting_from']:((float)$result['special'] ? $result['special'] : $result['price']));
				]]></add>
			</operation>
		</file>
		<file error="skip" path="catalog/controller/extension/module/bestseller.php|catalog/controller/extension/module/latest.php|catalog/controller/extension/module/special.php|catalog/controller/extension/module/featured.php">
			<operation error="skip" info="Add _constructor method to load OptionToProduct model and more">
				<search trim="true"><![CDATA[extends Controller {]]></search>
				<add position="replace"><![CDATA[extends Controller {
					public function __construct($registry) {
						parent::__construct($registry);
						$loader = new Loader($registry);
						$loader->model('extension/module/option_to_product');

						$this->text_starting_from = $this->config->get('config_otp_text_starting_from_'.$this->config->get('config_language_id'));
						$this->text_unavailable = $this->config->get('config_otp_text_unavailable_'.$this->config->get('config_language_id'));
					}
				]]></add>
			</operation>
			<operation error="skip">
				<search trim="true"><![CDATA[if ($this->config->get('config_tax')) {]]></search>
				<add position="replace"><![CDATA[
					$starting_from = isset($result) ? $result['starting_from'] : $product_info['starting_from'];
					$tax_class_id = isset($result) ? $result['tax_class_id'] : $product_info['tax_class_id'];
					if ($this->config->get('config_tax') && $starting_from) {
						$tax = $this->currency->format($starting_from, $this->session->data['currency']);
					}
					elseif ($this->config->get('config_tax')) {
				]]></add>
			</operation>
			<operation error="skip">
				<search trim="true"><![CDATA[$data['products'][] = array(]]></search>
				<add position="before"><![CDATA[
					$otp_bullets = '';
					if ($this->config->get('config_otp_bullet')) {
						$product_id = isset($result) ? $result['product_id'] : $product_info['product_id'];
						$bullets = $this->model_extension_module_option_to_product->getSwapBullets($product_id);
						if (!empty($bullets)) {
							$otp_bullets = $this->model_extension_module_option_to_product->getBulletsHtmlCode($bullets, $setting);
						}
					}
				]]></add>
			</operation>
			<operation error="skip">
				<search trim="true"><![CDATA[$data['products'][] = array(]]></search>
				<add position="after"><![CDATA[
					'starting_from' => ($starting_from?$this->text_starting_from . ' ' . $this->currency->format($this->tax->calculate($starting_from, $tax_class_id, $this->config->get('config_tax')), $this->session->data['currency']):''),
					'otp_bullets' => $otp_bullets,
				]]></add>
			</operation>
		</file>
		<file error="skip" path="catalog/controller/product/compare.php">
			<operation error="skip" info="Add _constructor method to load OptionToProduct model and more">
				<search trim="true"><![CDATA[extends Controller {]]></search>
				<add position="replace"><![CDATA[extends Controller {
					public function __construct($registry) {
						parent::__construct($registry);
						$this->text_starting_from = $this->config->get('config_otp_text_starting_from_'.$this->config->get('config_language_id'));
						$this->text_unavailable = $this->config->get('config_otp_text_unavailable_'.$this->config->get('config_language_id'));
					}
				]]></add>
			</operation>
			<operation error="skip">
				<search trim="true"><![CDATA[$data['products'][$product_id] = array(]]></search>
				<add position="after"><![CDATA['starting_from' => ($product_info['starting_from']?$this->text_starting_from . ' ' . $this->currency->format($this->tax->calculate($product_info['starting_from'], $product_info['tax_class_id'], $this->config->get('config_tax')), $this->session->data['currency']):''),]]></add>
			</operation>
		</file>
</modification>