+38(073) 413-59-71  info@binliz.org.ua

Стоит ли магазин на битрикс своих денег часть 1

 19.09.2016
php, 1C-Bitrix

Собственно вопрос, по реализации магазина и как я буду его оценивать.

Для начала разберем реальный магазин, как он работает, какие функции там реализованы и его стоимость.

И так итернет-магазин на битрикс можно реализовать на 2х редакциях это малый бизнес и бизнес.

В чем основная разница именно для магазина?

1. Нет модуля рекламы - целесообразность данного модуля можно поставить под сомнение его можно реализовать на инфоблоках и будет это быстро и неплохо работать, да и сам модуль тяжелый в некоторых случаях вообще не целесообразный

2. Сам модуль интернет магазин отличается тем, что в бизнесе нет ограничений по количеству цен для товара, и нет наборов и комплектов, в малом бизнесе только один склад, нет аффилатов (вопрос спорный надо ли в большинстве случаев) и нельзя продавать электронный контент остальное в редакциях магазинов одинаково работает.

Что мы имеем, битрикс полностью интегрирован с 1С, малый бизнес - хорош если нет складов и разных цен к примеру оптовых и за товар. Бизнес - монстрозубый мгазин который готов для любых предприятий.

И цена: 9 000 и 19 000 разница ощутимая.

Старт стоит 1 400 т.е. собсвенно остальные дополнения 7 600 и 17 600 соответсвенно.

В среднем на бирже труда работа программиста на php равняесть 5-10$ в час т.е. 130 грн - 260 грн. 58 и 29 часов соответсвенно т.е. при нормальном рабочем часе в день 4-7 дней. Реально ли?

Давайте разберемся, что надо реализвать в первую очередь.

1. Каталог товаров 

2. Корзина

2.1. Скидки

3. Оформление заказ

3.1. Способы оплаты

3.2. Способы доставки

Ну что же упростим для начала: 

Есть:

Битрикс старт

Надо:

Магазин

Любая правильная разработка в битрикс начинается с отдельного модуля в котором будет все свое хранится и не мешать всему остальному.

Разработка модуля итнернет магазина начинается со стандартного "пустого модуля"

создаем папку local в корне сайта и создаем в нем папку modules/NAMESPACE в моем случаи будет это binliz.sale для того чтобы битрикс определил что это модуль надо создать пару папочек и файликов это все написано в курсе по битрикс но я буду писать именно что я делаю

создаем папку install, файлики install/index.php, include.php, options.php

содержание файлов include и options пока оставляем пустыми а install/index.php пишу следующее:

/**
 * User: binliz
 */

use Bitrix\Main\Localization\Loc;
Loc::loadMessages(__FILE__);
if (class_exists('binliz_sale')) {
    return;
}
class binliz_sale extends CModule
{
    public $MODULE_ID = 'binliz.sale';
    public $MODULE_VERSION = '0.1';
    public $MODULE_VERSION_DATE = '2016-09-19';
    public $MODULE_NAME = 'Модуль binliz sale';
    public $MODULE_DESCRIPTION = 'Модуль магазина, служит для автоподключение классов. Использует движок D7.';
    public $MODULE_GROUP_RIGHTS = 'N';
    public $PARTNER_NAME = "binliz";
    public $PARTNER_URI = "http://binliz.org.ua";


    public function DoInstall()
    {
        global $APPLICATION;
        RegisterModule($this->MODULE_ID);
    }
    public function DoUninstall()
    {
        global $APPLICATION;
        UnRegisterModule($this->MODULE_ID);
    }
}

Вот и все, идем в Рабочий стол > Marketplace > Установленные решения и устанавливаем наш модуль, делать мы это будем часто устанавиливать и уаалять чтобы точно знать что наш модуль развернется из коробки.

Первым делом, что нам нужно организовать это возможность создание каталога в админке, для удобства сделаем его так же как и у битрикса т.е. не выдумывая новой структры - добавим к элементам инфоблока свои вкладки с торговым каталогом.

Как же это организовать? Попробуем для начала создать таблицу в которой будем хранить наши инфоблоки которые станут каталогами.

