@Sandro_s

Как в Yii2 реализовать мультивалютность?

Использую шаблон basik c модульной админкой. В main шаблоне интернет - магазина есть такой вот переключатель:

<div class="btn-group pull-right">
                        <div class="btn-group">
                            <button type="button" class="btn btn-default dropdown-toggle usa" data-toggle="dropdown">
                                USA
                                <span class="caret"></span>
                            </button>
                            <ul class="dropdown-menu">
                                <li><a href="#">Canada</a></li>
                                <li><a href="#">UK</a></li>
                            </ul>
                        </div>

                        <div class="btn-group">
                            <button type="button" class="btn btn-default dropdown-toggle usa" data-toggle="dropdown">
                                DOLLAR
                                <span class="caret"></span>
                            </button>
                            <ul class="dropdown-menu">
                                <li><a href="#">Canadian Dollar</a></li>
                                <li><a href="#">Pound</a></li>
                            </ul>
                        </div>
                    </div>
                </div>
                <div class="col-sm-8">
                    <div class="shop-menu pull-right">


В товарах, которые выводятся на главную из index/category

<div class="price-range"><!--price-range-->
            <h2>Price Range</h2>
            <div class="well text-center">
                <input type="text" class="span2" value="" data-slider-min="0" data-slider-max="600" data-slider-step="5" data-slider-value="[250,450]" id="sl2" ><br />
                <b class="pull-left">$ 0</b> <b class="pull-right">$ 600</b>
            </div>
        </div><!--/price-range-->


Цена на товар хранится в бд в 'price' просто числом и выводится сейчас как бы в долларах.
<h2>$<?= $hit->price?></h2>

Как реализовать переключатель валют в товарах и затем, чтобы это интегрировать с Робокассой, к примеру?
  • Вопрос задан
  • 595 просмотров
Пригласить эксперта
Ответы на вопрос 1
Для реализации задачи нужно следующее:
  1. В таблице товаров, помимо поля price, ещё нужно иметь поле currency_code, в котором хранить код валюты данного товара (ведь исходная цена товара может быть в USD, или EUR - не менять же её постоянно при колебаниях курса).

  2. Создать модуль для валют (таблица currency в БД, модель Currency и удобный КРУД для управления валютами). В таблице валют уникальный должен быть code - код валюты, по внешнему ключу связать его с полем currency_code в таблице товаров. Также у валюты должны быть поля rate (курс) и default (валюта по умолчанию для сайта). Для валюты по умолчанию rate должен быть равен 1.

  3. Нужно написать маленький компонент app/components/Currency.php, в котором через работу с сессией, сохранять в сессию выбранную пользователем валюту на сайте (выбор валюты через виджет удобно сделать). Также, во всех местах проекта, где выводится цена товара, она должна выводиться через компонент валют, чтобы он её преобразовывал из исходной (той, что в базе указана в качестве валюты для цены товара) в ту, что выбрал пользователь. Преобразование, соответственно, заданному в админке курсу (КРУД для валют, поле rate).

Пример модели валют
<?php

namespace app\modules\shop\models;

use Yii;
use yii\db\ActiveRecord;
use yii\helpers\ArrayHelper;

class Currency extends ActiveRecord
{
    const STATUS_ACTIVE = 1;
    const STATUS_INACTIVE = 0;

    public function behaviors()
    {
        return [
            'timestamp' => [
                'class' => \yii\behaviors\TimestampBehavior::class,
            ],
            'blameable' => [
                'class' => \yii\behaviors\BlameableBehavior::class,
            ],
            'ip' => [
                'class' => \yii\behaviors\AttributeBehavior::class,
                'attributes' => [
                    ActiveRecord::EVENT_BEFORE_INSERT => 'created_ip',
                    ActiveRecord::EVENT_BEFORE_UPDATE => 'updated_ip',
                ],
                'value' => function ($event) {
                    return Yii::$app->request->getUserIP();
                },
            ],
        ];
    }

    public static function tableName()
    {
        return 'currency';
    }

    public function rules()
    {
        return [
            [['name', 'code'], 'required'],
            [['is_default', 'sort', 'status'], 'integer'],
            [['decimal_places'], 'integer', 'max' => 9],
            [['rate'], 'number'],
            [['code'], 'string', 'length' => 3],
            [['code'], 'unique'],
            [['code'], 'match', 'pattern' => '/^[A-Z]+$/', 'message' => Yii::t('app', 'Это поле может содержать только строчные буквы, цифры и дефис')],
            [['name', 'symbol'], 'string', 'max' => 32],
        ];
    }

