Мультивалютность Opencart (OCstore) | Валюта по умолчанию доллары, а отображение цен на сайте по умолчанию в рублях

Задача: Хранить в базе данных цену каждого товара в своей валюте: Товар№1=Рубли, Товар№2=Доллары, Товар№3=Евро, Товар№4=МойСобственныйКурс и т.д.
На фронт выводить цены всегда в рублях, вне зависимости от валюты товара.
И при этом пересчитывать нерублёвые цены по указанному в админке курсу.
В общем, сделать как на Virtuemart.

Тестировалось на OcStore 2

1. В таблицу oc_product базы данных добавляем поле vendor_price, которое будет хранить цену от поставщика в его валюте (например в долларах). Формат данных указываем DECIMAL(15,2)
В эту же таблицу добавляем поле currency_id для связи с таблицей oc_currency

В таблице oc_currency поле value тип данных меняем с FLOAT на DECIMAL (15,8)

 

2. В модели админки добавляем эти поля. В файле /admin/model/catalog/product.php

Сначала добавим функцию получения списка валют, сразу после

class ModelCatalogProduct extends Model {

public function getCurrencies() {
$query = $this->db->query("SELECT * FROM " . DB_PREFIX . "currency");
return $query->rows;
}

Затем функция public function addProduct($data)

добавляем:

public function addProduct($data) {
$this->event->trigger('pre.admin.product.add', $data);

$this->db->query("INSERT INTO " . DB_PREFIX . "product SET
currency_id = '" . (int)$data['currency_id'] . "',
vendor_price = '" . (float)$data['vendor_price'] . "',
model = '" . $this->db->escape($data['model']) . "',
.........

 

после

$product_id = $this->db->getLastId();

добавляем пересчет по курсу

$this->db->query("UPDATE " . DB_PREFIX . "product JOIN " . DB_PREFIX . "currency USING(currency_id) SET price = vendor_price/value WHERE product_id = '" . (int)$product_id . "'");

 

 

функция public function editProduct($product_id, $data)

добавляем:

public function editProduct($product_id, $data) {

$this->event->trigger('pre.admin.product.edit', $data);

$this->db->query("UPDATE " . DB_PREFIX . "product SET
currency_id = '" . (int)$data['currency_id'] . "',
vendor_price = '" . (float)$data['vendor_price'] . "',
model = '" . $this->db->escape($data['model']) . "',

 

и ниже этого запроса добавляем пересчет по курсу

$this->db->query("UPDATE " . DB_PREFIX . "product JOIN " . DB_PREFIX . "currency USING(currency_id) SET price = vendor_price/value WHERE product_id = '" . (int)$product_id . "'");

 

Теперь добавим валюту в массив с продуктами public function getProducts($data = array()) {

    public function getProducts($data = array()) {
       
            $sql = "SELECT * FROM " . DB_PREFIX . "product p
            LEFT JOIN " . DB_PREFIX . "currency cur USING(`currency_id`)
            LEFT JOIN " . DB_PREFIX . "product_description pd ON (p.product_id = pd.product_id)";
           ....................

 

3. В контроллере /admin/controller/catalog/product.php

в переменную $data['products'][] = array(

добавляем поля

$data['products'][] = array(
'product_id' => $result['product_id'],
'image' => $image,
'name' => $result['name'],
'model' => $result['model'],
'price' => $result['price'],
'currency' => $result['title'], //Название валюты
'kurs' => $result['value'], //Курс валюты
'vendor_price' => $result['vendor_price'], //Цена поставщика
'category' => $category,
.................

 

Далее в функции protected function getForm() {

добавляем

    $data['currencies'] = $this->model_catalog_product->getCurrencies();
   
        if (!empty($product_info)) {
            $data['currency_id'] = $product_info['currency_id'];
            } else {
            $data['currency_id'] = '1';
        }

 

 

Далее строка примерно 960

после

if (isset($this->request->post['price'])) {
$data['price'] = $this->request->post['price'];
} elseif (!empty($product_info)) {
$data['price'] = $product_info['price'];
} else {
$data['price'] = '';
}

вставляем

if (isset($this->request->post['vendor_price'])) {
$data['vendor_price'] = $this->request->post['vendor_price'];
} elseif (!empty($product_info)) {
$data['vendor_price'] = $product_info['vendor_price'];
} else {
$data['vendor_price'] = ''; }

 if (isset($this->request->post['currency_id'])) {
$data['currency_id'] = $this->request->post['currency_id'];
} elseif (!empty($product_info)) {
$data['currency_id'] = $product_info['currency_id'];
} else {
$data['currency_id'] = '1'; }

 

 

4. Добавляем поля в файлах шаблонов.
Шаблон списка товаров /admin/view/template/catalog/product_list.tpl

добавляем заголовки колонок, строка примерно 112

<td class="text-left">Цена поставщика</td>
<td class="text-right">Валюта</td>
<td class="text-left">Курс</td>

и поля с данными, строка примерно 153

<td class="text-right"><?php echo $product['vendor_price'];?></td>
<td class="text-left"><?php echo $product['currency'];?></td>
<td class="text-left"><?php echo $product['kurs'];?></td>

 

Шаблон карточки товара /admin/view/template/catalog/product_form.tpl

Добавляем новые поля и закрываем от редактирования поле price

строка примерно 165

меняем тип на Hidden и добавим вывод рабочей цены

<div class="form-group">
<label class="col-sm-2 control-label" for="input-price"><?php echo $entry_price; ?></label>
<div class="col-sm-10">
<input type="hidden" name="price" value="<?php echo $price; ?>" placeholder="<?php echo $entry_price; ?>" id="input-price" class="form-control" />
<span><?php echo $price; ?></span>
</div>
</div>

 

ниже вставляем


<div class="form-group">
<label class="col-sm-2 control-label" for="input-vendor_price">Цена поставщика</label>
<div class="col-sm-10">
<input type="text" name="vendor_price" value="<?php echo $vendor_price; ?>" placeholder="0" id="input-vendor_price" class="form-control" />
</div>
</div>

<div class="form-group">
<label class="col-sm-2 control-label" for="input-currency">Валюта</label>
<div class="col-sm-10">
<select name="currency_id" id="input-currency" class="form-control">
<?php foreach ($currencies as $currency) { ?>
<?php if ($currency['currency_id'] == $currency_id) { ?>
<option value="<?php echo $currency['currency_id']; ?>" selected="selected"><?php echo $currency['title']; ?></option>
<?php } else { ?>
<option value="<?php echo $currency['currency_id']; ?>"><?php echo $currency['title']; ?></option>
<?php } ?>
<?php } ?>
</select>
</div>
</div>

В итоге получилось так:
список валют в админке Opencart-2

Теперь при нажатии на кнопку "Сохранить" цена в базе в поле price обновится по формуле vendor_price/value



5. Осталось самое главное – пересчитать все цены по курсу. Сделать это очень просто. Нужно добавить запрос на обновление после сохранения курса в базу. Открываем файл /admin/model/localisation/currency.php

И модифицируем функцию editCurrency()

public function editCurrency($currency_id, $data) {
$this->db->query("UPDATE " . DB_PREFIX . "currency SET
title = '" . $this->db->escape($data['title']) . "',
code = '" . $this->db->escape($data['code']) . "',
symbol_left = '" . $this->db->escape($data['symbol_left']) . "',
symbol_right = '" . $this->db->escape($data['symbol_right']) . "',
decimal_place = '" . $this->db->escape($data['decimal_place']) . "',
value = '" . $this->db->escape($data['value']) . "',
status = '" . (int)$data['status'] . "',
date_modified = NOW()
WHERE currency_id = '" . (int)$currency_id . "'");

$this->db->query("UPDATE " . DB_PREFIX . "product JOIN " . DB_PREFIX . "currency USING(currency_id)
SET price = vendor_price / value WHERE currency_id = '". (int)$currency_id ."'");

$this->cache->delete('currency');
}

Цены на сайте будут меняться каждый раз, когда вы меняете значение курса. И здесь у нас открываются широкие возможности в плане курсов. Мы можем заводить свои собственные курсы, которые можно назвать наценкой. Это видно на рисунках ниже

валюта opencart
валюта opencart

 

 

6. Теперь смотрим список товаров в админке и нам всё понятно. Скрипт тянет курс с Yahoo и пересчитывает неправильно ЕВРО.

Исправим это недоразумение. Воспользуемся бесплатным готовым решением для получения актуальных курсов ЦБ РФ на opencartforum.com
Обратите внимание, что функция обновления валют в OpenCart-2 сменила свое название с updateCurrencies на refresh, поэтому нельзя просто заменить файл /admin/model/localisation/currency.php
Мы заменим стандартный код функции public function refresh($force = false) в модели /admin/model/localisation/currency.php
на код функции public function updateCurrencies() из готового решения.

Должно быть так:

public function refresh() {

...Здесь код из готового решения...

}

И непременно в этот файл добавляем вспомогательную функцию из того же решения:

public function CheckHttpStatus($url) {

...код функции...

}

Теперь курсы пересчитываются правильно.

Если нам нужно прибавить 2% к курсу конкретной валюты, например, только к ЕВРО, а к остальным не нужно, то в функции public function refresh() нужно добавить проверку по коду валюты и умножить значение на 1,02.

if ($result['code'] == 'EUR') {
	$curs = $ret[$result['code']] * 1.02;
} else {
	$curs = $ret[$result['code']];
	}
$value = 1 / $curs;

 

На этом всё. Если возникнут вопросы, пишите.