diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..130bfa6 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,6 @@ +Процесс разработки. +============== + +1.0.0 +----------------- + * первая версия магазина \ No newline at end of file diff --git a/Module.php b/Module.php index 9e06280..50eceb1 100644 --- a/Module.php +++ b/Module.php @@ -23,7 +23,7 @@ class Module extends CmsModule protected function _descriptor() { return array_merge(parent::_descriptor(), [ - "version" => "0.0.1-dev", + "version" => "1.0.0", "name" => "Модуль интернет магазин", ]); } diff --git a/_vendor/YiiApplication.php b/_vendor/YiiApplication.php new file mode 100644 index 0000000..5e1b3b9 --- /dev/null +++ b/_vendor/YiiApplication.php @@ -0,0 +1,15 @@ + + * @link http://skeeks.com/ + * @copyright 2010 SkeekS (СкикС) + * @date 02.04.2015 + */ +namespace yii\web; +use skeeks\modules\cms\shop\components\shop\Shop; + +/** + * @property Shop $shop + */ +class Application +{} \ No newline at end of file diff --git a/assets/ShopAsset.php b/assets/ShopAsset.php new file mode 100644 index 0000000..4b62237 --- /dev/null +++ b/assets/ShopAsset.php @@ -0,0 +1,24 @@ + + * @link http://skeeks.com/ + * @copyright 2010 SkeekS (СкикС) + * @date 01.04.2015 + */ +namespace skeeks\modules\cms\shop\assets; + +/** + * Class Asset + * @package skeeks\modules\cms\shop\assets + */ +class ShopAsset extends Asset +{ + public $css = []; + public $js = [ + 'classes/Shop.js', + 'classes/Cart.js' + ]; + public $depends = [ + '\skeeks\sx\assets\Core', + ]; +} diff --git a/assets/classes/Cart.js b/assets/classes/Cart.js new file mode 100644 index 0000000..ece5ac1 --- /dev/null +++ b/assets/classes/Cart.js @@ -0,0 +1,112 @@ +/*! + * @author Semenov Alexander + * @link http://skeeks.com/ + * @copyright 2010 SkeekS (СкикС) + * @date 03.04.2015 + */ +(function(sx, $, _) +{ + sx.createNamespace('classes.shop', sx); + + /** + * Объект корзины + * Слушает события магазина + * Умеет обновляться update(); + * + * @events: + * update + * beforeUpdate + */ + sx.classes.shop._Cart = sx.classes.Component.extend({ + + construct: function (Shop, id, opts) + { + var self = this; + opts = opts || {}; + + if (!Shop instanceof sx.classes.shop._App) + { + throw new Error("Shop object not found"); + } + + this.id = String(id); + this.Shop = Shop; + this.Shop.registerCart(this); + + //this.parent.construct(opts); + this.applyParentMethod(sx.classes.Component, 'construct', [opts]); // TODO: make a workaround for magic parent calling + }, + + _init: function() + { + var self = this; + + this.Shop.bind('change', function(e, data) + { + self.update(); + }); + }, + + update: function() + { + this.trigger('beforeUpdate', { + 'Cart' : this + }); + //throw new Error("Not implemented this method"); + return this; + }, + + /** + * @returns {*|HTMLElement} + * @constructor + */ + JWrapper: function() + { + return $('#' + this.id); + } + }); + + sx.classes.shop.Cart = sx.classes.shop._Cart.extend({}); + + /** + * Корзина которая перезагружается Pjax + * + * @options: + * delay - задержка обновления контейнера + */ + sx.classes.shop.CartPjax = sx.classes.shop.Cart.extend({ + + _init: function() + { + this.applyParentMethod(sx.classes.shop.Cart, '_init', []); + + var self = this; + + self.JWrapper().on('pjax:complete', function() { + self.trigger('update', { + 'Cart' : this + }); + }); + }, + + /** + * @returns {sx.classes.shop.CartPjax} + */ + update: function() + { + var self = this; + + this.trigger('beforeUpdate', { + 'Cart' : this + }); + + _.delay(function() + { + $.pjax.reload(self.JWrapper()); + }, Number(this.get('delay', 0)) ); + + return this; + }, + }); + +})(sx, sx.$, sx._); \ No newline at end of file diff --git a/assets/classes/Shop.js b/assets/classes/Shop.js new file mode 100644 index 0000000..8e5b587 --- /dev/null +++ b/assets/classes/Shop.js @@ -0,0 +1,151 @@ +/*! + * @author Semenov Alexander + * @link http://skeeks.com/ + * @copyright 2010 SkeekS (СкикС) + * @date 03.04.2015 + */ +(function(sx, $, _) +{ + sx.createNamespace('classes.shop', sx); + + /** + * @events: + * beforeAddProduct + * addProduct + * + * beforeRemoveBasket + * removeBasket + * + * beforeUpdateBasket + * updateBasket + * + * change + * + */ + sx.classes.shop._App = sx.classes.Component.extend({ + + _init: function() + { + var self = this; + this.carts = []; + + this.bind('removeBasket addProduct updateBasket', function(e, data) + { + self.trigger('change', { + 'Shop' : this + }); + }); + }, + + /** + * @returns {sx.classes.AjaxQuery} + */ + ajaxQuery: function() + { + return sx.ajax.preparePostQuery('/'); + }, + + /** + * @param Cart + */ + registerCart: function(Cart) + { + if (!Cart instanceof sx.classes.shop._Cart) + { + throw new Error("Cart object must be instanceof sx.classes.shop._Cart"); + } + + this.carts.push(Cart); + }, + + /** + * Добавление продукта в корзину + * @param product_id + * @param quantity + */ + addProduct: function(product_id, quantity) + { + var self = this; + + this.trigger('beforeAddProduct', { + 'product_id' : product_id, + 'quantity' : quantity, + }); + + var ajax = this.ajaxQuery().setUrl(this.get('backend-add-product')); + + ajax.setData({ + 'product_id' : Number(product_id), + 'quantity' : Number(quantity), + }); + + ajax.onSuccess(function(e, data) + { + self.trigger('addProduct', { + 'product_id' : product_id, + 'quantity' : quantity, + 'response' : data.response, + }); + }); + + ajax.execute(); + }, + + + removeBasket: function(basket_id) + { + var self = this; + + this.trigger('beforeRemoveBasket', { + 'basket_id' : basket_id, + }); + + var ajax = this.ajaxQuery().setUrl(this.get('backend-remove-basket')); + + ajax.setData({ + 'basket_id' : Number(basket_id), + }); + + ajax.onSuccess(function(e, data) + { + self.trigger('removeBasket', { + 'basket_id' : basket_id, + 'response' : data.response, + }); + }); + + ajax.execute(); + }, + + updateBasket: function(basket_id, quantity) + { + var self = this; + + this.trigger('beforeUpdateBasket', { + 'basket_id' : basket_id, + 'quantity' : quantity, + }); + + var ajax = this.ajaxQuery().setUrl(this.get('backend-update-basket')); + + ajax.setData({ + 'basket_id' : Number(basket_id), + 'quantity' : Number(quantity), + }); + + ajax.onSuccess(function(e, data) + { + self.trigger('updateBasket', { + 'basket_id' : basket_id, + 'quantity' : quantity, + 'response' : data.response, + }); + }); + + ajax.execute(); + }, + }); + + sx.classes.shop.App = sx.classes.shop._App.extend({}); + +})(sx, sx.$, sx._); \ No newline at end of file diff --git a/components/Cart.php b/components/Cart.php new file mode 100644 index 0000000..d541ced --- /dev/null +++ b/components/Cart.php @@ -0,0 +1,212 @@ + + * @link http://skeeks.com/ + * @copyright 2010 SkeekS (СкикС) + * @date 02.04.2015 + */ +namespace skeeks\modules\cms\shop\components; +use skeeks\cms\helpers\UrlHelper; +use skeeks\modules\cms\shop\models\ShopBasket; +use skeeks\modules\cms\shop\models\ShopFuser; +use yii\helpers\ArrayHelper; + +/** + * Class Shop + * @package skeeks\modules\cms\shop\components + */ +class Cart extends \skeeks\cms\base\Component +{ + /** + * @var ShopFuser + */ + public $shopFuser = null; + + public $sessionFuserName = 'sx_fuser'; + + public function init() + { + parent::init(); + + if (\Yii::$app->user->isGuest) + { + //Проверка сессии + if (\Yii::$app->getSession()->offsetExists($this->sessionFuserName)) + { + $fuserId = \Yii::$app->getSession()->get($this->sessionFuserName); + $shopFuser = ShopFuser::find()->where(['id' => $fuserId])->one(); + //Поиск юзера + if ($shopFuser) + { + $this->shopFuser = $shopFuser; + } + } + } else + { + $this->shopFuser = ShopFuser::fetchByUser(\Yii::$app->cms->getAuthUser()); + + //Если у авторизовнного пользоывателя уже есть пользователь корзины + if ($this->shopFuser) + { + //Проверка сессии, а было ли чего то в корзине + if (\Yii::$app->getSession()->offsetExists($this->sessionFuserName)) + { + $fuserId = \Yii::$app->getSession()->get($this->sessionFuserName); + $shopFuser = ShopFuser::find()->where(['id' => $fuserId])->one(); + + //Поиск юзера + /** + * @var $shopFuser ShopFuser + */ + if ($shopFuser) + { + $this->shopFuser->addBaskets($shopFuser->getShopBaskets()->all()); + } + + \Yii::$app->getSession()->remove($this->sessionFuserName); + } + } else + { + //Проверка сессии, а было ли чего то в корзине + if (\Yii::$app->getSession()->offsetExists($this->sessionFuserName)) + { + $fuserId = \Yii::$app->getSession()->get($this->sessionFuserName); + $shopFuser = ShopFuser::find()->where(['id' => $fuserId])->one(); + //Поиск юзера + /** + * @var $shopFuser ShopFuser + */ + if ($shopFuser) + { + $shopFuser->user_id = \Yii::$app->cms->getAuthUser()->id; + $shopFuser->save(); + } + + \Yii::$app->getSession()->remove($this->sessionFuserName); + } + } + + } + } + + + /** + * Загрузить и создать пользователя корзины. Если нет. + * + * @return $this + */ + public function loadShopFuser() + { + if ($this->shopFuser) + { + return $this; + } + + if (\Yii::$app->user->isGuest) + { + $shopFuser = new ShopFuser([ + 'user_id' => \Yii::$app->cms->getAuthUser()->id + ]); + + $shopFuser->save(); + + \Yii::$app->getSession()->set($this->sessionFuserName, $shopFuser->id); + $this->shopFuser = $shopFuser; + } else + { + $shopFuser = new ShopFuser([ + 'user_id' => \Yii::$app->cms->getAuthUser()->id + ]); + + $shopFuser->save(); + + $this->shopFuser = $shopFuser; + } + + return $this; + } + + /** + * @return array|\yii\db\ActiveQuery + */ + public function findShopBaskets() + { + if (!$this->shopFuser) + { + return null; + } + + return $this->shopFuser->getShopBaskets()->where(['order_id' => null]); + } + + /** + * @return ShopBasket[] + */ + public function getShopBaskets() + { + if (!$this->shopFuser) + { + return []; + } + + return $this->findShopBaskets()->all(); + } + + /** + * Количество позиций в коризне + * + * @return int + */ + public function countBaskets() + { + if ($this->getShopBaskets()) + { + return count($this->getShopBaskets()); + } + + return 0; + } + + + /** + * @return int + */ + public function countProducts() + { + $result = 0; + + if ($baskets = $this->getShopBaskets()) + { + foreach ($baskets as $basket) + { + $result = $result + $basket->quantity; + } + } + + return $result; + } + /** + * Стоимость корзины. + * + * @return \skeeks\modules\cms\money\Money + */ + public function cost() + { + $money = \Yii::$app->money->newMoney(); + + if (!$this->countBaskets()) + { + return $money; + } + + if ($baskets = $this->getShopBaskets()) + { + foreach ($baskets as $basket) + { + $money = $money->add($basket->price()); + } + } + + return $money; + } +} \ No newline at end of file diff --git a/components/shop/Shop.php b/components/shop/Shop.php new file mode 100644 index 0000000..20febc7 --- /dev/null +++ b/components/shop/Shop.php @@ -0,0 +1,96 @@ + + * @link http://skeeks.com/ + * @copyright 2010 SkeekS (СкикС) + * @date 02.04.2015 + */ +namespace skeeks\modules\cms\shop\components\shop; +use skeeks\cms\helpers\UrlHelper; +use skeeks\modules\cms\shop\components\Cart; +use skeeks\modules\cms\shop\models\ShopPersonType; +use yii\helpers\ArrayHelper; + +/** + * Class Shop + * @package skeeks\modules\cms\shop\components + */ +class Shop extends \skeeks\cms\base\Component +{ + /** + * @var string E-Mail администратора сайта (отправитель по умолчанию). + */ + public $email = 'admin@skeeks.com'; + + /** + * @var int + */ + public $allowBuyWhithoutQuantity = 1; + + /** + * @var Cart + */ + public $cart = null; + + public function init() + { + parent::init(); + $this->cart = new Cart(); + } + /** + * Можно задать название и описание компонента + * @return array + */ + static public function getDescriptorConfig() + { + return + [ + 'name' => 'Интернет-магазин', + + ]; + } + + public function rules() + { + return ArrayHelper::merge(parent::rules(), [ + [['email'], 'email'], + [['allowBuyWhithoutQuantity'], 'integer'], + ]); + } + + public function attributeLabels() + { + return ArrayHelper::merge(parent::attributeLabels(), [ + 'email' => 'Email отдела продаж', + 'allowBuyWhithoutQuantity' => 'Разрешить покупку при отсутствии товара', + ]); + } + + + /** + * Опции для js. + * + * @return array + */ + public function getShopClientOptions() + { + return [ + 'backend-add-product' => UrlHelper::construct('shop/basket/add-product')->toString(), + 'backend-remove-basket' => UrlHelper::construct('shop/basket/remove-basket')->toString(), + 'backend-update-basket' => UrlHelper::construct('shop/basket/update-basket')->toString(), + 'backend-clear' => UrlHelper::construct('shop/basket/clear-all')->toString() + ]; + } + + /** + * Активные типы платежных пользователей. + * + * @return ShopPersonType[] + */ + public function getPersonTypes() + { + return ShopPersonType::find()->where(['active' => 1])->all(); + } + + +} \ No newline at end of file diff --git a/components/shop/_form.php b/components/shop/_form.php new file mode 100644 index 0000000..4bcbd94 --- /dev/null +++ b/components/shop/_form.php @@ -0,0 +1,31 @@ + + * @link http://skeeks.com/ + * @copyright 2010 SkeekS (СкикС) + * @date 27.03.2015 + */ +use yii\helpers\Html; +use skeeks\cms\widgets\base\hasModelsSmart\ActiveForm; + +/* @var $this yii\web\View */ +/* @var $model \skeeks\cms\models\WidgetConfig */ +?> + + + +fieldSet('Основное'); ?> + field($model, 'email')->textInput()->hint(''); ?> + field($model, 'allowBuyWhithoutQuantity')->widget( + \skeeks\widget\chosen\Chosen::className(), + [ + 'items' => \Yii::$app->formatter->booleanFormat, + 'allowDeselect' => false + ] + ); ?> +fieldSetEnd(); ?> + +buttonsCreateOrUpdate($model); ?> + + + diff --git a/config/admin/menu.php b/config/admin/menu.php index d5d3020..ec9e646 100644 --- a/config/admin/menu.php +++ b/config/admin/menu.php @@ -6,7 +6,7 @@ * @date 12.03.2015 */ return [ - 'catalog' => + 'shop' => [ 'label' => 'Интернет магазин', 'priority' => 0, @@ -16,8 +16,32 @@ return [ 'items' => [ [ + "label" => "Типы плательщиков", + "url" => ["shop/admin-shop-person-type"], + "img" => ['\skeeks\modules\cms\shop\assets\Asset', 'icons/shop.png'] + ], + + [ + "label" => "Платежные системы", + "url" => ["shop/admin-shop-pay-system"], + "img" => ['\skeeks\modules\cms\shop\assets\Asset', 'icons/shop.png'] + ], + + [ + "label" => "Службы доставки", + "url" => ["shop/admin-shop-delivery"], + "img" => ['\skeeks\modules\cms\shop\assets\Asset', 'icons/shop.png'] + ], + + [ + "label" => "Статусы заказов", + "url" => ["shop/admin-shop-order-status"], + "img" => ['\skeeks\modules\cms\shop\assets\Asset', 'icons/shop.png'] + ], + + [ "label" => "Заказы", - "url" => ["shop/admin-order"], + "url" => ["shop/admin-shop-order"], "img" => ['\skeeks\modules\cms\shop\assets\Asset', 'icons/shop.png'] ], diff --git a/config/main.php b/config/main.php index a942f3a..b29c116 100644 --- a/config/main.php +++ b/config/main.php @@ -14,6 +14,11 @@ return [ ] ], + 'shop' => + [ + 'class' => 'skeeks\modules\cms\shop\components\shop\Shop' + ], + "registeredWidgets" => [ 'components' => [ /*'skeeks\modules\cms\catalog\widgets\products\Products' => diff --git a/controllers/AdminShopDeliveryController.php b/controllers/AdminShopDeliveryController.php new file mode 100644 index 0000000..2cdc19e --- /dev/null +++ b/controllers/AdminShopDeliveryController.php @@ -0,0 +1,31 @@ + + * @link http://skeeks.com/ + * @copyright 2010 SkeekS (СкикС) + * @date 02.04.2015 + */ +namespace skeeks\modules\cms\shop\controllers; +use skeeks\cms\modules\admin\controllers\AdminModelEditorSmartController; +use skeeks\modules\cms\shop\models\ShopDelivery; +use skeeks\modules\cms\shop\models\ShopPaySystem; +use skeeks\modules\cms\shop\models\ShopPersonType; + +/** + * Class AdminShopPaySystemController + * @package skeeks\modules\cms\shop\controllers + */ +class AdminShopDeliveryController extends AdminModelEditorSmartController +{ + public function init() + { + $this->_label = "Службы доставки"; + $this->_modelShowAttribute = "name"; + $this->_modelClassName = ShopDelivery::className(); + + $this->modelValidate = true; + $this->enableScenarios = true; + + parent::init(); + } +} \ No newline at end of file diff --git a/controllers/AdminShopOrderController.php b/controllers/AdminShopOrderController.php new file mode 100644 index 0000000..4c50b34 --- /dev/null +++ b/controllers/AdminShopOrderController.php @@ -0,0 +1,32 @@ + + * @link http://skeeks.com/ + * @copyright 2010 SkeekS (СкикС) + * @date 02.04.2015 + */ +namespace skeeks\modules\cms\shop\controllers; +use skeeks\cms\modules\admin\controllers\AdminModelEditorSmartController; +use skeeks\modules\cms\shop\models\ShopDelivery; +use skeeks\modules\cms\shop\models\ShopOrder; +use skeeks\modules\cms\shop\models\ShopPaySystem; +use skeeks\modules\cms\shop\models\ShopPersonType; + +/** + * Class AdminShopPaySystemController + * @package skeeks\modules\cms\shop\controllers + */ +class AdminShopOrderController extends AdminModelEditorSmartController +{ + public function init() + { + $this->_label = "Заказы"; + $this->_modelShowAttribute = "id"; + $this->_modelClassName = ShopOrder::className(); + + $this->modelValidate = true; + $this->enableScenarios = true; + + parent::init(); + } +} \ No newline at end of file diff --git a/controllers/AdminShopOrderStatusController.php b/controllers/AdminShopOrderStatusController.php new file mode 100644 index 0000000..fc27987 --- /dev/null +++ b/controllers/AdminShopOrderStatusController.php @@ -0,0 +1,33 @@ + + * @link http://skeeks.com/ + * @copyright 2010 SkeekS (СкикС) + * @date 02.04.2015 + */ +namespace skeeks\modules\cms\shop\controllers; +use skeeks\cms\modules\admin\controllers\AdminModelEditorSmartController; +use skeeks\modules\cms\shop\models\ShopDelivery; +use skeeks\modules\cms\shop\models\ShopOrder; +use skeeks\modules\cms\shop\models\ShopOrderStatus; +use skeeks\modules\cms\shop\models\ShopPaySystem; +use skeeks\modules\cms\shop\models\ShopPersonType; + +/** + * Class AdminShopPaySystemController + * @package skeeks\modules\cms\shop\controllers + */ +class AdminShopOrderStatusController extends AdminModelEditorSmartController +{ + public function init() + { + $this->_label = "Статусы заказов"; + $this->_modelShowAttribute = "name"; + $this->_modelClassName = ShopOrderStatus::className(); + + $this->modelValidate = true; + $this->enableScenarios = true; + + parent::init(); + } +} \ No newline at end of file diff --git a/controllers/AdminShopPaySystemController.php b/controllers/AdminShopPaySystemController.php new file mode 100644 index 0000000..364dcfe --- /dev/null +++ b/controllers/AdminShopPaySystemController.php @@ -0,0 +1,30 @@ + + * @link http://skeeks.com/ + * @copyright 2010 SkeekS (СкикС) + * @date 02.04.2015 + */ +namespace skeeks\modules\cms\shop\controllers; +use skeeks\cms\modules\admin\controllers\AdminModelEditorSmartController; +use skeeks\modules\cms\shop\models\ShopPaySystem; +use skeeks\modules\cms\shop\models\ShopPersonType; + +/** + * Class AdminShopPaySystemController + * @package skeeks\modules\cms\shop\controllers + */ +class AdminShopPaySystemController extends AdminModelEditorSmartController +{ + public function init() + { + $this->_label = "Платежные системы"; + $this->_modelShowAttribute = "name"; + $this->_modelClassName = ShopPaySystem::className(); + + $this->modelValidate = true; + $this->enableScenarios = true; + + parent::init(); + } +} \ No newline at end of file diff --git a/controllers/AdminShopPersonTypeController.php b/controllers/AdminShopPersonTypeController.php new file mode 100644 index 0000000..95a61c0 --- /dev/null +++ b/controllers/AdminShopPersonTypeController.php @@ -0,0 +1,29 @@ + + * @link http://skeeks.com/ + * @copyright 2010 SkeekS (СкикС) + * @date 02.04.2015 + */ +namespace skeeks\modules\cms\shop\controllers; +use skeeks\cms\modules\admin\controllers\AdminModelEditorSmartController; +use skeeks\modules\cms\shop\models\ShopPersonType; + +/** + * Class AdminShopPersonTypeController + * @package skeeks\modules\cms\shop\controllers + */ +class AdminShopPersonTypeController extends AdminModelEditorSmartController +{ + public function init() + { + $this->_label = "Типы плательщиков"; + $this->_modelShowAttribute = "name"; + $this->_modelClassName = ShopPersonType::className(); + + $this->modelValidate = true; + $this->enableScenarios = true; + + parent::init(); + } +} \ No newline at end of file diff --git a/controllers/BackendController.php b/controllers/BackendController.php new file mode 100644 index 0000000..4172941 --- /dev/null +++ b/controllers/BackendController.php @@ -0,0 +1,222 @@ + + * @link http://skeeks.com/ + * @copyright 2010 SkeekS (СкикС) + * @date 15.03.2015 + */ +namespace skeeks\modules\cms\shop\controllers; +use skeeks\cms\base\Controller; +use skeeks\cms\helpers\RequestResponse; +use skeeks\cms\helpers\UrlHelper; +use skeeks\cms\models\forms\SignupForm; +use skeeks\modules\cms\form\models\Form; +use skeeks\modules\cms\form\models\FormField; +use skeeks\modules\cms\form\models\FormSendMessage; +use skeeks\modules\cms\shop\models\ShopOrder; +use skeeks\modules\cms\shop\models\ShopPaySystem; +use skeeks\modules\cms\shop\models\ShopPersonType; +use yii\base\Exception; +use yii\base\UserException; +use yii\filters\VerbFilter; +use yii\helpers\ArrayHelper; +use yii\web\Response; +use yii\widgets\ActiveForm; + +/** + * Class BackendController + * @package skeeks\modules\cms\form\controllers + */ +class BackendController extends Controller +{ + /** + * @return array + */ + public function behaviors() + { + return ArrayHelper::merge(parent::behaviors(), [ + + 'verbs' => [ + 'class' => VerbFilter::className(), + 'actions' => [ + 'validate' => ['post'], + 'submit' => ['post'], + ], + ], + ]); + } + + + /** + * Процесс отправки формы + * @return array + */ + public function actionCreateOrder() + { + if (\Yii::$app->request->isAjax && !\Yii::$app->request->isPjax) + { + \Yii::$app->response->format = Response::FORMAT_JSON; + + $rr = new RequestResponse(); + + try + { + if (!$formId = \Yii::$app->request->post(Form::FROM_PARAM_ID_NAME)) + { + throw new UserException('Не найден параметр формы'); + } + + /** + * @var $modelForm Form + */ + $modelForm = Form::find()->where(['id' => $formId])->one(); + $model = $modelForm->createValidateModel(); + + if ($model->load(\Yii::$app->request->post()) && $model->validate()) + { + $shopPersonTypeId = (int) \Yii::$app->request->post('shopPersonType'); + if (!$shopPersonTypeId) + { + throw new UserException('Не передан параметр тип плательщика'); + } + + $shopPersonType = ShopPersonType::findOne($shopPersonTypeId); + if (!$shopPersonType) + { + throw new UserException('Не указан плательщик'); + } + + $shopPaySystemId = (int) \Yii::$app->request->post('shopPaySystemId'); + $shopPaySystem = ShopPaySystem::findOne($shopPaySystemId); + if (!$shopPaySystem) + { + throw new UserException('Не указана система оплаты'); + } + + if (!$model->email) + { + throw new UserException('Не указан email.'); + } + + if (!\Yii::$app->shop->cart->countProducts()) + { + throw new UserException('Нет товаров в корзине.'); + } + + + //Пользователь авторизован или нет. + if (\Yii::$app->user->isGuest) + { + $registerForm = new SignupForm(); + $registerForm->setScenario(SignupForm::SCENARION_ONLYEMAIL); + $registerForm->email = $model->email; + + $user = $registerForm->signup(); + + //Проверим может что то можно заполнить в профиле пользователя. + if ($user) + { + foreach ($model->attributeValues() as $code => $value) + { + if ($user->hasAttribute($code)) + { + $user->{$code} = $value; + } + } + + $user->save(false); + } else + { + throw new UserException("Не удалось зарегистрировать пользователя, возможно пользователь с указанным email адресом уже зарегистрирован."); + } + + //Авторизация пользователя + \Yii::$app->user->login($user, 0); + + } else + { + $user = \Yii::$app->cms->getAuthUser(); + } + + $cost = \Yii::$app->shop->cart->cost(); + $currency = $cost->getCurrency(); + + //Создание нового заказа + $shopOrder = new ShopOrder([ + 'person_type_id' => $shopPersonType->id, + 'price' => $cost->getAmount() / $currency->getSubUnit(), + 'currency' => (string) $currency, + 'user_id' => $user->id, + 'pay_system_id' => $shopPaySystem->id, + 'data' => $model->attributeLabelsValues(), + ]); + + if (!$shopOrder->save()) + { + $result = []; + $errors = $shopOrder->getErrors(); + foreach ($errors as $errorData) + { + $result[] = implode(', ', $errorData); + } + + throw new UserException('Не получилось оформить заказ: ' . implode('; ', $result)); + } + + //Переписать позиции корзины + if ($shopBaskets = \Yii::$app->shop->cart->getShopBaskets()) + { + foreach ($shopBaskets as $shopBasket) + { + $shopBasket->order_id = $shopOrder->id; + $shopBasket->save(); + } + } + + //Отправка сообщения с формы + //Все проверки прошли, формируем модель отправленного сообщения и сохраняем ее + $modelFormSendMessage = new FormSendMessage(); + + $modelFormSendMessage->data_values = $model->attributeValues(); + $modelFormSendMessage->data_labels = $model->attributeLabels(); + + $modelFormSendMessage->page_url = \Yii::$app->request->referrer; + $modelFormSendMessage->form_id = $formId; + + if ($modelFormSendMessage->save()) + { + $modelFormSendMessage->notify(); + + $rr->success = true; + $rr->message = 'Успешно отправлена'; + + } else + { + $rr->message = 'Не удалось сохранить сообщение в базу'; + } + + + $rr->success = true; + $rr->message = 'Заказ успешно создан'; + \Yii::$app->session->setFlash("success", 'Заказ успешно создан'); + + return $this->redirect( UrlHelper::construct('shop/order/view', [ + 'id' => $shopOrder->id, + 'sx-new' => '1' + ])->toString() ); + + } else + { + $rr->message = 'Форма заполнена неправильно'; + } + + } catch(\Exception $e) + { + $rr->message = $e->getMessage(); + } + + return (array) $rr; + + } + } +} \ No newline at end of file diff --git a/controllers/BasketController.php b/controllers/BasketController.php new file mode 100644 index 0000000..365ab81 --- /dev/null +++ b/controllers/BasketController.php @@ -0,0 +1,143 @@ + + * @link http://skeeks.com/ + * @copyright 2010 SkeekS (СкикС) + * @date 03.04.2015 + */ +namespace skeeks\modules\cms\shop\controllers; + +use skeeks\cms\base\Controller; +use skeeks\cms\helpers\RequestResponse; +use skeeks\modules\cms\shop\models\ShopBasket; +use skeeks\modules\cms\shop\models\ShopFuser; +use skeeks\modules\cms\catalog\models\Product; +/** + * Class ShopController + * @package skeeks\modules\cms\shop\controllers + */ +class BasketController extends Controller +{ + /** + * Добавление продукта в корзину. + * + * @return array|\yii\web\Response + */ + public function actionAddProduct() + { + $rr = new RequestResponse(); + + if ($rr->isRequestAjaxPost()) + { + $product_id = \Yii::$app->request->post('product_id'); + $quantity = \Yii::$app->request->post('quantity'); + + $product = Product::find()->where(['id' => $product_id])->one(); + + if (!$product) + { + $rr->message = 'Товар не найден, возможно его только что удалили.'; + return (array) $rr; + } + + \Yii::$app->shop->cart->loadShopFuser(); + + $shopBasket = ShopBasket::find()->where([ + 'fuser_id' => \Yii::$app->shop->cart->shopFuser->id, + 'product_id' => $product_id, + 'order_id' => null, + ])->one(); + + if (!$shopBasket) + { + $shopBasket = new ShopBasket([ + 'fuser_id' => \Yii::$app->shop->cart->shopFuser->id, + 'name' => $product->name, + 'product_id' => $product_id, + 'quantity' => 0, + ]); + } + + $shopBasket->quantity = $shopBasket->quantity + $quantity; + $shopBasket->save(); + + $shopBasket->recalculate(); + + $rr->success = true; + $rr->message = 'Позиция добавлена в корзину'; + + return (array) $rr; + } else + { + return $this->goBack(); + } + } + + public function actionRemoveBasket() + { + $rr = new RequestResponse(); + + if ($rr->isRequestAjaxPost()) + { + $basket_id = \Yii::$app->request->post('basket_id'); + + $shopBasket = ShopBasket::find()->where(['id' => $basket_id ])->one(); + if ($shopBasket) + { + if ($shopBasket->delete()) + { + $rr->success = true; + $rr->message = 'Позиция успешно удалена'; + } + } + + + return (array) $rr; + } else + { + return $this->goBack(); + } + } + + public function actionUpdateBasket() + { + $rr = new RequestResponse(); + + if ($rr->isRequestAjaxPost()) + { + $basket_id = (int) \Yii::$app->request->post('basket_id'); + $quantity = (int) \Yii::$app->request->post('quantity'); + + $shopBasket = ShopBasket::find()->where(['id' => $basket_id ])->one(); + if ($shopBasket) + { + if ($quantity > 0) + { + $shopBasket->quantity = $quantity; + if ($shopBasket->save()) + { + $rr->success = true; + $rr->message = 'Позиция успешно обновлена'; + + $shopBasket->recalculate(); + } + + } else + { + if ($shopBasket->delete()) + { + $rr->success = true; + $rr->message = 'Позиция успешно удалена'; + } + } + + } + + + return (array) $rr; + } else + { + return $this->goBack(); + } + } +} \ No newline at end of file diff --git a/controllers/CartController.php b/controllers/CartController.php new file mode 100644 index 0000000..f439089 --- /dev/null +++ b/controllers/CartController.php @@ -0,0 +1,30 @@ + + * @link http://skeeks.com/ + * @copyright 2010 SkeekS (СкикС) + * @date 03.04.2015 + */ +namespace skeeks\modules\cms\shop\controllers; + +use skeeks\cms\base\Controller; +use skeeks\cms\helpers\RequestResponse; +use skeeks\modules\cms\shop\models\ShopBasket; +use skeeks\modules\cms\shop\models\ShopFuser; +use skeeks\modules\cms\catalog\models\Product; + +/** + * Class CartController + * @package skeeks\modules\cms\shop\controllers + */ +class CartController extends Controller +{ + /** + * @return array|\yii\web\Response + */ + public function actionIndex() + { + //\Yii::$app->shop->cart; + return $this->render('index'); + } +} \ No newline at end of file diff --git a/controllers/OrderController.php b/controllers/OrderController.php new file mode 100644 index 0000000..319e1c7 --- /dev/null +++ b/controllers/OrderController.php @@ -0,0 +1,43 @@ + + * @link http://skeeks.com/ + * @copyright 2010 SkeekS (СкикС) + * @date 03.04.2015 + */ +namespace skeeks\modules\cms\shop\controllers; + +use skeeks\cms\base\Controller; +use skeeks\cms\helpers\RequestResponse; +use skeeks\modules\cms\shop\models\ShopBasket; +use skeeks\modules\cms\shop\models\ShopFuser; +use skeeks\modules\cms\catalog\models\Product; +use skeeks\modules\cms\shop\models\ShopOrder; +use yii\base\UserException; + +/** + * Class OrderController + * @package skeeks\modules\cms\shop\controllers + */ +class OrderController extends Controller +{ + /** + * @return array|\yii\web\Response + */ + public function actionView() + { + if (!$id = (int) \Yii::$app->request->get('id')) + { + throw new UserException("Заказ не найден"); + } + + if (!$shopOrder = ShopOrder::findOne($id)) + { + throw new UserException("Заказ не найден"); + } + + return $this->render('view', [ + 'model' => $shopOrder + ]); + } +} \ No newline at end of file diff --git a/migrations/m150401_100558_create_table__shop_fuser.php b/migrations/m150401_100558_create_table__shop_fuser.php new file mode 100644 index 0000000..4368c52 --- /dev/null +++ b/migrations/m150401_100558_create_table__shop_fuser.php @@ -0,0 +1,72 @@ + + * @link http://skeeks.com/ + * @copyright 2010 SkeekS (СкикС) + * @date 01.04.2015 + */ +use yii\db\Schema; +use yii\db\Migration; + +class m150401_100558_create_table__shop_fuser extends Migration +{ + public function safeUp() + { + $tableExist = $this->db->getTableSchema("{{%shop_fuser}}", true); + if ($tableExist) + { + return true; + } + + $tableOptions = null; + if ($this->db->driverName === 'mysql') { + $tableOptions = 'CHARACTER SET utf8 COLLATE utf8_general_ci ENGINE=InnoDB'; + } + + $this->createTable("{{%shop_fuser}}", [ + 'id' => Schema::TYPE_PK, + + 'created_by' => Schema::TYPE_INTEGER . ' NULL', + 'updated_by' => Schema::TYPE_INTEGER . ' NULL', + + 'created_at' => Schema::TYPE_INTEGER . ' NULL', + 'updated_at' => Schema::TYPE_INTEGER . ' NULL', + + 'user_id' => Schema::TYPE_INTEGER . ' NULL', + + ], $tableOptions); + + $this->execute("ALTER TABLE {{%shop_fuser}} ADD INDEX(updated_by);"); + $this->execute("ALTER TABLE {{%shop_fuser}} ADD INDEX(created_by);"); + + $this->execute("ALTER TABLE {{%shop_fuser}} ADD INDEX(created_at);"); + $this->execute("ALTER TABLE {{%shop_fuser}} ADD INDEX(updated_at);"); + $this->execute("ALTER TABLE {{%shop_fuser}} ADD UNIQUE(user_id);"); + + $this->execute("ALTER TABLE {{%shop_fuser}} COMMENT = 'Пользователи для корзины';"); + + $this->addForeignKey( + 'shop_fuser_created_by', "{{%shop_fuser}}", + 'created_by', '{{%cms_user}}', 'id', 'SET NULL', 'SET NULL' + ); + + $this->addForeignKey( + 'shop_fuser_updated_by', "{{%shop_fuser}}", + 'updated_by', '{{%cms_user}}', 'id', 'SET NULL', 'SET NULL' + ); + + $this->addForeignKey( + 'shop_fuser_user_id', "{{%shop_fuser}}", + 'user_id', '{{%cms_user}}', 'id', 'SET NULL', 'SET NULL' + ); + + } + + public function safeDown() + { + $this->dropForeignKey("shop_fuser_updated_by", "{{%shop_fuser}}"); + $this->dropForeignKey("shop_fuser_updated_by", "{{%shop_fuser}}"); + + $this->dropTable("{{%shop_fuser}}"); + } +} diff --git a/migrations/m150401_100559_create_table__shop_order_status.php b/migrations/m150401_100559_create_table__shop_order_status.php new file mode 100644 index 0000000..e97738e --- /dev/null +++ b/migrations/m150401_100559_create_table__shop_order_status.php @@ -0,0 +1,76 @@ + + * @link http://skeeks.com/ + * @copyright 2010 SkeekS (СкикС) + * @date 01.04.2015 + */ +use yii\db\Schema; +use yii\db\Migration; + +class m150401_100559_create_table__shop_order_status extends Migration +{ + public function safeUp() + { + $tableExist = $this->db->getTableSchema("{{%shop_order_status}}", true); + if ($tableExist) + { + return true; + } + + $tableOptions = null; + if ($this->db->driverName === 'mysql') { + $tableOptions = 'CHARACTER SET utf8 COLLATE utf8_general_ci ENGINE=InnoDB'; + } + + $this->createTable("{{%shop_order_status}}", [ + 'id' => Schema::TYPE_PK, + + 'created_by' => Schema::TYPE_INTEGER . ' NULL', + 'updated_by' => Schema::TYPE_INTEGER . ' NULL', + + 'created_at' => Schema::TYPE_INTEGER . ' NULL', + 'updated_at' => Schema::TYPE_INTEGER . ' NULL', + + 'code' => 'char(1) NOT NULL', + + 'name' => Schema::TYPE_STRING . '(255) NOT NULL', + 'description' => Schema::TYPE_TEXT . ' NULL', + 'priority' => Schema::TYPE_INTEGER . ' NOT NULL DEFAULT 0', + + 'color' => Schema::TYPE_STRING . '(32) NULL', + + ], $tableOptions); + + $this->execute("ALTER TABLE {{%shop_order_status}} ADD INDEX(updated_by);"); + $this->execute("ALTER TABLE {{%shop_order_status}} ADD INDEX(created_by);"); + + $this->execute("ALTER TABLE {{%shop_order_status}} ADD INDEX(created_at);"); + $this->execute("ALTER TABLE {{%shop_order_status}} ADD INDEX(updated_at);"); + $this->execute("ALTER TABLE {{%shop_order_status}} ADD INDEX(name);"); + $this->execute("ALTER TABLE {{%shop_order_status}} ADD INDEX(priority);"); + $this->execute("ALTER TABLE {{%shop_order_status}} ADD INDEX(color);"); + $this->execute("ALTER TABLE {{%shop_order_status}} ADD UNIQUE(code);"); + + $this->execute("ALTER TABLE {{%shop_order_status}} COMMENT = 'Статусы заказов';"); + + $this->addForeignKey( + 'shop_order_status_created_by', "{{%shop_order_status}}", + 'created_by', '{{%cms_user}}', 'id', 'SET NULL', 'SET NULL' + ); + + $this->addForeignKey( + 'shop_order_status_updated_by', "{{%shop_order_status}}", + 'updated_by', '{{%cms_user}}', 'id', 'SET NULL', 'SET NULL' + ); + + } + + public function safeDown() + { + $this->dropForeignKey("shop_order_status_updated_by", "{{%shop_order_status}}"); + $this->dropForeignKey("shop_order_status_updated_by", "{{%shop_order_status}}"); + + $this->dropTable("{{%shop_order_status}}"); + } +} diff --git a/migrations/m150401_100601_create_table__shop_person_type.php b/migrations/m150401_100601_create_table__shop_person_type.php new file mode 100644 index 0000000..2856e0d --- /dev/null +++ b/migrations/m150401_100601_create_table__shop_person_type.php @@ -0,0 +1,78 @@ + + * @link http://skeeks.com/ + * @copyright 2010 SkeekS (СкикС) + * @date 01.04.2015 + */ +use yii\db\Schema; +use yii\db\Migration; + +class m150401_100601_create_table__shop_person_type extends Migration +{ + public function safeUp() + { + $tableExist = $this->db->getTableSchema("{{%shop_person_type}}", true); + if ($tableExist) + { + return true; + } + + $tableOptions = null; + if ($this->db->driverName === 'mysql') { + $tableOptions = 'CHARACTER SET utf8 COLLATE utf8_general_ci ENGINE=InnoDB'; + } + + $this->createTable("{{%shop_person_type}}", [ + 'id' => Schema::TYPE_PK, + + 'created_by' => Schema::TYPE_INTEGER . ' NULL', + 'updated_by' => Schema::TYPE_INTEGER . ' NULL', + + 'created_at' => Schema::TYPE_INTEGER . ' NULL', + 'updated_at' => Schema::TYPE_INTEGER . ' NULL', + + 'name' => Schema::TYPE_STRING . '(255) NOT NULL', + + 'active' => Schema::TYPE_SMALLINT . ' NOT NULL DEFAULT 1', //статус, активна некативна, удалено + 'form_id' => Schema::TYPE_INTEGER . ' NULL', //Форма с данными и полями + + ], $tableOptions); + + $this->execute("ALTER TABLE {{%shop_person_type}} ADD INDEX(updated_by);"); + $this->execute("ALTER TABLE {{%shop_person_type}} ADD INDEX(created_by);"); + + $this->execute("ALTER TABLE {{%shop_person_type}} ADD INDEX(created_at);"); + $this->execute("ALTER TABLE {{%shop_person_type}} ADD INDEX(updated_at);"); + + $this->execute("ALTER TABLE {{%shop_person_type}} ADD INDEX(active);"); + $this->execute("ALTER TABLE {{%shop_person_type}} ADD INDEX(form_id);"); + $this->execute("ALTER TABLE {{%shop_person_type}} ADD INDEX(name);"); + + $this->execute("ALTER TABLE {{%shop_person_type}} COMMENT = 'Типы плательщика';"); + + $this->addForeignKey( + 'shop_person_type_created_by', "{{%shop_person_type}}", + 'created_by', '{{%cms_user}}', 'id', 'SET NULL', 'SET NULL' + ); + + $this->addForeignKey( + 'shop_person_type_updated_by', "{{%shop_person_type}}", + 'updated_by', '{{%cms_user}}', 'id', 'SET NULL', 'SET NULL' + ); + + $this->addForeignKey( + 'shop_person_type_form_form', "{{%shop_person_type}}", + 'form_id', '{{%form_form}}', 'id', 'RESTRICT', 'RESTRICT' + ); + } + + public function safeDown() + { + $this->dropForeignKey("shop_person_type_updated_by", "{{%shop_person_type}}"); + $this->dropForeignKey("shop_person_type_updated_by", "{{%shop_person_type}}"); + $this->dropForeignKey("shop_person_type_form_form", "{{%shop_person_type}}"); + + $this->dropTable("{{%shop_person_type}}"); + } +} diff --git a/migrations/m150401_100610_create_table__shop_pay_system.php b/migrations/m150401_100610_create_table__shop_pay_system.php new file mode 100644 index 0000000..75ae613 --- /dev/null +++ b/migrations/m150401_100610_create_table__shop_pay_system.php @@ -0,0 +1,76 @@ + + * @link http://skeeks.com/ + * @copyright 2010 SkeekS (СкикС) + * @date 01.04.2015 + */ +use yii\db\Schema; +use yii\db\Migration; + +class m150401_100610_create_table__shop_pay_system extends Migration +{ + public function safeUp() + { + $tableExist = $this->db->getTableSchema("{{%shop_pay_system}}", true); + if ($tableExist) + { + return true; + } + + $tableOptions = null; + if ($this->db->driverName === 'mysql') { + $tableOptions = 'CHARACTER SET utf8 COLLATE utf8_general_ci ENGINE=InnoDB'; + } + + $this->createTable("{{%shop_pay_system}}", [ + 'id' => Schema::TYPE_PK, + + 'created_by' => Schema::TYPE_INTEGER . ' NULL', + 'updated_by' => Schema::TYPE_INTEGER . ' NULL', + + 'created_at' => Schema::TYPE_INTEGER . ' NULL', + 'updated_at' => Schema::TYPE_INTEGER . ' NULL', + + 'currency' => Schema::TYPE_STRING. '(3) DEFAULT "RUB"', + + 'name' => Schema::TYPE_STRING . '(255) NOT NULL', + 'description' => Schema::TYPE_TEXT . ' NULL', + + 'active' => Schema::TYPE_SMALLINT . ' NOT NULL DEFAULT 1', + + + ], $tableOptions); + + $this->execute("ALTER TABLE {{%shop_pay_system}} ADD INDEX(updated_by);"); + $this->execute("ALTER TABLE {{%shop_pay_system}} ADD INDEX(created_by);"); + + $this->execute("ALTER TABLE {{%shop_pay_system}} ADD INDEX(created_at);"); + $this->execute("ALTER TABLE {{%shop_pay_system}} ADD INDEX(updated_at);"); + + $this->execute("ALTER TABLE {{%shop_pay_system}} ADD INDEX(currency);"); + $this->execute("ALTER TABLE {{%shop_pay_system}} ADD INDEX(active);"); + $this->execute("ALTER TABLE {{%shop_pay_system}} ADD INDEX(name);"); + + + $this->execute("ALTER TABLE {{%shop_pay_system}} COMMENT = 'Платежные системы';"); + + $this->addForeignKey( + 'shop_pay_system_created_by', "{{%shop_pay_system}}", + 'created_by', '{{%cms_user}}', 'id', 'SET NULL', 'SET NULL' + ); + + $this->addForeignKey( + 'shop_pay_system_updated_by', "{{%shop_pay_system}}", + 'updated_by', '{{%cms_user}}', 'id', 'SET NULL', 'SET NULL' + ); + } + + public function safeDown() + { + $this->dropForeignKey("shop_pay_system_updated_by", "{{%shop_pay_system}}"); + $this->dropForeignKey("shop_pay_system_updated_by", "{{%shop_pay_system}}"); + + $this->dropTable("{{%shop_pay_system}}"); + } +} diff --git a/migrations/m150401_100620_create_table__shop_delivery.php b/migrations/m150401_100620_create_table__shop_delivery.php new file mode 100644 index 0000000..92d4d74 --- /dev/null +++ b/migrations/m150401_100620_create_table__shop_delivery.php @@ -0,0 +1,103 @@ + + * @link http://skeeks.com/ + * @copyright 2010 SkeekS (СкикС) + * @date 01.04.2015 + */ +use yii\db\Schema; +use yii\db\Migration; + +class m150401_100620_create_table__shop_delivery extends Migration +{ + public function safeUp() + { + $tableExist = $this->db->getTableSchema("{{%shop_delivery}}", true); + if ($tableExist) + { + return true; + } + + $tableOptions = null; + if ($this->db->driverName === 'mysql') { + $tableOptions = 'CHARACTER SET utf8 COLLATE utf8_general_ci ENGINE=InnoDB'; + } + + $this->createTable("{{%shop_delivery}}", [ + 'id' => Schema::TYPE_PK, + + 'created_by' => Schema::TYPE_INTEGER . ' NULL', + 'updated_by' => Schema::TYPE_INTEGER . ' NULL', + + 'created_at' => Schema::TYPE_INTEGER . ' NULL', + 'updated_at' => Schema::TYPE_INTEGER . ' NULL', + + 'currency' => Schema::TYPE_STRING. '(3) NULL DEFAULT "RUB"', + + 'name' => Schema::TYPE_STRING . '(255) NOT NULL', + 'description' => Schema::TYPE_TEXT . ' NULL', + + 'period_from' => Schema::TYPE_INTEGER . ' NULL', + 'period_to' => Schema::TYPE_INTEGER . ' NULL', + + 'period_type' => Schema::TYPE_STRING . '(1) NULL', + + 'weight_from' => Schema::TYPE_INTEGER . ' NULL', + 'weight_to' => Schema::TYPE_INTEGER . ' NULL', + + 'order_price_from' => Schema::TYPE_DECIMAL . '(18,2) NULL', + 'order_price_to' => Schema::TYPE_DECIMAL . '(18,2) NULL', + 'order_currency' => Schema::TYPE_STRING . '(3) NULL', + + 'active' => Schema::TYPE_SMALLINT . ' NOT NULL DEFAULT 1', + + 'price' => Schema::TYPE_DECIMAL . '(18,2)', + 'currency' => Schema::TYPE_STRING. '(3) DEFAULT "RUB"', + + ], $tableOptions); + + $this->execute("ALTER TABLE {{%shop_delivery}} ADD INDEX(updated_by);"); + $this->execute("ALTER TABLE {{%shop_delivery}} ADD INDEX(created_by);"); + + $this->execute("ALTER TABLE {{%shop_delivery}} ADD INDEX(created_at);"); + $this->execute("ALTER TABLE {{%shop_delivery}} ADD INDEX(updated_at);"); + + $this->execute("ALTER TABLE {{%shop_delivery}} ADD INDEX(currency);"); + $this->execute("ALTER TABLE {{%shop_delivery}} ADD INDEX(active);"); + $this->execute("ALTER TABLE {{%shop_delivery}} ADD INDEX(name);"); + + $this->execute("ALTER TABLE {{%shop_delivery}} ADD INDEX(period_from);"); + $this->execute("ALTER TABLE {{%shop_delivery}} ADD INDEX(period_to);"); + + $this->execute("ALTER TABLE {{%shop_delivery}} ADD INDEX(weight_from);"); + $this->execute("ALTER TABLE {{%shop_delivery}} ADD INDEX(weight_to);"); + + $this->execute("ALTER TABLE {{%shop_delivery}} ADD INDEX(order_price_from);"); + $this->execute("ALTER TABLE {{%shop_delivery}} ADD INDEX(order_price_to);"); + $this->execute("ALTER TABLE {{%shop_delivery}} ADD INDEX(order_currency);"); + + $this->execute("ALTER TABLE {{%shop_delivery}} ADD INDEX(price);"); + $this->execute("ALTER TABLE {{%shop_delivery}} ADD INDEX(currency);"); + + + $this->execute("ALTER TABLE {{%shop_delivery}} COMMENT = 'Система доставки';"); + + $this->addForeignKey( + 'shop_delivery_created_by', "{{%shop_delivery}}", + 'created_by', '{{%cms_user}}', 'id', 'SET NULL', 'SET NULL' + ); + + $this->addForeignKey( + 'shop_delivery_updated_by', "{{%shop_delivery}}", + 'updated_by', '{{%cms_user}}', 'id', 'SET NULL', 'SET NULL' + ); + } + + public function safeDown() + { + $this->dropForeignKey("shop_delivery_updated_by", "{{%shop_delivery}}"); + $this->dropForeignKey("shop_delivery_updated_by", "{{%shop_delivery}}"); + + $this->dropTable("{{%shop_delivery}}"); + } +} diff --git a/migrations/m150401_110600_create_table__shop_order.php b/migrations/m150401_110600_create_table__shop_order.php new file mode 100644 index 0000000..1c30a4f --- /dev/null +++ b/migrations/m150401_110600_create_table__shop_order.php @@ -0,0 +1,174 @@ + + * @link http://skeeks.com/ + * @copyright 2010 SkeekS (СкикС) + * @date 01.04.2015 + */ +use yii\db\Schema; +use yii\db\Migration; + +class m150401_110600_create_table__shop_order extends Migration +{ + public function safeUp() + { + $tableExist = $this->db->getTableSchema("{{%shop_order}}", true); + if ($tableExist) + { + return true; + } + + $tableOptions = null; + if ($this->db->driverName === 'mysql') { + $tableOptions = 'CHARACTER SET utf8 COLLATE utf8_general_ci ENGINE=InnoDB'; + } + + $this->createTable("{{%shop_order}}", [ + 'id' => Schema::TYPE_PK, + + 'created_by' => Schema::TYPE_INTEGER . ' NULL', + 'updated_by' => Schema::TYPE_INTEGER . ' NULL', + + 'created_at' => Schema::TYPE_INTEGER . ' NULL', + 'updated_at' => Schema::TYPE_INTEGER . ' NULL', + + 'person_type_id' => Schema::TYPE_INTEGER . ' NULL', + + 'payed' => Schema::TYPE_SMALLINT . '(1) NOT NULL DEFAULT 0', + 'payed_at' => Schema::TYPE_INTEGER . ' NULL', + + 'canceled' => Schema::TYPE_SMALLINT . '(1) NOT NULL DEFAULT 0', + 'canceled_at' => Schema::TYPE_INTEGER . ' NULL', + 'reason_canceled' => Schema::TYPE_STRING . '(255) NULL', + + 'status_code' => 'char(1) NOT NULL DEFAULT "N"', + 'status_at' => Schema::TYPE_INTEGER . ' NULL', + + 'price' => Schema::TYPE_DECIMAL . '(18,2)', + 'currency' => Schema::TYPE_STRING. '(3) DEFAULT "RUB"', + + 'price_delivery' => Schema::TYPE_DECIMAL . '(18,2) NULL', + 'allow_delivery' => Schema::TYPE_SMALLINT . '(1) NOT NULL DEFAULT 0', + 'allow_delivery_at' => Schema::TYPE_INTEGER . ' NULL', + + 'discount_value' => Schema::TYPE_DECIMAL . '(18,2) NULL', + 'user_id' => Schema::TYPE_INTEGER . ' NOT NULL', + + 'pay_system_id' => Schema::TYPE_INTEGER . ' NULL', + 'delivery_id' => Schema::TYPE_INTEGER . ' NULL', + + 'user_description' => Schema::TYPE_STRING . '(255) NULL', + 'additional_info' => Schema::TYPE_STRING . '(255) NULL', + + 'ps_status' => Schema::TYPE_STRING . '(1) NULL', + 'ps_status_code' => Schema::TYPE_STRING . '(5) NULL', + 'ps_status_description' => Schema::TYPE_STRING . '(255) NULL', + 'ps_status_message' => Schema::TYPE_STRING . '(255) NULL', + 'ps_sum' => Schema::TYPE_DECIMAL . '(18,2) NULL', + 'ps_currency' => Schema::TYPE_STRING. '(3) NULL', + 'ps_respose_at' => Schema::TYPE_INTEGER. ' NULL', + 'data' => Schema::TYPE_TEXT. ' NULL', + + 'comments' => Schema::TYPE_TEXT. ' NULL', + 'tax_value' => Schema::TYPE_DECIMAL . '(18,2) NULL', + + 'locked_by' => Schema::TYPE_INTEGER . ' NULL', + 'locked_at' => Schema::TYPE_INTEGER . ' NULL', + + 'reserved' => Schema::TYPE_SMALLINT . '(1) NOT NULL DEFAULT 0', + + ], $tableOptions); + + $this->execute("ALTER TABLE {{%shop_order}} ADD INDEX(updated_by);"); + $this->execute("ALTER TABLE {{%shop_order}} ADD INDEX(created_by);"); + + $this->execute("ALTER TABLE {{%shop_order}} ADD INDEX(created_at);"); + $this->execute("ALTER TABLE {{%shop_order}} ADD INDEX(updated_at);"); + + $this->execute("ALTER TABLE {{%shop_order}} ADD INDEX(person_type_id);"); + $this->execute("ALTER TABLE {{%shop_order}} ADD INDEX(payed);"); + $this->execute("ALTER TABLE {{%shop_order}} ADD INDEX(payed_at);"); + $this->execute("ALTER TABLE {{%shop_order}} ADD INDEX(status_code);"); + $this->execute("ALTER TABLE {{%shop_order}} ADD INDEX(status_at);"); + + $this->execute("ALTER TABLE {{%shop_order}} ADD INDEX(canceled);"); + $this->execute("ALTER TABLE {{%shop_order}} ADD INDEX(canceled_at);"); + $this->execute("ALTER TABLE {{%shop_order}} ADD INDEX(reason_canceled);"); + + $this->execute("ALTER TABLE {{%shop_order}} ADD INDEX(price);"); + $this->execute("ALTER TABLE {{%shop_order}} ADD INDEX(currency);"); + + $this->execute("ALTER TABLE {{%shop_order}} ADD INDEX(price_delivery);"); + $this->execute("ALTER TABLE {{%shop_order}} ADD INDEX(allow_delivery);"); + $this->execute("ALTER TABLE {{%shop_order}} ADD INDEX(allow_delivery_at);"); + + $this->execute("ALTER TABLE {{%shop_order}} ADD INDEX(discount_value);"); + $this->execute("ALTER TABLE {{%shop_order}} ADD INDEX(user_id);"); + + $this->execute("ALTER TABLE {{%shop_order}} ADD INDEX(pay_system_id);"); + $this->execute("ALTER TABLE {{%shop_order}} ADD INDEX(delivery_id);"); + + $this->execute("ALTER TABLE {{%shop_order}} ADD INDEX(user_description);"); + $this->execute("ALTER TABLE {{%shop_order}} ADD INDEX(additional_info);"); + + $this->execute("ALTER TABLE {{%shop_order}} ADD INDEX(ps_status);"); + $this->execute("ALTER TABLE {{%shop_order}} ADD INDEX(ps_status_code);"); + $this->execute("ALTER TABLE {{%shop_order}} ADD INDEX(ps_status_description);"); + $this->execute("ALTER TABLE {{%shop_order}} ADD INDEX(ps_status_message);"); + $this->execute("ALTER TABLE {{%shop_order}} ADD INDEX(ps_sum);"); + $this->execute("ALTER TABLE {{%shop_order}} ADD INDEX(ps_currency);"); + $this->execute("ALTER TABLE {{%shop_order}} ADD INDEX(ps_respose_at);"); + + $this->execute("ALTER TABLE {{%shop_order}} ADD INDEX(tax_value);"); + + $this->execute("ALTER TABLE {{%shop_order}} ADD INDEX(locked_by);"); + $this->execute("ALTER TABLE {{%shop_order}} ADD INDEX(locked_at);"); + + $this->execute("ALTER TABLE {{%shop_order}} ADD INDEX(reserved);"); + + $this->execute("ALTER TABLE {{%shop_order}} COMMENT = 'Заказы';"); + + $this->addForeignKey( + 'shop_order_created_by', "{{%shop_order}}", + 'created_by', '{{%cms_user}}', 'id', 'SET NULL', 'SET NULL' + ); + + $this->addForeignKey( + 'shop_order_updated_by', "{{%shop_order}}", + 'updated_by', '{{%cms_user}}', 'id', 'SET NULL', 'SET NULL' + ); + + $this->addForeignKey( + 'shop_order_person_type_id', "{{%shop_order}}", + 'person_type_id', '{{%shop_person_type}}', 'id', 'RESTRICT', 'RESTRICT' + ); + + $this->addForeignKey( + 'shop_order__user_id', "{{%shop_order}}", + 'user_id', '{{%cms_user}}', 'id', 'RESTRICT', 'RESTRICT' + ); + + $this->addForeignKey( + 'shop_order__status_code', "{{%shop_order}}", + 'status_code', '{{%shop_order_status}}', 'code', 'RESTRICT', 'RESTRICT' + ); + + + $this->addForeignKey( + 'shop_order__locked_by', "{{%shop_order}}", + 'locked_by', '{{%cms_user}}', 'id', 'RESTRICT', 'RESTRICT' + ); + } + + public function safeDown() + { + $this->dropForeignKey("shop_order_updated_by", "{{%shop_order}}"); + $this->dropForeignKey("shop_order_updated_by", "{{%shop_order}}"); + $this->dropForeignKey("shop_order_person_type_id", "{{%shop_order}}"); + $this->dropForeignKey("shop_order__user_id", "{{%shop_order}}"); + $this->dropForeignKey("shop_order__status_code", "{{%shop_order}}"); + $this->dropForeignKey("shop_order__locked_by", "{{%shop_order}}"); + + $this->dropTable("{{%shop_order}}"); + } +} diff --git a/migrations/m150401_112818_create_table__shop_basket.php b/migrations/m150401_112818_create_table__shop_basket.php new file mode 100644 index 0000000..869296d --- /dev/null +++ b/migrations/m150401_112818_create_table__shop_basket.php @@ -0,0 +1,132 @@ + + * @link http://skeeks.com/ + * @copyright 2010 SkeekS (СкикС) + * @date 01.04.2015 + */ +use yii\db\Schema; +use yii\db\Migration; + +class m150401_112818_create_table__shop_basket extends Migration +{ + public function up() + { + $tableExist = $this->db->getTableSchema("{{%shop_basket}}", true); + if ($tableExist) + { + return true; + } + + $tableOptions = null; + if ($this->db->driverName === 'mysql') { + $tableOptions = 'CHARACTER SET utf8 COLLATE utf8_general_ci ENGINE=InnoDB'; + } + + $this->createTable("{{%shop_basket}}", [ + 'id' => Schema::TYPE_PK, + + 'created_by' => Schema::TYPE_INTEGER . ' NULL', + 'updated_by' => Schema::TYPE_INTEGER . ' NULL', + + 'created_at' => Schema::TYPE_INTEGER . ' NULL', + 'updated_at' => Schema::TYPE_INTEGER . ' NULL', + + 'fuser_id' => Schema::TYPE_INTEGER . ' NOT NULL', + 'order_id' => Schema::TYPE_INTEGER . ' NULL', + 'product_id' => Schema::TYPE_INTEGER . ' NULL', + + 'price' => Schema::TYPE_DECIMAL . '(18,2)', + 'currency' => Schema::TYPE_STRING. '(3)', + + 'weight' => 'double (18,2)', + 'quantity' => 'double (18,2) DEFAULT "0.00"', + + 'name' => Schema::TYPE_STRING . '(255) NOT NULL', + + 'can_buy' => Schema::TYPE_SMALLINT . ' NOT NULL DEFAULT 1', + 'notes' => Schema::TYPE_STRING . '(255) NULL', + 'detail_page_url' => Schema::TYPE_TEXT . ' NULL', + + 'discount_price' => Schema::TYPE_DECIMAL . '(18,2) NOT NULL DEFAULT "0.00"', + 'discount_name' => Schema::TYPE_STRING . '(255) NULL', + 'discount_value' => Schema::TYPE_STRING . '(32) NULL', + 'discount_coupon' => Schema::TYPE_STRING . '(32) NULL', + + 'vat_rate' => Schema::TYPE_DECIMAL . '(18,2) NOT NULL DEFAULT "0.00"', + + 'reserved' => Schema::TYPE_SMALLINT . ' NOT NULL DEFAULT 0', + 'reserved_quantity' => 'double NULL', + 'deducted' => Schema::TYPE_SMALLINT . ' NOT NULL DEFAULT 0', + 'custom_price' => Schema::TYPE_SMALLINT . ' NOT NULL DEFAULT 0', + + ], $tableOptions); + + $this->execute("ALTER TABLE {{%shop_basket}} ADD INDEX(updated_by);"); + $this->execute("ALTER TABLE {{%shop_basket}} ADD INDEX(created_by);"); + + $this->execute("ALTER TABLE {{%shop_basket}} ADD INDEX(created_at);"); + $this->execute("ALTER TABLE {{%shop_basket}} ADD INDEX(updated_at);"); + + $this->execute("ALTER TABLE {{%shop_basket}} ADD INDEX(fuser_id);"); + $this->execute("ALTER TABLE {{%shop_basket}} ADD INDEX(order_id);"); + $this->execute("ALTER TABLE {{%shop_basket}} ADD INDEX(product_id);"); + $this->execute("ALTER TABLE {{%shop_basket}} ADD INDEX(price);"); + $this->execute("ALTER TABLE {{%shop_basket}} ADD INDEX(currency);"); + $this->execute("ALTER TABLE {{%shop_basket}} ADD INDEX(weight);"); + $this->execute("ALTER TABLE {{%shop_basket}} ADD INDEX(quantity);"); + $this->execute("ALTER TABLE {{%shop_basket}} ADD INDEX(name);"); + $this->execute("ALTER TABLE {{%shop_basket}} ADD INDEX(can_buy);"); + $this->execute("ALTER TABLE {{%shop_basket}} ADD INDEX(notes);"); + $this->execute("ALTER TABLE {{%shop_basket}} ADD INDEX(discount_price);"); + $this->execute("ALTER TABLE {{%shop_basket}} ADD INDEX(discount_name);"); + $this->execute("ALTER TABLE {{%shop_basket}} ADD INDEX(discount_value);"); + $this->execute("ALTER TABLE {{%shop_basket}} ADD INDEX(discount_coupon);"); + $this->execute("ALTER TABLE {{%shop_basket}} ADD INDEX(vat_rate);"); + $this->execute("ALTER TABLE {{%shop_basket}} ADD INDEX(reserved);"); + $this->execute("ALTER TABLE {{%shop_basket}} ADD INDEX(reserved_quantity);"); + $this->execute("ALTER TABLE {{%shop_basket}} ADD INDEX(deducted);"); + $this->execute("ALTER TABLE {{%shop_basket}} ADD INDEX(custom_price);"); + + $this->execute("ALTER TABLE {{%shop_basket}} ADD UNIQUE(fuser_id,product_id,order_id);"); + + $this->execute("ALTER TABLE {{%shop_basket}} COMMENT = 'Позиция в корзине';"); + + $this->addForeignKey( + 'shop_basket_created_by', "{{%shop_basket}}", + 'created_by', '{{%cms_user}}', 'id', 'SET NULL', 'SET NULL' + ); + + $this->addForeignKey( + 'shop_basket_updated_by', "{{%shop_basket}}", + 'updated_by', '{{%cms_user}}', 'id', 'SET NULL', 'SET NULL' + ); + + $this->addForeignKey( + 'shop_basket_fuser_id', "{{%shop_basket}}", + 'fuser_id', '{{%shop_fuser}}', 'id', 'CASCADE', 'CASCADE' + ); + + $this->addForeignKey( + 'shop_basket_order_id', "{{%shop_basket}}", + 'order_id', '{{%shop_order}}', 'id', 'SET NULL', 'SET NULL' + ); + + $this->addForeignKey( + 'shop_basket_product_id', "{{%shop_basket}}", + 'product_id', '{{%catalog_product}}', 'id', 'SET NULL', 'SET NULL' + ); + } + + public function down() + { + $this->dropForeignKey("shop_basket_created_by", "{{%shop_basket}}"); + $this->dropForeignKey("shop_basket_updated_by", "{{%shop_basket}}"); + + $this->dropForeignKey("shop_basket_fuser_id", "{{%shop_basket}}"); + $this->dropForeignKey("shop_basket_order_id", "{{%shop_basket}}"); + $this->dropForeignKey("shop_basket_product_id", "{{%shop_basket}}"); + + $this->dropTable("{{%shop_basket}}"); + } +} diff --git a/migrations/m150401_113818_append_data.php b/migrations/m150401_113818_append_data.php new file mode 100644 index 0000000..e1ea2c7 --- /dev/null +++ b/migrations/m150401_113818_append_data.php @@ -0,0 +1,58 @@ + + * @link http://skeeks.com/ + * @copyright 2010 SkeekS (СкикС) + * @date 01.04.2015 + */ +use yii\db\Schema; +use yii\db\Migration; + +class m150401_113818_append_data extends Migration +{ + public function up() + { + $status = new \skeeks\modules\cms\shop\models\ShopOrderStatus(); + $status->name = 'Выполнен'; + $status->description = 'Заказ доставлен и оплачен'; + $status->priority = '200'; + $status->code = 'F'; + $status->save(); + + $status = new \skeeks\modules\cms\shop\models\ShopOrderStatus(); + $status->name = 'Принят'; + $status->description = 'Заказ принят, но пока не обрабатывается (например, заказ только что создан или ожидается оплата заказа)'; + $status->priority = '200'; + $status->code = 'N'; + $status->save(); + + + + $paySystem = new \skeeks\modules\cms\shop\models\ShopPaySystem(); + $paySystem->name = 'Наличная оплата'; + $paySystem->currency = 'RUB'; + $paySystem->active = 1; + $paySystem->save(); + + $paySystem = new \skeeks\modules\cms\shop\models\ShopPaySystem(); + $paySystem->name = 'Безналичная оплата'; + $paySystem->currency = 'RUB'; + $paySystem->active = 0; + $paySystem->save(); + + + + $personType = new \skeeks\modules\cms\shop\models\ShopPersonType(); + $personType->name = 'Физическое лицо'; + $personType->active = 1; + $personType->save(); + + $personType = new \skeeks\modules\cms\shop\models\ShopPersonType(); + $personType->name = 'Юридическое лицо'; + $personType->active = 0; + $personType->save(); + } + + public function down() + {} +} diff --git a/models/ShopBasket.php b/models/ShopBasket.php new file mode 100644 index 0000000..16ac06a --- /dev/null +++ b/models/ShopBasket.php @@ -0,0 +1,248 @@ + + * @link http://skeeks.com/ + * @copyright 2010 SkeekS (СкикС) + * @date 02.04.2015 + */ +namespace skeeks\modules\cms\shop\models; +use skeeks\cms\models\behaviors\HasStatus; +use skeeks\cms\models\behaviors\HasStatusBoolean; +use skeeks\cms\models\Core; +use skeeks\modules\cms\catalog\models\Product; +use skeeks\modules\cms\money\Currency; +use skeeks\modules\cms\money\Money; +use \Yii; +use yii\helpers\ArrayHelper; + +/** + * This is the model class for table "{{%shop_basket}}". + * + * @property integer $id + * @property integer $created_by + * @property integer $updated_by + * @property integer $created_at + * @property integer $updated_at + * @property integer $fuser_id + * @property integer $order_id + * @property integer $product_id + * @property string $price + * @property string $currency + * @property double $weight + * @property double $quantity + * @property string $name + * @property integer $can_buy + * @property string $notes + * @property string $detail_page_url + * @property string $discount_price + * @property string $discount_name + * @property string $discount_value + * @property string $discount_coupon + * @property string $vat_rate + * @property integer $reserved + * @property double $reserved_quantity + * @property integer $deducted + * @property integer $custom_price + * + * @property CatalogProduct $product + * @property CmsUser $createdBy + * @property ShopFuser $fuser + * @property ShopOrder $order + * @property CmsUser $updatedBy + */ +class ShopBasket extends Core +{ + /** + * @inheritdoc + */ + public static function tableName() + { + return '{{%shop_basket}}'; + } + + /** + * @inheritdoc + */ + public function behaviors() + { + return ArrayHelper::merge(parent::behaviors(), [ + HasStatusBoolean::className() => + [ + 'class' => HasStatusBoolean::className(), + ] + ]); + } + + /** + * @inheritdoc + */ + public function attributeLabels() + { + return array_merge(parent::attributeLabels(), [ + 'id' => Yii::t('app', 'ID'), + 'created_by' => Yii::t('app', 'Created By'), + 'updated_by' => Yii::t('app', 'Updated By'), + 'created_at' => Yii::t('app', 'Created At'), + 'updated_at' => Yii::t('app', 'Updated At'), + 'fuser_id' => Yii::t('app', 'Fuser ID'), + 'order_id' => Yii::t('app', 'Order ID'), + 'product_id' => Yii::t('app', 'Product ID'), + 'price' => Yii::t('app', 'Price'), + 'currency' => Yii::t('app', 'Currency'), + 'weight' => Yii::t('app', 'Weight'), + 'quantity' => Yii::t('app', 'Quantity'), + 'name' => Yii::t('app', 'Name'), + 'can_buy' => Yii::t('app', 'Can Buy'), + 'notes' => Yii::t('app', 'Notes'), + 'detail_page_url' => Yii::t('app', 'Detail Page Url'), + 'discount_price' => Yii::t('app', 'Discount Price'), + 'discount_name' => Yii::t('app', 'Discount Name'), + 'discount_value' => Yii::t('app', 'Discount Value'), + 'discount_coupon' => Yii::t('app', 'Discount Coupon'), + 'vat_rate' => Yii::t('app', 'Vat Rate'), + 'reserved' => Yii::t('app', 'Reserved'), + 'reserved_quantity' => Yii::t('app', 'Reserved Quantity'), + 'deducted' => Yii::t('app', 'Deducted'), + 'custom_price' => Yii::t('app', 'Custom Price'), + ]); + } + + public function scenarios() + { + $scenarios = parent::scenarios(); + + $scenarios[self::SCENARIO_DEFAULT]; + + $scenarios['create'] = $scenarios[self::SCENARIO_DEFAULT]; + $scenarios['update'] = $scenarios[self::SCENARIO_DEFAULT]; + + return $scenarios; + } + + /** + * @inheritdoc + */ + public function rules() + { + return array_merge(parent::rules(), [ + [['created_by', 'updated_by', 'created_at', 'updated_at', 'fuser_id', 'order_id', 'product_id', 'can_buy', 'reserved', 'deducted', 'custom_price'], 'integer'], + [['fuser_id', 'name'], 'required'], + [['price', 'weight', 'quantity', 'discount_price', 'vat_rate', 'reserved_quantity'], 'number'], + [['detail_page_url'], 'string'], + [['currency'], 'string', 'max' => 3], + [['name', 'notes', 'discount_name'], 'string', 'max' => 255], + [['discount_value', 'discount_coupon'], 'string', 'max' => 32] + ]); + } + + + /** + * @return Money + */ + public function price() + { + if ($this->price) + { + return Money::fromString((string) $this->price, $this->currency()); + } + + return Money::fromString((string) 0, $this->currency()); + } + + /** + * @return Currency + */ + public function currency() + { + if ($currency = $this->getAttribute($this->currency)) + { + return Currency::getInstance($currency); + } + + return Currency::getInstance(\Yii::$app->money->currency); + } + + + protected $_product = null; + + /** + * @return Product + */ + public function product() + { + if ($this->_product === null) + { + $this->_product = $this->getProduct()->one(); + } + + return $this->_product; + } + + /** + * @return \yii\db\ActiveQuery + */ + public function getProduct() + { + return $this->hasOne(Product::className(), ['id' => 'product_id']); + } + + /** + * @return \yii\db\ActiveQuery + */ + public function getCreatedBy() + { + return $this->hasOne(CmsUser::className(), ['id' => 'created_by']); + } + + /** + * @return \yii\db\ActiveQuery + */ + public function getFuser() + { + return $this->hasOne(ShopFuser::className(), ['id' => 'fuser_id']); + } + + /** + * @return \yii\db\ActiveQuery + */ + public function getOrder() + { + return $this->hasOne(ShopOrder::className(), ['id' => 'order_id']); + } + + /** + * @return \yii\db\ActiveQuery + */ + public function getUpdatedBy() + { + return $this->hasOne(CmsUser::className(), ['id' => 'updated_by']); + } + + + /** + * Обновить позицию. + * + * @return $this + */ + public function recalculate() + { + /** + * @var $product Product + */ + $product = $this->getProduct()->one(); + if (!$product) + { + return $this; + } + + $cost = $product->cost(); //цена продукта + $money = $cost->multiply($this->quantity); //умножаем на количество + + $this->price = $money->getAmount() / $money->getCurrency()->getSubUnit(); + $this->currency = (string) $money->getCurrency(); + + $this->save(); + + return $this; + } +} \ No newline at end of file diff --git a/models/ShopDelivery.php b/models/ShopDelivery.php new file mode 100644 index 0000000..5dc174d --- /dev/null +++ b/models/ShopDelivery.php @@ -0,0 +1,125 @@ + + * @link http://skeeks.com/ + * @copyright 2010 SkeekS (СкикС) + * @date 02.04.2015 + */ +namespace skeeks\modules\cms\shop\models; +use skeeks\cms\models\behaviors\HasStatus; +use skeeks\cms\models\behaviors\HasStatusBoolean; +use skeeks\cms\models\Core; +use \Yii; +use yii\helpers\ArrayHelper; + +/** + * This is the model class for table "{{%shop_delivery}}". + * + * @property integer $id + * @property integer $created_by + * @property integer $updated_by + * @property integer $created_at + * @property integer $updated_at + * @property string $currency + * @property string $name + * @property string $description + * @property integer $period_from + * @property integer $period_to + * @property string $period_type + * @property integer $weight_from + * @property integer $weight_to + * @property string $order_price_from + * @property string $order_price_to + * @property string $order_currency + * @property integer $status + * @property string $price + * + * @property CmsUser $updatedBy + * @property CmsUser $createdBy + */ +class ShopDelivery extends Core +{ + /** + * @inheritdoc + */ + public static function tableName() + { + return '{{%shop_delivery}}'; + } + + /** + * @inheritdoc + */ + public function behaviors() + { + return ArrayHelper::merge(parent::behaviors(), [ + HasStatusBoolean::className() => + [ + 'class' => HasStatusBoolean::className(), + ] + ]); + } + + /** + * @inheritdoc + */ + public function attributeLabels() + { + return array_merge(parent::attributeLabels(), [ + 'id' => Yii::t('app', 'ID'), + 'created_by' => Yii::t('app', 'Created By'), + 'updated_by' => Yii::t('app', 'Updated By'), + 'created_at' => Yii::t('app', 'Created At'), + 'updated_at' => Yii::t('app', 'Updated At'), + 'currency' => Yii::t('app', 'Currency'), + 'name' => Yii::t('app', 'Name'), + 'description' => Yii::t('app', 'Description'), + 'period_from' => Yii::t('app', 'Period From'), + 'period_to' => Yii::t('app', 'Period To'), + 'period_type' => Yii::t('app', 'Period Type'), + 'weight_from' => Yii::t('app', 'Weight From'), + 'weight_to' => Yii::t('app', 'Weight To'), + 'order_price_from' => Yii::t('app', 'Order Price From'), + 'order_price_to' => Yii::t('app', 'Order Price To'), + 'order_currency' => Yii::t('app', 'Order Currency'), + 'status' => Yii::t('app', 'Status'), + 'price' => Yii::t('app', 'Price'), + ]); + } + + public function scenarios() + { + $scenarios = parent::scenarios(); + + $scenarios[self::SCENARIO_DEFAULT]; + + $scenarios['create'] = $scenarios[self::SCENARIO_DEFAULT]; + $scenarios['update'] = $scenarios[self::SCENARIO_DEFAULT]; + + return $scenarios; + } + + /** + * @inheritdoc + */ + public function rules() + { + return array_merge(parent::rules(), [ + [['created_by', 'updated_by', 'created_at', 'updated_at', 'period_from', 'period_to', 'weight_from', 'weight_to', 'status'], 'integer'], + [['name'], 'required'], + [['description'], 'string'], + [['order_price_from', 'order_price_to', 'price'], 'number'], + [['currency', 'order_currency'], 'string', 'max' => 3], + [['name'], 'string', 'max' => 255], + [['period_type'], 'string', 'max' => 1] + ]); + } + + /** + * @return \yii\db\ActiveQuery + */ + public function getShopOrders() + { + return $this->hasMany(ShopOrder::className(), ['person_type_id' => 'id']); + } +} \ No newline at end of file diff --git a/models/ShopFuser.php b/models/ShopFuser.php new file mode 100644 index 0000000..95c858f --- /dev/null +++ b/models/ShopFuser.php @@ -0,0 +1,157 @@ + + * @link http://skeeks.com/ + * @copyright 2010 SkeekS (СкикС) + * @date 02.04.2015 + */ +namespace skeeks\modules\cms\shop\models; +use skeeks\cms\models\behaviors\HasStatus; +use skeeks\cms\models\behaviors\HasStatusBoolean; +use skeeks\cms\models\Core; +use skeeks\cms\models\User; +use \Yii; +use yii\helpers\ArrayHelper; + +/** + * This is the model class for table "shop_fuser". + * + * @property integer $id + * @property integer $created_by + * @property integer $updated_by + * @property integer $created_at + * @property integer $updated_at + * + * @property ShopBasket[] $shopBaskets + * @property CmsUser $updatedBy + * @property CmsUser $createdBy + */ +class ShopFuser extends Core +{ + /** + * @inheritdoc + */ + public static function tableName() + { + return '{{%shop_fuser}}'; + } + + /** + * @inheritdoc + */ + public function behaviors() + { + return ArrayHelper::merge(parent::behaviors(), [ + + ]); + } + + /** + * @inheritdoc + */ + public function attributeLabels() + { + return array_merge(parent::attributeLabels(), [ + 'id' => Yii::t('app', 'ID'), + 'created_by' => Yii::t('app', 'Created By'), + 'updated_by' => Yii::t('app', 'Updated By'), + 'created_at' => Yii::t('app', 'Created At'), + 'updated_at' => Yii::t('app', 'Updated At'), + 'currency' => Yii::t('app', 'Currency'), + 'name' => Yii::t('app', 'Name'), + 'description' => Yii::t('app', 'Description'), + 'period_from' => Yii::t('app', 'Period From'), + 'period_to' => Yii::t('app', 'Period To'), + 'period_type' => Yii::t('app', 'Period Type'), + 'weight_from' => Yii::t('app', 'Weight From'), + 'weight_to' => Yii::t('app', 'Weight To'), + 'order_price_from' => Yii::t('app', 'Order Price From'), + 'order_price_to' => Yii::t('app', 'Order Price To'), + 'order_currency' => Yii::t('app', 'Order Currency'), + 'status' => Yii::t('app', 'Status'), + 'price' => Yii::t('app', 'Price'), + ]); + } + + public function scenarios() + { + $scenarios = parent::scenarios(); + + $scenarios[self::SCENARIO_DEFAULT]; + + $scenarios['create'] = $scenarios[self::SCENARIO_DEFAULT]; + $scenarios['update'] = $scenarios[self::SCENARIO_DEFAULT]; + + return $scenarios; + } + + /** + * @inheritdoc + */ + public function rules() + { + return array_merge(parent::rules(), [ + [['created_by', 'updated_by', 'created_at', 'updated_at', 'user_id'], 'integer'], + [['user_id'], 'unique'] + ]); + } + + /** + * @return \yii\db\ActiveQuery + */ + public function getUser() + { + return $this->hasOne(CmsUser::className(), ['id' => 'user_id']); + } + + + /** + * @param User $user + * @return static|null + */ + static public function fetchByUser(User $user) + { + return static::find()->where(['user_id' => $user->id])->one(); + } + + + /** + * @return \yii\db\ActiveQuery + */ + public function getShopBaskets() + { + return $this->hasMany(ShopBasket::className(), ['fuser_id' => 'id']); + } + + /** + * Добавить корзины этому пользователю + * + * @param ShopBasket[] $baskets + * @return $this + */ + public function addBaskets($baskets = []) + { + /** + * @var $currentBasket ShopBasket + */ + foreach ($baskets as $basket) + { + //Если в корзине которую необходимо добавить продукт такой же который уже есть у текущего пользователя, то нужно обновить количество. + if ($currentBasket = $this->getShopBaskets()->andWhere(['product_id' => $basket->product_id])->one()) + { + $currentBasket->quantity = $currentBasket->quantity + $basket->quantity; + $currentBasket->save(); + + $basket->delete(); + + $currentBasket->recalculate(); + } else + { + $basket->fuser_id = $this->id; + $basket->save(); + } + } + + return $this; + } +} \ No newline at end of file diff --git a/models/ShopOrder.php b/models/ShopOrder.php new file mode 100644 index 0000000..e0327ee --- /dev/null +++ b/models/ShopOrder.php @@ -0,0 +1,327 @@ + + * @link http://skeeks.com/ + * @copyright 2010 SkeekS (СкикС) + * @date 02.04.2015 + */ +namespace skeeks\modules\cms\shop\models; +use skeeks\cms\models\behaviors\Serialize; +use skeeks\cms\models\User; +use skeeks\cms\helpers\UrlHelper; +use skeeks\cms\models\behaviors\HasStatus; +use skeeks\cms\models\behaviors\HasStatusBoolean; +use skeeks\cms\models\Core; +use skeeks\modules\cms\money\Currency; +use skeeks\modules\cms\money\Money; +use \Yii; +use yii\db\BaseActiveRecord; +use yii\helpers\ArrayHelper; + +/** + * This is the model class for table "{{%shop_order}}". + * + * @property integer $id + * @property integer $created_by + * @property integer $updated_by + * @property integer $created_at + * @property integer $updated_at + * @property integer $person_type_id + * @property integer $payed + * @property integer $payed_at + * @property integer $canceled + * @property integer $canceled_at + * @property string $reason_canceled + * @property string $status_code + * @property integer $status_at + * @property string $price + * @property string $currency + * @property string $price_delivery + * @property integer $allow_delivery + * @property integer $allow_delivery_at + * @property string $discount_value + * @property integer $user_id + * @property integer $pay_system_id + * @property integer $delivery_id + * @property string $user_description + * @property string $additional_info + * @property string $ps_status + * @property string $ps_status_code + * @property string $ps_status_description + * @property string $ps_status_message + * @property string $ps_sum + * @property string $ps_currency + * @property integer $ps_respose_at + * @property string $data + * @property string $comments + * @property string $tax_value + * @property integer $locked_by + * @property integer $locked_at + * @property integer $reserved + * + * @property ShopBasket[] $shopBaskets + * @property User $lockedBy + * @property User $createdBy + * @property ShopPersonType $personType + * @property User $updatedBy + * @property ShopOrderStatus $statusCode + * @property User $user + */ +class ShopOrder extends Core +{ + /** + * @inheritdoc + */ + public static function tableName() + { + return '{{%shop_order}}'; + } + + /** + * @inheritdoc + */ + public function behaviors() + { + return ArrayHelper::merge(parent::behaviors(), [ + HasStatusBoolean::className() => + [ + 'class' => HasStatusBoolean::className(), + ], + Serialize::className() => + [ + 'class' => Serialize::className(), + 'fields' => ['data'] + ] + ]); + } + + /** + * @inheritdoc + */ + public function attributeLabels() + { + return array_merge(parent::attributeLabels(), [ + 'id' => Yii::t('app', 'ID'), + 'created_by' => Yii::t('app', 'Created By'), + 'updated_by' => Yii::t('app', 'Updated By'), + 'created_at' => Yii::t('app', 'Created At'), + 'updated_at' => Yii::t('app', 'Updated At'), + 'person_type_id' => Yii::t('app', 'Person Type ID'), + 'payed' => Yii::t('app', 'Оплачен'), + 'payed_at' => Yii::t('app', 'Payed At'), + 'canceled' => Yii::t('app', 'Отменен'), + 'canceled_at' => Yii::t('app', 'Canceled At'), + 'reason_canceled' => Yii::t('app', 'Reason Canceled'), + 'status' => Yii::t('app', 'Status'), + 'price' => Yii::t('app', 'Price'), + 'currency' => Yii::t('app', 'Currency'), + 'price_delivery' => Yii::t('app', 'Price Delivery'), + 'allow_delivery' => Yii::t('app', 'Доставка разрешена?'), + 'discount_value' => Yii::t('app', 'Discount Value'), + 'user_id' => Yii::t('app', 'User ID'), + 'pay_system_id' => Yii::t('app', 'Pay System ID'), + 'delivery_id' => Yii::t('app', 'Delivery ID'), + 'user_description' => Yii::t('app', 'User Description'), + 'additional_info' => Yii::t('app', 'Additional Info'), + 'ps_status' => Yii::t('app', 'Ps Status'), + 'ps_status_code' => Yii::t('app', 'Ps Status Code'), + 'ps_status_description' => Yii::t('app', 'Ps Status Description'), + 'ps_status_message' => Yii::t('app', 'Ps Status Message'), + 'ps_sum' => Yii::t('app', 'Ps Sum'), + 'ps_currency' => Yii::t('app', 'Ps Currency'), + 'ps_respose_at' => Yii::t('app', 'Ps Respose At'), + 'comments' => Yii::t('app', 'Comments'), + 'tax_value' => Yii::t('app', 'Tax Value'), + 'status_code' => Yii::t('app', 'Статус'), + 'data' => Yii::t('app', 'Данные заказа'), + 'reason_canceled' => Yii::t('app', 'Причина отмены'), + ]); + } + + public function scenarios() + { + $scenarios = parent::scenarios(); + + $scenarios[self::SCENARIO_DEFAULT]; + + $scenarios['create'] = $scenarios[self::SCENARIO_DEFAULT]; + $scenarios['update'] = $scenarios[self::SCENARIO_DEFAULT]; + + return $scenarios; + } + + /** + * @inheritdoc + */ + public function init() + { + parent::init(); + + $this->on(BaseActiveRecord::EVENT_BEFORE_INSERT, [$this, "checkSave"]); + $this->on(BaseActiveRecord::EVENT_BEFORE_UPDATE, [$this, "checkSave"]); + } + + public function checkSave() + { + if ($this->getOldAttribute('status_code') != $this->getAttribute('status_code')) + { + $this->status_at = \Yii::$app->formatter->asTimestamp(time()); + } + + if ($this->getOldAttribute('payed') != $this->getAttribute('payed')) + { + $this->payed_at = \Yii::$app->formatter->asTimestamp(time()); + } + + if ($this->getOldAttribute('canceled') != $this->getAttribute('canceled')) + { + $this->canceled_at = \Yii::$app->formatter->asTimestamp(time()); + } + } + + + /** + * @inheritdoc + */ + public function rules() + { + return array_merge(parent::rules(), [ + [['created_by', 'updated_by', 'created_at', 'updated_at', 'person_type_id', 'payed', 'payed_at', 'canceled', 'canceled_at', 'status_at', 'allow_delivery', 'allow_delivery_at', 'user_id', 'pay_system_id', 'delivery_id', 'ps_respose_at', 'locked_by', 'locked_at', 'reserved'], 'integer'], + [['price', 'price_delivery', 'discount_value', 'ps_sum', 'tax_value'], 'number'], + [['user_id'], 'required'], + [['data'], 'safe'], + [['canceled'], 'validateCanceled'], + [['comments'], 'string'], + [['reason_canceled', 'user_description', 'additional_info', 'ps_status_description', 'ps_status_message'], 'string', 'max' => 255], + [['status_code', 'ps_status'], 'string', 'max' => 1], + [['currency', 'ps_currency'], 'string', 'max' => 3], + [['ps_status_code'], 'string', 'max' => 5], + + ['status_at', 'default', 'value' => function(ShopOrder $model, $attribute) + { + if (!$model->$attribute) + { + return \Yii::$app->formatter->asTimestamp(time()); + } + }], + + ]); + } + + /** + * Правильная валидация видео ссылки. + * + * @param $attribute + */ + public function validateCanceled($attribute) + { + if ($this->$attribute == 1) + { + if (!$this->reason_canceled) + { + $this->addError($attribute, "Укажите причину отмены"); + } + } + } + + + /** + * @return \yii\db\ActiveQuery + */ + public function getShopBaskets() + { + return $this->hasMany(ShopBasket::className(), ['order_id' => 'id']); + } + + /** + * @return \yii\db\ActiveQuery + */ + public function getUser() + { + return $this->hasOne(User::className(), ['id' => 'user_id']); + } + + /** + * @return \yii\db\ActiveQuery + */ + public function getLockedBy() + { + return $this->hasOne(CmsUser::className(), ['id' => 'locked_by']); + } + + /** + * @return \yii\db\ActiveQuery + */ + public function getCreatedBy() + { + return $this->hasOne(User::className(), ['id' => 'created_by']); + } + + /** + * @return \yii\db\ActiveQuery + */ + public function getPersonType() + { + return $this->hasOne(ShopPersonType::className(), ['id' => 'person_type_id']); + } + + /** + * @return \yii\db\ActiveQuery + */ + public function getPaySystem() + { + return $this->hasOne(ShopPaySystem::className(), ['id' => 'pay_system_id']); + } + + /** + * @return \yii\db\ActiveQuery + */ + public function getUpdatedBy() + { + return $this->hasOne(User::className(), ['id' => 'updated_by']); + } + + /** + * @return \yii\db\ActiveQuery + */ + public function getStatusCode() + { + return $this->hasOne(ShopOrderStatus::className(), ['code' => 'status_code']); + } + + + + /** + * @return Money + */ + public function price() + { + if ($this->price) + { + return Money::fromString((string) $this->price, $this->currency()); + } + + return Money::fromString((string) 0, $this->currency()); + } + + /** + * @return Currency + */ + public function currency() + { + if ($currency = $this->getAttribute($this->currency)) + { + return Currency::getInstance($currency); + } + + return Currency::getInstance(\Yii::$app->money->currency); + } + + /** + * @return string + */ + public function getPageUrl() + { + return UrlHelper::construct('shop/order/view', ['id' => $this->id])->toString(); + } +} \ No newline at end of file diff --git a/models/ShopOrderStatus.php b/models/ShopOrderStatus.php new file mode 100644 index 0000000..d475233 --- /dev/null +++ b/models/ShopOrderStatus.php @@ -0,0 +1,176 @@ + + * @link http://skeeks.com/ + * @copyright 2010 SkeekS (СкикС) + * @date 21.04.2015 + */ +namespace skeeks\modules\cms\shop\models; + +use skeeks\cms\models\Core; +use skeeks\cms\models\User; +use skeeks\modules\cms\shop\models\ShopOrder; +use Yii; +use yii\base\UserException; +use yii\db\BaseActiveRecord; +use yii\helpers\ArrayHelper; + +/** + * This is the model class for table "{{%shop_order_status}}". + * + * @property integer $id + * @property integer $created_by + * @property integer $updated_by + * @property integer $created_at + * @property integer $updated_at + * @property string $code + * @property string $name + * @property string $description + * @property integer $priority + * @property string $color + * + * @property ShopOrder[] $shopOrders + * @property User $updatedBy + * @property User $createdBy + */ +class ShopOrderStatus extends Core +{ + const STATUS_CODE_START = "N"; + const STATUS_CODE_END = "F"; + + static public $protectedStatuses = + [ + self::STATUS_CODE_START, self::STATUS_CODE_END + ]; + + /** + * @inheritdoc + */ + public function init() + { + parent::init(); + + $this->on(BaseActiveRecord::EVENT_BEFORE_DELETE, [$this, "checkDelete"]); + } + + public function checkDelete() + { + if ($this->isProtected()) + { + throw new UserException('Нельзя удалять этот статус'); + } + } + + /** + * @inheritdoc + */ + public static function tableName() + { + return '{{%shop_order_status}}'; + } + + /** + * @inheritdoc + */ + public function behaviors() + { + return ArrayHelper::merge(parent::behaviors(), []); + } + + /** + * Нельзя удалять и редактировать статус? + * @return bool + */ + public function isProtected() + { + if (in_array($this->code, (array) static::$protectedStatuses)) + { + return true; + } + + return false; + } + + /** + * @inheritdoc + */ + public function attributeLabels() + { + return array_merge(parent::attributeLabels(), [ + 'id' => Yii::t('app', 'ID'), + 'created_by' => Yii::t('app', 'Created By'), + 'updated_by' => Yii::t('app', 'Updated By'), + 'created_at' => Yii::t('app', 'Created At'), + 'updated_at' => Yii::t('app', 'Updated At'), + 'code' => Yii::t('app', 'Код'), + 'name' => Yii::t('app', 'Name'), + 'description' => Yii::t('app', 'Описание'), + 'priority' => Yii::t('app', 'Priority'), + 'color' => Yii::t('app', 'Color'), + ]); + } + + public function scenarios() + { + $scenarios = parent::scenarios(); + + $scenarios[self::SCENARIO_DEFAULT]; + + $scenarios['create'] = $scenarios[self::SCENARIO_DEFAULT]; + $scenarios['update'] = $scenarios[self::SCENARIO_DEFAULT]; + + return $scenarios; + } + + + /** + * @inheritdoc + */ + public function rules() + { + return array_merge(parent::rules(), [ + [['created_by', 'updated_by', 'created_at', 'updated_at', 'priority'], 'integer'], + [['code', 'name'], 'required'], + [['description'], 'string'], + [['code'], 'string', 'max' => 1], + [['name'], 'string', 'max' => 255], + [['color'], 'string', 'max' => 32], + [['code'], 'unique'], + [['code'], 'validateCode'] + ]); + } + + + public function validateCode($attribute) + { + if(!preg_match('/^[A-Z]{1}$/', $this->$attribute)) + { + $this->addError($attribute, 'Используйте только заглавные буквы латинского алфавита.'); + } + } + + + /** + * @return \yii\db\ActiveQuery + */ + public function getShopOrders() + { + return $this->hasMany(ShopOrder::className(), ['status_code' => 'code']); + } + + /** + * @return \yii\db\ActiveQuery + */ + public function getUpdatedBy() + { + return $this->hasOne(CmsUser::className(), ['id' => 'updated_by']); + } + + /** + * @return \yii\db\ActiveQuery + */ + public function getCreatedBy() + { + return $this->hasOne(CmsUser::className(), ['id' => 'created_by']); + } +} \ No newline at end of file diff --git a/models/ShopPaySystem.php b/models/ShopPaySystem.php new file mode 100644 index 0000000..28e103e --- /dev/null +++ b/models/ShopPaySystem.php @@ -0,0 +1,97 @@ + + * @link http://skeeks.com/ + * @copyright 2010 SkeekS (СкикС) + * @date 02.04.2015 + */ +namespace skeeks\modules\cms\shop\models; +use skeeks\cms\models\behaviors\HasStatus; +use skeeks\cms\models\behaviors\HasStatusBoolean; +use skeeks\cms\models\Core; +use \Yii; +use yii\helpers\ArrayHelper; + +/** + * This is the model class for table "{{%shop_pay_system}}". + * + * @property integer $id + * @property integer $created_by + * @property integer $updated_by + * @property integer $created_at + * @property integer $updated_at + * @property string $currency + * @property string $name + * @property string $description + * @property integer $status + * + * @property User $updatedBy + * @property User $createdBy + */ +class ShopPaySystem extends Core +{ + /** + * @inheritdoc + */ + public static function tableName() + { + return '{{%shop_pay_system}}'; + } + + /** + * @inheritdoc + */ + public function behaviors() + { + return ArrayHelper::merge(parent::behaviors(), [ + HasStatusBoolean::className() => + [ + 'class' => HasStatusBoolean::className(), + ] + ]); + } + + /** + * @inheritdoc + */ + public function attributeLabels() + { + return array_merge(parent::attributeLabels(), [ + 'id' => Yii::t('app', 'ID'), + 'created_by' => Yii::t('app', 'Created By'), + 'updated_by' => Yii::t('app', 'Updated By'), + 'created_at' => Yii::t('app', 'Created At'), + 'updated_at' => Yii::t('app', 'Updated At'), + 'currency' => Yii::t('app', 'Currency'), + 'name' => Yii::t('app', 'Name'), + 'description' => Yii::t('app', 'Description'), + 'active' => Yii::t('app', 'Активность'), + ]); + } + + public function scenarios() + { + $scenarios = parent::scenarios(); + + $scenarios[self::SCENARIO_DEFAULT]; + + $scenarios['create'] = $scenarios[self::SCENARIO_DEFAULT]; + $scenarios['update'] = $scenarios[self::SCENARIO_DEFAULT]; + + return $scenarios; + } + + /** + * @inheritdoc + */ + public function rules() + { + return array_merge(parent::rules(), [ + [['created_by', 'updated_by', 'created_at', 'updated_at', 'active'], 'integer'], + [['name'], 'required'], + [['description'], 'string'], + [['currency'], 'string', 'max' => 3], + [['name'], 'string', 'max' => 255] + ]); + } +} \ No newline at end of file diff --git a/models/ShopPersonType.php b/models/ShopPersonType.php new file mode 100644 index 0000000..847feed --- /dev/null +++ b/models/ShopPersonType.php @@ -0,0 +1,166 @@ + + * @link http://skeeks.com/ + * @copyright 2010 SkeekS (СкикС) + * @date 02.04.2015 + */ +namespace skeeks\modules\cms\shop\models; +use skeeks\cms\models\behaviors\HasStatus; +use skeeks\cms\models\behaviors\HasStatusBoolean; +use skeeks\cms\models\Core; +use skeeks\modules\cms\form\models\Form; +use \Yii; +use yii\helpers\ArrayHelper; +use yii\web\ErrorHandler; + +/** + * This is the model class for table "{{%shop_person_type}}". + * + * @property integer $id + * @property integer $created_by + * @property integer $updated_by + * @property integer $created_at + * @property integer $updated_at + * @property string $name + * @property integer $active + * @property integer $form_id + * + * @property ShopOrder[] $shopOrders + * @property User $updatedBy + * @property User $createdBy + */ +class ShopPersonType extends Core +{ + /** + * @inheritdoc + */ + public static function tableName() + { + return '{{%shop_person_type}}'; + } + + /** + * @inheritdoc + */ + public function behaviors() + { + return ArrayHelper::merge(parent::behaviors(), [ + HasStatusBoolean::className() => + [ + 'class' => HasStatusBoolean::className(), + ] + ]); + } + + /** + * @inheritdoc + */ + public function attributeLabels() + { + return array_merge(parent::attributeLabels(), [ + 'id' => Yii::t('app', 'ID'), + 'created_by' => Yii::t('app', 'Created By'), + 'updated_by' => Yii::t('app', 'Updated By'), + 'created_at' => Yii::t('app', 'Created At'), + 'updated_at' => Yii::t('app', 'Updated At'), + 'name' => Yii::t('app', 'Name'), + 'active' => Yii::t('app', 'Активность'), + 'form_id' => Yii::t('app', 'Форма с полями и данными'), + ]); + } + + public function scenarios() + { + $scenarios = parent::scenarios(); + + $scenarios[self::SCENARIO_DEFAULT]; + + $scenarios['create'] = $scenarios[self::SCENARIO_DEFAULT]; + $scenarios['update'] = $scenarios[self::SCENARIO_DEFAULT]; + + return $scenarios; + } + + /** + * @inheritdoc + */ + public function rules() + { + return array_merge(parent::rules(), [ + [['created_by', 'updated_by', 'created_at', 'updated_at', 'active', 'form_id'], 'integer'], + [['name'], 'required'], + [['name'], 'string', 'max' => 255] + ]); + } + + /** + * @return \yii\db\ActiveQuery + */ + public function getShopOrders() + { + return $this->hasMany(ShopOrder::className(), ['person_type_id' => 'id']); + } + + /** + * @return \yii\db\ActiveQuery + */ + public function getForm() + { + return $this->hasOne(Form::className(), ['id' => 'form_id']); + } + + /** + * @return Form + */ + public function form() + { + return $this->getForm()->one(); + } + + /** + * @return string + */ + public function renderForm() + { + /** + * @var $moduleForm \skeeks\modules\cms\shop\Module + */ + //$moduleForm = \Yii::$app->getModule('shop'); + $moduleForm = \Yii::$app->getModule('form'); + $formModel = $this->form(); + + try + { + $model = $formModel->createValidateModel(); + if (!\Yii::$app->user->isGuest) + { + $model->setAttributes(\Yii::$app->cms->getAuthUser()->toArray(), true); + } + + return \Yii::$app->view->render('@skeeks/modules/cms/shop/views/cart-form', [ + 'shopPersonType' => $this, + 'shopPaySystems' => $this->fetchPaySystems(), + 'module' => $moduleForm, + 'modelForm' => $formModel, + 'fields' => $formModel->fields(), + 'model' => $model + ]); + + } catch (\Exception $e) + { + ob_end_clean(); + ErrorHandler::convertExceptionToError($e); + return 'Ошибка рендеринга формы: ' . $e->getMessage(); + } + } + + /** + * TODO: добавить выборку платежных систем которые подходят для текущего плательщика. + * @return ShopPaySystem[] + */ + public function fetchPaySystems() + { + return ShopPaySystem::find()->where(['active' => 1])->all(); + } +} \ No newline at end of file diff --git a/views/admin-shop-order-status/_form.php b/views/admin-shop-order-status/_form.php new file mode 100644 index 0000000..59b4d57 --- /dev/null +++ b/views/admin-shop-order-status/_form.php @@ -0,0 +1,37 @@ + + + + + +fieldSet('Основное'); ?> + + isProtected()) : ?> +
+ Этот статус является базовым, нельзя менять его код +
+ field($model, 'code')->textInput([ + 'maxlength' => 255, + 'disabled' => 'disabled', + ]) ?> + + field($model, 'code')->textInput([ + 'maxlength' => 255, + ]) ?> + + + field($model, 'name')->textInput(['maxlength' => 255]) ?> + field($model, 'description')->textarea(['rows' => 5]) ?> + +fieldSetEnd(); ?> + + +buttonsCreateOrUpdate($model); ?> + \ No newline at end of file diff --git a/views/admin-shop-order-status/index.php b/views/admin-shop-order-status/index.php new file mode 100644 index 0000000..e2d53f1 --- /dev/null +++ b/views/admin-shop-order-status/index.php @@ -0,0 +1,37 @@ + + + * @link http://skeeks.com/ + * @copyright 2010-2014 SkeekS (Sx) + * @date 30.10.2014 + * @since 1.0.0 + */ +use skeeks\cms\modules\admin\widgets\GridView; + +/* @var $this yii\web\View */ +/* @var $searchModel common\models\searchs\Game */ +/* @var $dataProvider yii\data\ActiveDataProvider */ +?> + + $dataProvider, + 'filterModel' => $searchModel, + 'columns' => [ + [ + 'class' => \skeeks\cms\modules\admin\grid\ActionColumn::className(), + 'controller' => $controller + ], + + [ + 'attribute' => 'code', + //'filter' => \yii\helpers\Html::input(), + ], + + 'name', + 'description', + + ], +]); ?> diff --git a/views/admin-shop-order/_form.php b/views/admin-shop-order/_form.php new file mode 100644 index 0000000..e585884 --- /dev/null +++ b/views/admin-shop-order/_form.php @@ -0,0 +1,311 @@ + + * @link http://skeeks.com/ + * @copyright 2010 SkeekS (СкикС) + * @date 14.04.2015 + */ +/* @var $widget \skeeks\modules\cms\shop\widgets\order\OrderWidget */ +/* @var $model \skeeks\modules\cms\shop\models\ShopOrder */ +/* @var $this \yii\web\View */ + +use yii\helpers\Html; +use skeeks\cms\modules\admin\widgets\form\ActiveFormUseTab as ActiveForm; + +?> + + + +fieldSet('Карточка заказа'); ?> + + + + + + + + + + + + + + + + + + + + + + + + + + +
Заказ №id; ?> от formatter->asDatetime($model->created_at); ?> (formatter->asRelativeTime($model->created_at); ?>)
Заказ №:id; ?>
Создан:formatter->asDatetime($model->created_at); ?> (formatter->asRelativeTime($model->created_at); ?>)
Текущий статус заказа:statusCode->name; ?>
formatter->asDatetime($model->status_at); ?> (formatter->asRelativeTime($model->status_at); ?>)
Сумма заказа:money->intlFormatter()->format($model->price()); ?>
Отменен: + canceled) : ?> + Да +
+ formatter->asDatetime($model->canceled_at); ?> (formatter->asRelativeTime($model->canceled_at); ?>) +
+