    public function attributeLabels()
    {
        return [
            'id' => Yii::t('app', 'ID'),
            'created_at' => Yii::t('app', 'Дата создания'),
            'updated_at' => Yii::t('app', 'Дата обновления'),
            'created_by' => Yii::t('app', 'Создано пользователем'),
            'updated_by' => Yii::t('app', 'Обновлено пользователем'),
            'created_ip' => Yii::t('app', 'Создано c IP'),
            'updated_ip' => Yii::t('app', 'Обновлено c IP'),
            'code' => Yii::t('app', 'Код'),
            'name' => Yii::t('app', 'Название'),
            'symbol' => Yii::t('app', 'Символ'),
            'rate' => Yii::t('app', 'Курс'),
            'decimal_places' => Yii::t('app', 'Количество знаков после запятой'),
            'is_default' => Yii::t('app', 'По умолчанию'),
            'sort' => Yii::t('app', 'Сортировка'),
            'status' => Yii::t('app', 'Опубликован'),
        ];
    }
   
    public function afterSave($insert, $changedAttributes)
    {
        return Yii::$app->session->remove('currency');
    }
    
    public static function listItems()
    {
        $items = self::find()
            ->select(['code'])
            ->where(['status' => self::STATUS_ACTIVE])
            ->orderBy(['sort' => SORT_ASC])
            ->asArray()
            ->all();
        return ArrayHelper::map($items, 'code', 'code');
    }
    
    public static function statuses()
    {
        return [
            self::STATUS_ACTIVE => Yii::t('app', 'Опубликован'),
            self::STATUS_INACTIVE => Yii::t('app', 'Не опубликован'),
        ];
    }
}

Пример компонента валют
<?php

namespace app\modules\shop\components;

use Yii;
use yii\base\BaseObject;
use app\modules\shop\models\Currency;

class CurrencyManager extends BaseObject
{
    public $currencies;
    public $defaultCurrency;
    public $siteCurrency;
    
    public function init()
    {
        parent::init();
        
        $this->currencies = Currency::find()
            ->where(['status' => Currency::STATUS_ACTIVE])
            ->orderBy(['sort' => SORT_ASC])
            ->asArray()
            ->all();
        foreach ($this->currencies as $item) {
            if ($item['is_default'] == 1) {
                $this->defaultCurrency = $item;
            }
        }
        if (!Yii::$app->session['currency']) {
            Yii::$app->session['currency'] = $this->defaultCurrency;
        }
        $this->siteCurrency = Yii::$app->session['currency'];
    }
    
    public function listCurrencies()
    {
        $result = [];
        foreach ($this->currencies as $item) {
            $result[$item['code']] = $item['code'];
        }
        return $result;
    }
    
    public function showPrice($offer, $symbol = true)
    {
        if ($offer['currency_code'] == $this->siteCurrency['code']) {
            $price = $offer['price'];
        } else {
            foreach ($this->currencies as $item) {
                if ($item['code'] == $offer['currency_code']) {
                    $rate = $item['rate'];
                }
            }
            $price = ($offer['price'] * $rate) / $this->siteCurrency['rate'];
        }
                
        if ($symbol === true) {
            return number_format($price, $this->siteCurrency['decimal_places'], '.', '') . '&nbsp;' . $this->siteCurrency['symbol'];
        } else {
            //return round($price, $this->siteCurrency['decimal_places']);
            return number_format($price, $this->siteCurrency['decimal_places'], '.', '');
        }
    }
    
    public function showOldPrice($offer, $symbol = true)
    {
        if ($offer['currency_code'] == $this->siteCurrency['code']) {
            $price = $offer['old_price'];
        } else {
            foreach ($this->currencies as $item) {
                if ($item['code'] == $offer['currency_code']) {
                    $rate = $item['rate'];
                }
            }
            $price = ($offer['old_price'] * $rate) / $this->siteCurrency['rate'];
        }
                
        if ($symbol === true) {
            return number_format($price, $this->siteCurrency['decimal_places'], '.', '') . '&nbsp;' . $this->siteCurrency['symbol'];
        } else {
            return round($price, $this->siteCurrency['decimal_places']);
        }
    }
}

Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы