Commit 98782e5a by semenov

Merge branch 'master' into 'release'

Master

See merge request !1
parents 05d7ed2f 1ae98ee2
Процесс разработки.
==============
1.0.0
-----------------
* первая версия магазина
\ No newline at end of file
...@@ -23,7 +23,7 @@ class Module extends CmsModule ...@@ -23,7 +23,7 @@ class Module extends CmsModule
protected function _descriptor() protected function _descriptor()
{ {
return array_merge(parent::_descriptor(), [ return array_merge(parent::_descriptor(), [
"version" => "0.0.1-dev", "version" => "1.0.0",
"name" => "Модуль интернет магазин", "name" => "Модуль интернет магазин",
]); ]);
} }
......
<?php
/**
* @author Semenov Alexander <semenov@skeeks.com>
* @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
<?php
/**
* @author Semenov Alexander <semenov@skeeks.com>
* @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',
];
}
/*!
* @author Semenov Alexander <semenov@skeeks.com>
* @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
/*!
* @author Semenov Alexander <semenov@skeeks.com>
* @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
<?php
/**
* @author Semenov Alexander <semenov@skeeks.com>
* @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
<?php
/**
* @author Semenov Alexander <semenov@skeeks.com>
* @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
<?php
/**
* @author Semenov Alexander <semenov@skeeks.com>
* @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 */
?>
<?php $form = ActiveForm::begin(); ?>
<?= $form->fieldSet('Основное'); ?>
<?= $form->field($model, 'email')->textInput()->hint(''); ?>
<?= $form->field($model, 'allowBuyWhithoutQuantity')->widget(
\skeeks\widget\chosen\Chosen::className(),
[
'items' => \Yii::$app->formatter->booleanFormat,
'allowDeselect' => false
]
); ?>
<?= $form->fieldSetEnd(); ?>
<?= $form->buttonsCreateOrUpdate($model); ?>
<?php ActiveForm::end(); ?>
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
* @date 12.03.2015 * @date 12.03.2015
*/ */
return [ return [
'catalog' => 'shop' =>
[ [
'label' => 'Интернет магазин', 'label' => 'Интернет магазин',
'priority' => 0, 'priority' => 0,
...@@ -16,8 +16,32 @@ return [ ...@@ -16,8 +16,32 @@ return [
'items' => '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" => "Заказы", "label" => "Заказы",
"url" => ["shop/admin-order"], "url" => ["shop/admin-shop-order"],
"img" => ['\skeeks\modules\cms\shop\assets\Asset', 'icons/shop.png'] "img" => ['\skeeks\modules\cms\shop\assets\Asset', 'icons/shop.png']
], ],
......
...@@ -14,6 +14,11 @@ return [ ...@@ -14,6 +14,11 @@ return [
] ]
], ],
'shop' =>
[
'class' => 'skeeks\modules\cms\shop\components\shop\Shop'
],
"registeredWidgets" => [ "registeredWidgets" => [
'components' => [ 'components' => [
/*'skeeks\modules\cms\catalog\widgets\products\Products' => /*'skeeks\modules\cms\catalog\widgets\products\Products' =>
......
<?php
/**
* @author Semenov Alexander <semenov@skeeks.com>
* @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
<?php
/**
* @author Semenov Alexander <semenov@skeeks.com>
* @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
*/