Прчина: reason_canceled; ?>

+ + Нет + +
+ + + + + + + + + + + + + + + + + +
Данные учетной записи
Учетная запись:user->getDisplayName(); ?>
Логин:user->username; ?>
E-Mail адрес:user->email; ?>
+ + + + + + + + + + data) : ?> + data as $key => $value) : ?> + + + + + + +
Параметры заказа
Тип плательщика:personType->name; ?>
:
+ + + + + + + + + + + + + +
Оплата и доставка
Платежная система:paySystem->name; ?>
Оплачен: + payed) : ?> + Да
formatter->asDatetime($model->payed_at); ?> (formatter->asRelativeTime($model->payed_at); ?>) + + Нет + +
+ + + + + + + + + +
Служба доставки
Служба доставки:Не используется
+ + + + + + + + +
Содержимое заказа
+ registerCss(<< +
+ new \yii\data\ArrayDataProvider([ + 'allModels' => \skeeks\modules\cms\shop\models\ShopBasket::find()->where(['order_id' => $model->id])->all() + ]), + 'layout' => '{items}', + 'columns' => + [ + [ + 'class' => \yii\grid\DataColumn::className(), + 'value' => function(\skeeks\modules\cms\shop\models\ShopBasket $model) + { + $product = $model->product(); + $pageUrl = $product->getPageUrl(); + $name = $product->name; + + $imageUrl = skeeks\cms\helpers\Image::getSrc($product->getMainImageSrc()); + + + return << + {$name} + +HTML; + }, + 'format' => 'html', + 'label' => 'Фото' + ], + + [ + 'class' => \yii\grid\DataColumn::className(), + 'value' => function(\skeeks\modules\cms\shop\models\ShopBasket $model) + { + return \yii\helpers\Html::a($model->name, $model->product()->getPageUrl()); + }, + 'format' => 'html', + 'label' => 'Товар' + ], + + [ + 'class' => \yii\grid\DataColumn::className(), + 'value' => function(\skeeks\modules\cms\shop\models\ShopBasket $model) + { + return $model->quantity; + + }, + 'format' => 'raw', + 'label' => 'Количество' + ], + + [ + 'class' => \yii\grid\DataColumn::className(), + 'value' => function(\skeeks\modules\cms\shop\models\ShopBasket $model) + { + return \Yii::$app->money->intlFormatter()->format($model->product()->cost()); + }, + 'format' => 'html', + 'label' => 'Цена товара' + ], + + [ + 'class' => \yii\grid\DataColumn::className(), + 'value' => function(\skeeks\modules\cms\shop\models\ShopBasket $model) + { + return \Yii::$app->money->intlFormatter()->format($model->price()); + }, + 'format' => 'html', + 'label' => 'Всего' + ], + + ] + ]); + ?> +
+
+ + +fieldSetEnd(); ?> + +fieldSet('Управление'); ?> + + field($model, 'status_code')->widget( + \skeeks\widget\chosen\Chosen::className(), + [ + 'allowDeselect' => false, + 'items' => \yii\helpers\ArrayHelper::map( + \skeeks\modules\cms\shop\models\ShopOrderStatus::find()->all(), + 'code', + 'name' + ) + ] + ) ?> + + field($model, 'payed')->radioList( + \Yii::$app->formatter->booleanFormat + ) ?> + + field($model, 'allow_delivery')->radioList( + \Yii::$app->formatter->booleanFormat + ) ?> + + field($model, 'canceled')->widget( + \skeeks\widget\chosen\Chosen::className(), + [ + 'allowDeselect' => false, + 'items' => \Yii::$app->formatter->booleanFormat + ] + ) ?> + + + +registerJs(<< + + + +fieldSetEnd(); ?> + +buttonsCreateOrUpdate($model); ?> + + + diff --git a/views/admin-shop-order/index.php b/views/admin-shop-order/index.php new file mode 100644 index 0000000..8c1f357 --- /dev/null +++ b/views/admin-shop-order/index.php @@ -0,0 +1,106 @@ + + * @link http://skeeks.com/ + * @copyright 2010-2014 SkeekS (Sx) + * @date 30.10.2014 + * @since 1.0.0 + */ +use skeeks\cms\modules\admin\widgets\GridView; + +/* @var $this yii\web\View */ +/* @var $searchModel common\models\searchs\Game */ +/* @var $dataProvider yii\data\ActiveDataProvider */ + +$dataProvider->sort->defaultOrder = ['id' => SORT_DESC]; +?> + + $dataProvider, + 'filterModel' => $searchModel, + 'columns' => [ + [ + 'class' => \skeeks\cms\modules\admin\grid\ActionColumn::className(), + 'controller' => $controller + ], + + [ + 'class' => \skeeks\cms\grid\CreatedAtColumn::className(), + ], + + [ + 'class' => \yii\grid\DataColumn::className(), + 'value' => function(\skeeks\modules\cms\shop\models\ShopOrder $model) + { + return "№" . $model->id; + }, + 'label' => 'Номер заказа', + 'attribute' => 'id', + //'filter' => \yii\helpers\Html::input(), + ], + + + [ + 'class' => \yii\grid\DataColumn::className(), + 'value' => function(\skeeks\modules\cms\shop\models\ShopOrder $model) + { + $result = []; + foreach ($model->shopBaskets as $shopBasket) + { + $result[] = \yii\helpers\Html::a("[{$shopBasket->product->id}] " . $shopBasket->product->name . " ({$shopBasket->quantity} шт.)", $shopBasket->product->getPageUrl(), [ + 'data' => + [ + 'pjax' => '0' + ], + 'target' => '_blank', + 'title' => 'Смотреть товар на сайте (откроется в новой вкладке)' + ]); + } + + return implode('
', $result); + }, + 'label' => 'Позиции', + 'format' => 'raw', + ], + + + [ + 'class' => \skeeks\cms\grid\UserColumnData::className(), + 'attribute' => 'user_id', + 'label' => 'Покупатель' + ], + + [ + 'attribute' => 'price', + 'label' => 'Сумма', + 'class' => \yii\grid\DataColumn::className(), + 'value' => function(\skeeks\modules\cms\shop\models\ShopOrder $model) + { + return \Yii::$app->money->intlFormatter()->format($model->price()); + }, + ], + + [ + 'class' => \skeeks\cms\grid\BooleanColumn::className(), + 'attribute' => 'payed', + ], + + [ + 'class' => \skeeks\cms\grid\BooleanColumn::className(), + 'attribute' => 'canceled', + ], + + [ + 'class' => \yii\grid\DataColumn::className(), + 'value' => function(\skeeks\modules\cms\shop\models\ShopOrder $model) + { + return $model->statusCode->name; + }, + 'attribute' => 'status_code', + 'label' => 'Статус', + 'filter' => \yii\helpers\ArrayHelper::map(\skeeks\modules\cms\shop\models\ShopOrderStatus::find()->all(), 'code', 'name') + ], + ], +]); ?> diff --git a/views/admin-shop-pay-system/_form.php b/views/admin-shop-pay-system/_form.php new file mode 100644 index 0000000..bb78257 --- /dev/null +++ b/views/admin-shop-pay-system/_form.php @@ -0,0 +1,29 @@ + + + + + +fieldSet('Основное'); ?> + + field($model, 'name')->textInput(['maxlength' => 255]) ?> + field($model, 'active')->widget( + \skeeks\widget\chosen\Chosen::className(), + [ + 'items' => \Yii::$app->formatter->booleanFormat + ] + ) ?> +fieldSetEnd(); ?> + +fieldSet('Типы плательщиков'); ?> + +fieldSetEnd(); ?> + +buttonsCreateOrUpdate($model); ?> + \ No newline at end of file diff --git a/views/admin-shop-pay-system/index.php b/views/admin-shop-pay-system/index.php new file mode 100644 index 0000000..0cd4a20 --- /dev/null +++ b/views/admin-shop-pay-system/index.php @@ -0,0 +1,37 @@ + + * @link http://skeeks.com/ + * @copyright 2010-2014 SkeekS (Sx) + * @date 30.10.2014 + * @since 1.0.0 + */ +use skeeks\cms\modules\admin\widgets\GridView; + +/* @var $this yii\web\View */ +/* @var $searchModel common\models\searchs\Game */ +/* @var $dataProvider yii\data\ActiveDataProvider */ + +$dataProvider->sort->defaultOrder = [ + 'active' => SORT_DESC, +]; + +?> + + $dataProvider, + 'filterModel' => $searchModel, + 'columns' => [ + [ + 'class' => \skeeks\cms\modules\admin\grid\ActionColumn::className(), + 'controller' => $controller + ], + 'name', + [ + 'class' => \skeeks\cms\grid\BooleanColumn::className(), + 'attribute' => 'active' + ], + ], +]); ?> diff --git a/views/admin-shop-person-type/_form.php b/views/admin-shop-person-type/_form.php new file mode 100644 index 0000000..86dfcbe --- /dev/null +++ b/views/admin-shop-person-type/_form.php @@ -0,0 +1,41 @@ + + + + + +fieldSet('Основное'); ?> + + field($model, 'name')->textInput(['maxlength' => 255]) ?> + field($model, 'active')->widget( + \skeeks\widget\chosen\Chosen::className(), + [ + 'items' => \Yii::$app->formatter->booleanFormat + ] + ) ?> +fieldSetEnd(); ?> + +fieldSet('Форма с полями и данными'); ?> + field($model, 'form_id')->widget( + + \skeeks\cms\widgets\formInputs\EditedSelect::className(), [ + 'items' => \yii\helpers\ArrayHelper::map( + \skeeks\modules\cms\form\models\Form::find()->all(), + 'id', 'name' + ), + 'controllerRoute' => 'form/admin-form', + ]); + ?> +fieldSetEnd(); ?> +fieldSetEnd(); */?> + +buttonsCreateOrUpdate($model); ?> + \ No newline at end of file diff --git a/views/admin-shop-person-type/index.php b/views/admin-shop-person-type/index.php new file mode 100644 index 0000000..0cd4a20 --- /dev/null +++ b/views/admin-shop-person-type/index.php @@ -0,0 +1,37 @@ + + * @link http://skeeks.com/ + * @copyright 2010-2014 SkeekS (Sx) + * @date 30.10.2014 + * @since 1.0.0 + */ +use skeeks\cms\modules\admin\widgets\GridView; + +/* @var $this yii\web\View */ +/* @var $searchModel common\models\searchs\Game */ +/* @var $dataProvider yii\data\ActiveDataProvider */ + +$dataProvider->sort->defaultOrder = [ + 'active' => SORT_DESC, +]; + +?> + + $dataProvider, + 'filterModel' => $searchModel, + 'columns' => [ + [ + 'class' => \skeeks\cms\modules\admin\grid\ActionColumn::className(), + 'controller' => $controller + ], + 'name', + [ + 'class' => \skeeks\cms\grid\BooleanColumn::className(), + 'attribute' => 'active' + ], + ], +]); ?> diff --git a/views/cart-form.php b/views/cart-form.php new file mode 100644 index 0000000..19ea3d0 --- /dev/null +++ b/views/cart-form.php @@ -0,0 +1,49 @@ + + * @link http://skeeks.com/ + * @copyright 2010 SkeekS (СкикС) + * @date 17.03.2015 + * + * @var $formField \skeeks\modules\cms\form\models\FormField + * @var $model \skeeks\modules\cms\form\models\FormValidateModel + * @var $shopPersonType \skeeks\modules\cms\shop\models\ShopPersonType + * @var $shopPaySystems \skeeks\modules\cms\shop\models\ShopPaySystem[] + */ +use skeeks\modules\cms\form\widgets\ActiveForm; +?> + $model->modelForm, + 'action' => \skeeks\cms\helpers\UrlHelper::construct('shop/backend/create-order')->toString(), +]); +?> + + +id); ?> + + + + id); ?> + + +
+ + false, + 'name' => 'shopPaySystemId', + 'items' => \yii\helpers\ArrayHelper::map($shopPaySystems, 'id', 'name') + ])?> +
+ + + + + + + renderActiveForm($form, $model)?> + + + + + + \ No newline at end of file diff --git a/views/cart/index.php b/views/cart/index.php new file mode 100644 index 0000000..62d4a40 --- /dev/null +++ b/views/cart/index.php @@ -0,0 +1 @@ +sdfg \ No newline at end of file diff --git a/widgets/cart/CartWidget.php b/widgets/cart/CartWidget.php new file mode 100644 index 0000000..0be5888 --- /dev/null +++ b/widgets/cart/CartWidget.php @@ -0,0 +1,66 @@ + + * @link http://skeeks.com/ + * @copyright 2010 SkeekS (СкикС) + * @date 03.04.2015 + */ +namespace skeeks\modules\cms\shop\widgets\cart; +use skeeks\cms\widgets\base\hasTemplate\WidgetHasTemplate; +use skeeks\modules\cms\shop\assets\ShopAsset; +use yii\helpers\Json; + +/** + * Class Products + * @package skeeks\modules\cms\shop\widgets\cart + */ +class CartWidget extends WidgetHasTemplate +{ + static public $isRegisteredAssets = false; + + public $allowRegisterAsset = true; + + public function rules() + { + return ArrayHelper::merge(parent::rules(), [ + [['allowRegisterAsset'], 'integer'] + ]); + } + + public function attributeLabels() + { + return ArrayHelper::merge(parent::attributeLabels(), [ + 'allowRegisterAsset' => 'Подключить стандартные скрипты' + ]); + } + + + /** + * Подготовка данных для шаблона + * @return $this + */ + public function bind() + { + parent::bind(); + + if (static::$isRegisteredAssets === false && $this->allowRegisterAsset) + { + ShopAsset::register($this->getView()); + $options = \Yii::$app->shop->getShopClientOptions(); + $options = Json::encode($options); + + $this->getView()->registerJs(<< + * @link http://skeeks.com/ + * @copyright 2010 SkeekS (СкикС) + * @date 03.04.2015 + */ +namespace skeeks\modules\cms\shop\widgets\order; + +use skeeks\cms\widgets\base\hasModelsSmart\WidgetHasModelsSmart; +use skeeks\cms\widgets\base\hasTemplate\WidgetHasTemplate; +use skeeks\modules\cms\shop\assets\ShopAsset; +use skeeks\modules\cms\shop\models\ShopOrder; +use yii\helpers\Json; + +/** + * Class OrdersWidget + * @package skeeks\modules\cms\shop\widgets + */ +class OrderWidget extends WidgetHasTemplate +{ + public $modelClassName = '\skeeks\modules\cms\shop\models\ShopOrder'; + public $title = ''; + + /** + * @var ShopOrder + */ + public $model; + + public function rules() + { + return ArrayHelper::merge(parent::rules(), [ + ]); + } + + public function attributeLabels() + { + return ArrayHelper::merge(parent::attributeLabels(), [ + ]); + } +} diff --git a/widgets/orders/OrdersWidget.php b/widgets/orders/OrdersWidget.php new file mode 100644 index 0000000..c940270 --- /dev/null +++ b/widgets/orders/OrdersWidget.php @@ -0,0 +1,56 @@ + + * @link http://skeeks.com/ + * @copyright 2010 SkeekS (СкикС) + * @date 03.04.2015 + */ +namespace skeeks\modules\cms\shop\widgets\orders; + +use skeeks\cms\widgets\base\hasModelsSmart\WidgetHasModelsSmart; +use skeeks\cms\widgets\base\hasTemplate\WidgetHasTemplate; +use skeeks\modules\cms\shop\assets\ShopAsset; +use skeeks\modules\cms\shop\models\ShopOrder; +use yii\helpers\Json; + +/** + * Class OrdersWidget + * @package skeeks\modules\cms\shop\widgets + */ +class OrdersWidget extends WidgetHasModelsSmart +{ + public $modelClassName = '\skeeks\modules\cms\shop\models\ShopOrder'; + public $title = ''; + public $user_id; + + public function rules() + { + return ArrayHelper::merge(parent::rules(), [ + ['user_id', 'integer'] + ]); + } + + public function attributeLabels() + { + return ArrayHelper::merge(parent::attributeLabels(), [ + 'user_id' => 'Пользователь' + ]); + } + + /** + * Подготовка данных для шаблона + * @return $this + */ + public function bind() + { + parent::bind(); + + if ($this->user_id) + { + $query = $this->getSearch()->getDataProvider()->query; + $query->andWhere(['user_id' => $this->user_id]); + } + + return $this; + } +}