CREATE TABLE `b_binliz_sale_catalog` (
  `ID` int(11) NOT NULL,
  `IBLOCK_ID` int(11) NOT NULL,
  `OFFER_IBLOCK_ID` int(11) NOT NULL,
  `IS_CATALOG` int(1) NOT NULL,
  `IS_OFFERS` int(1) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

ALTER TABLE `b_binliz_sale_catalog`
  ADD PRIMARY KEY (`ID`),
  ADD UNIQUE KEY `IBLOCK_ID` (`IBLOCK_ID`),
  ADD UNIQUE KEY `OFFER_IBLOCK_ID` (`OFFER_IBLOCK_ID`);

ALTER TABLE `b_binliz_sale_catalog`
  MODIFY `ID` int(11) NOT NULL AUTO_INCREMENT;

Создадим в ОРМ представление данной таблице, создадим папку lib и в нее положим файл salecatalog.php

namespace Binliz\Sale;

use Bitrix\Main,
	Bitrix\Main\Localization\Loc;
Loc::loadMessages(__FILE__);

/**
 * Class SaleCatalogTable
 * 
 * @package Binliz\Sale
 **/

class SaleCatalogTable extends Main\Entity\DataManager
{
	/**
	 * Returns DB table name for entity.
	 *
	 * @return string
	 */
	public static function getTableName()
	{
		return 'b_binliz_sale_catalog';
	}

	/**
	 * Returns entity map definition.
	 *
	 * @return array
	 */
	public static function getMap()
	{
		return array(
			'ID' => array(
				'data_type' => 'integer',
				'primary' => true,
				'autocomplete' => true,
				'title' => Loc::getMessage('SALE_CATALOG_ENTITY_ID_FIELD'),
			),
			'IBLOCK_ID' => array(
				'data_type' => 'integer',
				'required' => true,
				'title' => Loc::getMessage('SALE_CATALOG_ENTITY_IBLOCK_ID_FIELD'),
			),
			'OFFER_IBLOCK_ID' => array(
				'data_type' => 'integer',
				'required' => true,
				'title' => Loc::getMessage('SALE_CATALOG_ENTITY_OFFER_IBLOCK_ID_FIELD'),
			),
			'IS_CATALOG' => array(
				'data_type' => 'integer',
				'required' => true,
				'title' => Loc::getMessage('SALE_CATALOG_ENTITY_IS_CATALOG_FIELD'),
			),
			'IS_OFFERS' => array(
				'data_type' => 'integer',
				'required' => true,
				'title' => Loc::getMessage('SALE_CATALOG_ENTITY_IS_OFFERS_FIELD'),
			),
		);
	}
}

И можно в приниципе и локализацию положить lang/ru/lib/salediscount.php

$MESS["SALE_CATALOG_ENTITY_ID_FIELD"] = "";
$MESS["SALE_CATALOG_ENTITY_IBLOCK_ID_FIELD"] = "";
$MESS["SALE_CATALOG_ENTITY_OFFER_IBLOCK_ID_FIELD"] = "";
$MESS["SALE_CATALOG_ENTITY_IS_CATALOG_FIELD"] = "";
$MESS["SALE_CATALOG_ENTITY_IS_OFFERS_FIELD"] = "";

пока я ничего не переопредил просто положил файлик, табличка создана пора создавать вкладку и задавать ей методы работы с нею, так как у нас битрикс, он имеет систему событий лучший и правильный способ это организовать классы которые будут навешиватся на эти самые события и решать наши задачи, для этого я предпочел руководсвоватся принципом один класс одно решение и конструкторе само определение того на, что навешиваемся. Первым делом будем решать задачу определения каталогов. Для этого нам надо в разделе редактирования инфоблока создать вкладку в которой будет наша галочка, что это каталог и пока этого будет достаточно мы не будем заморачиватся пока торговыми предложениями мы сможем это сделать попозже. Создадим абстрактный класс для событий в котором создадим массив передающий следующие данные:

модуль на который навешиваемся, событие, и метод класса который за это отвечает. Для этого в папке lib создадим папку events и туда будем складывать наши события. И так абстрактный класс.

	namespace Binliz\Sale\Events;

	abstract class Base{
			protected $eventlist = [];
			public final function __construct(){

					$eventManager = \Bitrix\Main\EventManager::getInstance(); 
					foreach($this->eventlist as $event){
							$eventMethods = get_called_class().'::'.$event['method'];
							$eventManager->addEventHandler($event['module'],$event['event'],$eventMethods);
					}

			}
	}

И класс для работы с инфоблоком:

	namespace Binliz\Sale\Events;

	class SaleCatalogIblockEdit extends Base{
			protected $eventlist = [
					['module'=>'main','event'=>'onAdminTabControlBegin','method'=>'onAdminTabControlBegin'],
					['module'=>'iblock','event'=>'onAfterIblockAdd','method'=>'onAdminIblock'],
					['module'=>'iblock','event'=>'onAfterIblockUpdate','method'=>'onAdminIblock'],
					['module'=>'iblock','event'=>'OnIBlockDelete','method'=>'onAdminIblockDelete'],
			];
			static public function getApp(){
				$application = \Bitrix\Main\Application::getInstance();
				$context = $application->getContext();
				$request = $context->getRequest();
				$uri = $request->getRequestedPage();
				return array('application'=>$application,'context'=>$context,'request'=>$request,'uri'=>$uri);
			}
			public function onAdminTabControlBegin(&$form){
				$ells = self::getApp();
	    		if($ells['uri'] == '/bitrix/admin/iblock_edit.php')
    			{
					if($ells['request']->getQuery('ID')>0)
						$results = \Binliz\Sale\SaleCatalogTable::GetByIblock($ells['request']->getQuery('ID'));
						ob_start();
						include(__DIR__.'/templates/iblock_edit.php');
						$str = ob_get_contents();
						ob_end_clean();
			        $form->tabs[] = array("DIV" => "BINLIZ_SALE_CATALOG", "TAB" => "Торговый каталог Binliz.Sale",  "ICON"=>"main_user_edit", "TITLE"=>"Каталог настройки", "CONTENT"=>$str);
			    }

			}
			public function onAdminIblock($arFields){
				$ells = self::getApp();
				file_put_contents(__DIR__.'/fields.txt',var_export(array($arFields,$ells['request']->getPostList(),$ells['request']->getPost('IS_BINLIZ_CATALOG')),1));
				if($arFields['RESULT']!=false){
					$ID = $arFields['ID'];
					$fields = ['IBLOCK_ID'=> $ID,'IS_CATALOG'=>$ells['request']->getPost('IS_BINLIZ_CATALOG')=='Y'?1:0];
					\Binliz\Sale\SaleCatalogTable::AddByIblock($ID,$fields);
				}

			}
			public function onAdminIblockDelete($ID){
					\Binliz\Sale\SaleCatalogTable::DeleteByIblock($ID);
			}
	}

Соответсвенно добавим наши функции к модели таблицы:

	public function GetByIblock($IBLOCK_ID){
			$query = new \Bitrix\Main\Entity\Query(self::getEntity());
			$query->setSelect(array('*'));
			$query->setFilter(array('=IBLOCK_ID' => $IBLOCK_ID));
			$result = $query->exec();
			$ells = $result->fetch();
			if(isset($ells['ID'])) return $ells; 
			else return false;
	}

	public function AddByIblock($IBLOCK_ID,$arFields){
			$query = new \Bitrix\Main\Entity\Query(self::getEntity());
			$query->setSelect(array('IBLOCK_ID','ID'));
			$query->setFilter(array('=IBLOCK_ID' => $IBLOCK_ID));
			$result = $query->exec();
			$ells = $result->fetch();
			if(isset($ells['ID'])) self::Update($ells['ID'],$arFields); else $res = self::Add($arFields); 
	}
	public function DeleteByIblock($IBLOCK_ID){
			$query = new \Bitrix\Main\Entity\Query(self::getEntity());
			$query->setSelect(array('IBLOCK_ID','OFFER_IBLOCK_ID','ID','IS_CATALOG','IS_OFFERS'));
			$query->setFilter(array('=IBLOCK_ID' => $IBLOCK_ID));
			$result = $query->exec();
			$ells = $result->fetch();
			if(isset($ells['ID']) && $ells['OFFER_IBLOCK_ID']==null) {self::Delete($ells['ID']); return true;}
	}

И файл шаблона с галочкой который мы выводим:

	<tr class="heading">
		<td colspan="2">Основные настройки</td>
	</tr>
	<tr>
		<td width="40%" class="adm-detail-content-cell-l"><label for="IS_CATALOG_Y">Является торговым каталогом</label></td>
		<td width="60%" class="adm-detail-content-cell-r">
			<input type="hidden" name="IS_BINLIZ_CATALOG" id="IS_CATALOG_N" value="N">
			<input type="checkbox" name="IS_BINLIZ_CATALOG" id="IS_CATALOG_Y" value="Y" <?if($results['IS_CATALOG'] ==1) echo "checked";?>>
		</td>
	</tr>

Ура, вот и получилась у нас рабочая галочка которая определяет каталог это у нас или нет.